Print thread ids in traces with only 4 digits now that they are small
[wine] / server / select.c
1 /*
2  * Server main select() loop
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #ifdef HAVE_SYS_POLL_H
29 #include <sys/poll.h>
30 #endif
31 #include <sys/time.h>
32 #include <sys/types.h>
33 #include <unistd.h>
34
35 #include "file.h"
36 #include "thread.h"
37 #include "process.h"
38
39 struct timeout_user
40 {
41     struct timeout_user  *next;       /* next in sorted timeout list */
42     struct timeout_user  *prev;       /* prev in sorted timeout list */
43     struct timeval        when;       /* timeout expiry (absolute time) */
44     timeout_callback      callback;   /* callback function */
45     void                 *private;    /* callback private data */
46 };
47
48 static struct object **poll_users;          /* users array */
49 static struct pollfd *pollfd;               /* poll fd array */
50 static int nb_users;                        /* count of array entries actually in use */
51 static int active_users;                    /* current number of active users */
52 static int allocated_users;                 /* count of allocated entries in the array */
53 static struct object **freelist;            /* list of free entries in the array */
54
55 static struct timeout_user *timeout_head;   /* sorted timeouts list head */
56 static struct timeout_user *timeout_tail;   /* sorted timeouts list tail */
57
58
59 /* add a user and return an opaque handle to it, or -1 on failure */
60 int add_select_user( struct object *obj )
61 {
62     int ret;
63     if (freelist)
64     {
65         ret = freelist - poll_users;
66         freelist = (struct object **)poll_users[ret];
67     }
68     else
69     {
70         if (nb_users == allocated_users)
71         {
72             struct object **newusers;
73             struct pollfd *newpoll;
74             int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
75             if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
76             if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) )))
77             {
78                 if (allocated_users)
79                     poll_users = newusers;
80                 else
81                     free( newusers );
82                 obj->select = -1;
83                 return -1;
84             }
85             poll_users = newusers;
86             pollfd = newpoll;
87             allocated_users = new_count;
88         }
89         ret = nb_users++;
90     }
91     pollfd[ret].fd = obj->fd;
92     pollfd[ret].events = 0;
93     pollfd[ret].revents = 0;
94     poll_users[ret] = obj;
95     obj->select = ret;
96     active_users++;
97     return ret;
98 }
99
100 /* remove an object from the select list and close its fd */
101 void remove_select_user( struct object *obj )
102 {
103     int user = obj->select;
104     assert( user >= 0 );
105     assert( poll_users[user] == obj );
106     pollfd[user].fd = -1;
107     pollfd[user].events = 0;
108     pollfd[user].revents = 0;
109     poll_users[user] = (struct object *)freelist;
110     freelist = &poll_users[user];
111     close( obj->fd );
112     obj->fd = -1;
113     obj->select = -1;
114     active_users--;
115 }
116
117 /* change the fd and events of an object */
118 void change_select_fd( struct object *obj, int fd, int events )
119 {
120     int user = obj->select;
121     assert( poll_users[user] == obj );
122     pollfd[user].fd = fd;
123     pollfd[user].events = events;
124     obj->fd = fd;
125 }
126
127 /* set the events that select waits for on this fd */
128 void set_select_events( struct object *obj, int events )
129 {
130     int user = obj->select;
131     assert( poll_users[user] == obj );
132     if (events == -1)  /* stop waiting on this fd completely */
133     {
134         pollfd[user].fd = -1;
135         pollfd[user].events = 0;
136         pollfd[user].revents = 0;
137     }
138     else if (pollfd[user].fd != -1) pollfd[user].events = events;
139 }
140
141 /* add a timeout user */
142 struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private )
143 {
144     struct timeout_user *user;
145     struct timeout_user *pos;
146
147     if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
148     user->when     = *when;
149     user->callback = func;
150     user->private  = private;
151
152     /* Now insert it in the linked list */
153
154     for (pos = timeout_head; pos; pos = pos->next)
155         if (!time_before( &pos->when, when )) break;
156
157     if (pos)  /* insert it before 'pos' */
158     {
159         if ((user->prev = pos->prev)) user->prev->next = user;
160         else timeout_head = user;
161         user->next = pos;
162         pos->prev = user;
163     }
164     else  /* insert it at the tail */
165     {
166         user->next = NULL;
167         if (timeout_tail) timeout_tail->next = user;
168         else timeout_head = user;
169         user->prev = timeout_tail;
170         timeout_tail = user;
171     }
172     return user;
173 }
174
175 /* remove a timeout user */
176 void remove_timeout_user( struct timeout_user *user )
177 {
178     if (user->next) user->next->prev = user->prev;
179     else timeout_tail = user->prev;
180     if (user->prev) user->prev->next = user->next;
181     else timeout_head = user->next;
182     free( user );
183 }
184
185 /* add a timeout in milliseconds to an absolute time */
186 void add_timeout( struct timeval *when, int timeout )
187 {
188     if (timeout)
189     {
190         long sec = timeout / 1000;
191         if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
192         {
193             when->tv_usec -= 1000000;
194             when->tv_sec++;
195         }
196         when->tv_sec += sec;
197     }
198 }
199
200 /* handle the next expired timeout */
201 static void handle_timeout(void)
202 {
203     struct timeout_user *user = timeout_head;
204     timeout_head = user->next;
205     if (user->next) user->next->prev = user->prev;
206     else timeout_tail = user->prev;
207     user->callback( user->private );
208     free( user );
209 }
210
211 /* SIGHUP handler */
212 static void sighup_handler()
213 {
214 #ifdef DEBUG_OBJECTS
215     dump_objects();
216 #endif
217 }
218
219 /* SIGTERM handler */
220 static void sigterm_handler()
221 {
222     flush_registry();
223     exit(1);
224 }
225
226 /* SIGINT handler */
227 static void sigint_handler()
228 {
229     kill_all_processes( NULL, 1 );
230     flush_registry();
231     exit(1);
232 }
233
234 /* server main loop */
235 void select_loop(void)
236 {
237     int ret;
238     sigset_t sigset;
239     struct sigaction action;
240
241     /* block the signals we use */
242     sigemptyset( &sigset );
243     sigaddset( &sigset, SIGCHLD );
244     sigaddset( &sigset, SIGHUP );
245     sigaddset( &sigset, SIGINT );
246     sigaddset( &sigset, SIGQUIT );
247     sigaddset( &sigset, SIGTERM );
248     sigprocmask( SIG_BLOCK, &sigset, NULL );
249
250     /* set the handlers */
251     action.sa_mask = sigset;
252     action.sa_flags = 0;
253     action.sa_handler = sigchld_handler;
254     sigaction( SIGCHLD, &action, NULL );
255     action.sa_handler = sighup_handler;
256     sigaction( SIGHUP, &action, NULL );
257     action.sa_handler = sigint_handler;
258     sigaction( SIGINT, &action, NULL );
259     action.sa_handler = sigterm_handler;
260     sigaction( SIGQUIT, &action, NULL );
261     sigaction( SIGTERM, &action, NULL );
262
263     while (active_users)
264     {
265         long diff = -1;
266         if (timeout_head)
267         {
268             struct timeval now;
269             gettimeofday( &now, NULL );
270             while (timeout_head)
271             {
272                 if (!time_before( &now, &timeout_head->when )) handle_timeout();
273                 else
274                 {
275                     diff = (timeout_head->when.tv_sec - now.tv_sec) * 1000
276                             + (timeout_head->when.tv_usec - now.tv_usec) / 1000;
277                     break;
278                 }
279             }
280             if (!active_users) break;  /* last user removed by a timeout */
281         }
282
283         sigprocmask( SIG_UNBLOCK, &sigset, NULL );
284
285         /* Note: we assume that the signal handlers do not manipulate the pollfd array
286          *       or the timeout list, otherwise there is a race here.
287          */
288         ret = poll( pollfd, nb_users, diff );
289
290         sigprocmask( SIG_BLOCK, &sigset, NULL );
291
292         if (ret > 0)
293         {
294             int i;
295             for (i = 0; i < nb_users; i++)
296             {
297                 if (pollfd[i].revents)
298                 {
299                     fd_poll_event( poll_users[i], pollfd[i].revents );
300                     if (!--ret) break;
301                 }
302             }
303         }
304     }
305 }