Save the registry before exiting on a SIGTERM.
[wine] / server / select.c
1 /*
2  * Server main select() loop
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  */
6
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>
17
18 #include "object.h"
19 #include "thread.h"
20
21
22 struct timeout_user
23 {
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 */
29 };
30
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 */
37
38 static struct timeout_user *timeout_head;   /* sorted timeouts list head */
39 static struct timeout_user *timeout_tail;   /* sorted timeouts list tail */
40
41
42 /* add a user and return an opaque handle to it, or -1 on failure */
43 int add_select_user( struct object *obj )
44 {
45     int ret;
46     if (freelist)
47     {
48         ret = freelist - poll_users;
49         freelist = (struct object **)poll_users[ret];
50     }
51     else
52     {
53         if (nb_users == allocated_users)
54         {
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) )))
60             {
61                 if (allocated_users)
62                     poll_users = newusers;
63                 else
64                     free( newusers );
65                 obj->select = -1;
66                 return -1;
67             }
68             poll_users = newusers;
69             pollfd = newpoll;
70             allocated_users = new_count;
71         }
72         ret = nb_users++;
73     }
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;
81 }
82
83 /* remove an object from the select list and close its fd */
84 void remove_select_user( struct object *obj )
85 {
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--;
98 }
99
100 /* change the fd and events of an object */
101 void change_select_fd( struct object *obj, int fd, int events )
102 {
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;
108 }
109
110 /* set the events that select waits for on this fd */
111 void set_select_events( struct object *obj, int events )
112 {
113     int user = obj->select;
114     assert( poll_users[user] == obj );
115     if (events == -1)  /* stop waiting on this fd completely */
116     {
117         pollfd[user].fd = -1;
118         pollfd[user].events = 0;
119         pollfd[user].revents = 0;
120     }
121     else if (pollfd[user].fd != -1) pollfd[user].events = events;
122 }
123
124 /* check if events are pending */
125 int check_select_events( int fd, int events )
126 {
127     struct pollfd pfd;
128     pfd.fd     = fd;
129     pfd.events = events;
130     return poll( &pfd, 1, 0 ) > 0;
131 }
132
133 /* add a timeout user */
134 struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private )
135 {
136     struct timeout_user *user;
137     struct timeout_user *pos;
138
139     if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
140     user->when     = *when;
141     user->callback = func;
142     user->private  = private;
143
144     /* Now insert it in the linked list */
145
146     for (pos = timeout_head; pos; pos = pos->next)
147         if (!time_before( &pos->when, when )) break;
148
149     if (pos)  /* insert it before 'pos' */
150     {
151         if ((user->prev = pos->prev)) user->prev->next = user;
152         else timeout_head = user;
153         user->next = pos;
154         pos->prev = user;
155     }
156     else  /* insert it at the tail */
157     {
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;
163     }
164     return user;
165 }
166
167 /* remove a timeout user */
168 void remove_timeout_user( struct timeout_user *user )
169 {
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 );
175 }
176
177 /* add a timeout in milliseconds to an absolute time */
178 void add_timeout( struct timeval *when, int timeout )
179 {
180     if (timeout)
181     {
182         long sec = timeout / 1000;
183         if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
184         {
185             when->tv_usec -= 1000000;
186             when->tv_sec++;
187         }
188         when->tv_sec += sec;
189     }
190 }
191
192 /* handle the next expired timeout */
193 static void handle_timeout(void)
194 {
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 );
201 }
202
203 /* SIGHUP handler */
204 static void sighup_handler()
205 {
206 #ifdef DEBUG_OBJECTS
207     dump_objects();
208 #endif
209 }
210
211 /* SIGTERM handler */
212 static void sigterm_handler()
213 {
214     close_registry();
215     exit(1);
216 }
217
218 /* server main loop */
219 void select_loop(void)
220 {
221     int ret;
222     sigset_t sigset;
223     struct sigaction action;
224
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 );
233
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 );
245
246     while (active_users)
247     {
248         long diff = -1;
249         if (timeout_head)
250         {
251             struct timeval now;
252             gettimeofday( &now, NULL );
253             while (timeout_head)
254             {
255                 if (!time_before( &now, &timeout_head->when )) handle_timeout();
256                 else
257                 {
258                     diff = (timeout_head->when.tv_sec - now.tv_sec) * 1000
259                             + (timeout_head->when.tv_usec - now.tv_usec) / 1000;
260                     break;
261                 }
262             }
263         }
264
265         sigprocmask( SIG_UNBLOCK, &sigset, NULL );
266
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.
269          */
270         ret = poll( pollfd, nb_users, diff );
271
272         sigprocmask( SIG_BLOCK, &sigset, NULL );
273
274         if (ret > 0)
275         {
276             int i;
277             for (i = 0; i < nb_users; i++)
278             {
279                 if (pollfd[i].revents)
280                 {
281                     poll_users[i]->ops->poll_event( poll_users[i], pollfd[i].revents );
282                     if (!--ret) break;
283                 }
284             }
285         }
286     }
287 }