Save the registry before exiting on a SIGTERM.
[wine/wine-kai.git] / server / select.c
blobbbd8d2e92c6342d97b7efe7259c413a569789a80
1 /*
2 * Server main select() loop
4 * Copyright (C) 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <errno.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/poll.h>
14 #include <sys/time.h>
15 #include <sys/types.h>
16 #include <unistd.h>
18 #include "object.h"
19 #include "thread.h"
22 struct timeout_user
24 struct timeout_user *next; /* next in sorted timeout list */
25 struct timeout_user *prev; /* prev in sorted timeout list */
26 struct timeval when; /* timeout expiry (absolute time) */
27 timeout_callback callback; /* callback function */
28 void *private; /* callback private data */
31 static struct object **poll_users; /* users array */
32 static struct pollfd *pollfd; /* poll fd array */
33 static int nb_users; /* count of array entries actually in use */
34 static int active_users; /* current number of active users */
35 static int allocated_users; /* count of allocated entries in the array */
36 static struct object **freelist; /* list of free entries in the array */
38 static struct timeout_user *timeout_head; /* sorted timeouts list head */
39 static struct timeout_user *timeout_tail; /* sorted timeouts list tail */
42 /* add a user and return an opaque handle to it, or -1 on failure */
43 int add_select_user( struct object *obj )
45 int ret;
46 if (freelist)
48 ret = freelist - poll_users;
49 freelist = (struct object **)poll_users[ret];
51 else
53 if (nb_users == allocated_users)
55 struct object **newusers;
56 struct pollfd *newpoll;
57 int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
58 if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
59 if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) )))
61 if (allocated_users)
62 poll_users = newusers;
63 else
64 free( newusers );
65 obj->select = -1;
66 return -1;
68 poll_users = newusers;
69 pollfd = newpoll;
70 allocated_users = new_count;
72 ret = nb_users++;
74 pollfd[ret].fd = obj->fd;
75 pollfd[ret].events = 0;
76 pollfd[ret].revents = 0;
77 poll_users[ret] = obj;
78 obj->select = ret;
79 active_users++;
80 return ret;
83 /* remove an object from the select list and close its fd */
84 void remove_select_user( struct object *obj )
86 int user = obj->select;
87 assert( user >= 0 );
88 assert( poll_users[user] == obj );
89 pollfd[user].fd = -1;
90 pollfd[user].events = 0;
91 pollfd[user].revents = 0;
92 poll_users[user] = (struct object *)freelist;
93 freelist = &poll_users[user];
94 close( obj->fd );
95 obj->fd = -1;
96 obj->select = -1;
97 active_users--;
100 /* change the fd and events of an object */
101 void change_select_fd( struct object *obj, int fd, int events )
103 int user = obj->select;
104 assert( poll_users[user] == obj );
105 pollfd[user].fd = fd;
106 pollfd[user].events = events;
107 obj->fd = fd;
110 /* set the events that select waits for on this fd */
111 void set_select_events( struct object *obj, int events )
113 int user = obj->select;
114 assert( poll_users[user] == obj );
115 if (events == -1) /* stop waiting on this fd completely */
117 pollfd[user].fd = -1;
118 pollfd[user].events = 0;
119 pollfd[user].revents = 0;
121 else if (pollfd[user].fd != -1) pollfd[user].events = events;
124 /* check if events are pending */
125 int check_select_events( int fd, int events )
127 struct pollfd pfd;
128 pfd.fd = fd;
129 pfd.events = events;
130 return poll( &pfd, 1, 0 ) > 0;
133 /* add a timeout user */
134 struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private )
136 struct timeout_user *user;
137 struct timeout_user *pos;
139 if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
140 user->when = *when;
141 user->callback = func;
142 user->private = private;
144 /* Now insert it in the linked list */
146 for (pos = timeout_head; pos; pos = pos->next)
147 if (!time_before( &pos->when, when )) break;
149 if (pos) /* insert it before 'pos' */
151 if ((user->prev = pos->prev)) user->prev->next = user;
152 else timeout_head = user;
153 user->next = pos;
154 pos->prev = user;
156 else /* insert it at the tail */
158 user->next = NULL;
159 if (timeout_tail) timeout_tail->next = user;
160 else timeout_head = user;
161 user->prev = timeout_tail;
162 timeout_tail = user;
164 return user;
167 /* remove a timeout user */
168 void remove_timeout_user( struct timeout_user *user )
170 if (user->next) user->next->prev = user->prev;
171 else timeout_tail = user->prev;
172 if (user->prev) user->prev->next = user->next;
173 else timeout_head = user->next;
174 free( user );
177 /* add a timeout in milliseconds to an absolute time */
178 void add_timeout( struct timeval *when, int timeout )
180 if (timeout)
182 long sec = timeout / 1000;
183 if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
185 when->tv_usec -= 1000000;
186 when->tv_sec++;
188 when->tv_sec += sec;
192 /* handle the next expired timeout */
193 static void handle_timeout(void)
195 struct timeout_user *user = timeout_head;
196 timeout_head = user->next;
197 if (user->next) user->next->prev = user->prev;
198 else timeout_tail = user->prev;
199 user->callback( user->private );
200 free( user );
203 /* SIGHUP handler */
204 static void sighup_handler()
206 #ifdef DEBUG_OBJECTS
207 dump_objects();
208 #endif
211 /* SIGTERM handler */
212 static void sigterm_handler()
214 close_registry();
215 exit(1);
218 /* server main loop */
219 void select_loop(void)
221 int ret;
222 sigset_t sigset;
223 struct sigaction action;
225 /* block the signals we use */
226 sigemptyset( &sigset );
227 sigaddset( &sigset, SIGCHLD );
228 sigaddset( &sigset, SIGHUP );
229 sigaddset( &sigset, SIGINT );
230 sigaddset( &sigset, SIGQUIT );
231 sigaddset( &sigset, SIGTERM );
232 sigprocmask( SIG_BLOCK, &sigset, NULL );
234 /* set the handlers */
235 action.sa_mask = sigset;
236 action.sa_flags = 0;
237 action.sa_handler = sigchld_handler;
238 sigaction( SIGCHLD, &action, NULL );
239 action.sa_handler = sighup_handler;
240 sigaction( SIGHUP, &action, NULL );
241 action.sa_handler = sigterm_handler;
242 sigaction( SIGINT, &action, NULL );
243 sigaction( SIGQUIT, &action, NULL );
244 sigaction( SIGTERM, &action, NULL );
246 while (active_users)
248 long diff = -1;
249 if (timeout_head)
251 struct timeval now;
252 gettimeofday( &now, NULL );
253 while (timeout_head)
255 if (!time_before( &now, &timeout_head->when )) handle_timeout();
256 else
258 diff = (timeout_head->when.tv_sec - now.tv_sec) * 1000
259 + (timeout_head->when.tv_usec - now.tv_usec) / 1000;
260 break;
265 sigprocmask( SIG_UNBLOCK, &sigset, NULL );
267 /* Note: we assume that the signal handlers do not manipulate the pollfd array
268 * or the timeout list, otherwise there is a race here.
270 ret = poll( pollfd, nb_users, diff );
272 sigprocmask( SIG_BLOCK, &sigset, NULL );
274 if (ret > 0)
276 int i;
277 for (i = 0; i < nb_users; i++)
279 if (pollfd[i].revents)
281 poll_users[i]->ops->poll_event( poll_users[i], pollfd[i].revents );
282 if (!--ret) break;