blob: 6a8db7a1c13005fea1ef89a7f51332df157b2104 [file] [log] [blame]
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +00001/*
2 * Server main select() loop
3 *
4 * Copyright (C) 1998 Alexandre Julliard
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00005 *
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
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +000019 */
20
21#include <assert.h>
22#include <errno.h>
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +000023#include <signal.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000027#include <sys/poll.h>
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +000028#include <sys/time.h>
29#include <sys/types.h>
30#include <unistd.h>
31
Alexandre Julliard43c190e1999-05-15 10:48:19 +000032#include "object.h"
Alexandre Julliard0a707831999-11-08 05:31:47 +000033#include "thread.h"
Alexandre Julliard40043ed2002-08-16 20:02:15 +000034#include "process.h"
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000035
Alexandre Julliard88de35c1999-05-16 16:57:49 +000036struct timeout_user
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +000037{
Alexandre Julliard88de35c1999-05-16 16:57:49 +000038 struct timeout_user *next; /* next in sorted timeout list */
39 struct timeout_user *prev; /* prev in sorted timeout list */
40 struct timeval when; /* timeout expiry (absolute time) */
41 timeout_callback callback; /* callback function */
42 void *private; /* callback private data */
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +000043};
44
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000045static struct object **poll_users; /* users array */
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000046static struct pollfd *pollfd; /* poll fd array */
47static int nb_users; /* count of array entries actually in use */
48static int active_users; /* current number of active users */
49static int allocated_users; /* count of allocated entries in the array */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000050static struct object **freelist; /* list of free entries in the array */
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000051
Alexandre Julliard88de35c1999-05-16 16:57:49 +000052static struct timeout_user *timeout_head; /* sorted timeouts list head */
53static struct timeout_user *timeout_tail; /* sorted timeouts list tail */
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +000054
55
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000056/* add a user and return an opaque handle to it, or -1 on failure */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000057int add_select_user( struct object *obj )
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +000058{
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000059 int ret;
60 if (freelist)
61 {
62 ret = freelist - poll_users;
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000063 freelist = (struct object **)poll_users[ret];
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000064 }
65 else
66 {
67 if (nb_users == allocated_users)
68 {
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000069 struct object **newusers;
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000070 struct pollfd *newpoll;
71 int new_count = allocated_users ? (allocated_users + allocated_users / 2) : 16;
72 if (!(newusers = realloc( poll_users, new_count * sizeof(*poll_users) ))) return -1;
73 if (!(newpoll = realloc( pollfd, new_count * sizeof(*pollfd) )))
74 {
Bill Medland9e5af612001-11-06 22:25:11 +000075 if (allocated_users)
76 poll_users = newusers;
77 else
78 free( newusers );
79 obj->select = -1;
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000080 return -1;
81 }
82 poll_users = newusers;
83 pollfd = newpoll;
84 allocated_users = new_count;
85 }
86 ret = nb_users++;
87 }
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000088 pollfd[ret].fd = obj->fd;
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000089 pollfd[ret].events = 0;
90 pollfd[ret].revents = 0;
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000091 poll_users[ret] = obj;
92 obj->select = ret;
Alexandre Julliard247b8ae1999-12-13 00:16:44 +000093 active_users++;
94 return ret;
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +000095}
96
Alexandre Julliard1dca5e22000-01-01 00:56:27 +000097/* remove an object from the select list and close its fd */
98void remove_select_user( struct object *obj )
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +000099{
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000100 int user = obj->select;
Bill Medland9e5af612001-11-06 22:25:11 +0000101 assert( user >= 0 );
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000102 assert( poll_users[user] == obj );
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000103 pollfd[user].fd = -1;
104 pollfd[user].events = 0;
105 pollfd[user].revents = 0;
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000106 poll_users[user] = (struct object *)freelist;
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000107 freelist = &poll_users[user];
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000108 close( obj->fd );
109 obj->fd = -1;
110 obj->select = -1;
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000111 active_users--;
112}
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000113
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000114/* change the fd and events of an object */
115void change_select_fd( struct object *obj, int fd, int events )
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000116{
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000117 int user = obj->select;
118 assert( poll_users[user] == obj );
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000119 pollfd[user].fd = fd;
Alexandre Julliard9caa71e2001-11-30 18:46:42 +0000120 pollfd[user].events = events;
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000121 obj->fd = fd;
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000122}
123
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000124/* set the events that select waits for on this fd */
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000125void set_select_events( struct object *obj, int events )
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000126{
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000127 int user = obj->select;
128 assert( poll_users[user] == obj );
129 if (events == -1) /* stop waiting on this fd completely */
130 {
131 pollfd[user].fd = -1;
132 pollfd[user].events = 0;
133 pollfd[user].revents = 0;
134 }
135 else if (pollfd[user].fd != -1) pollfd[user].events = events;
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000136}
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000137
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000138/* check if events are pending */
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000139int check_select_events( int fd, int events )
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000140{
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000141 struct pollfd pfd;
142 pfd.fd = fd;
143 pfd.events = events;
144 return poll( &pfd, 1, 0 ) > 0;
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000145}
146
147/* add a timeout user */
148struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private )
149{
150 struct timeout_user *user;
151 struct timeout_user *pos;
152
153 if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
154 user->when = *when;
155 user->callback = func;
156 user->private = private;
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000157
158 /* Now insert it in the linked list */
159
160 for (pos = timeout_head; pos; pos = pos->next)
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000161 if (!time_before( &pos->when, when )) break;
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000162
163 if (pos) /* insert it before 'pos' */
164 {
165 if ((user->prev = pos->prev)) user->prev->next = user;
166 else timeout_head = user;
167 user->next = pos;
168 pos->prev = user;
169 }
170 else /* insert it at the tail */
171 {
172 user->next = NULL;
173 if (timeout_tail) timeout_tail->next = user;
174 else timeout_head = user;
175 user->prev = timeout_tail;
176 timeout_tail = user;
177 }
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000178 return user;
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000179}
180
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000181/* remove a timeout user */
182void remove_timeout_user( struct timeout_user *user )
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000183{
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000184 if (user->next) user->next->prev = user->prev;
185 else timeout_tail = user->prev;
186 if (user->prev) user->prev->next = user->next;
187 else timeout_head = user->next;
188 free( user );
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000189}
190
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000191/* add a timeout in milliseconds to an absolute time */
192void add_timeout( struct timeval *when, int timeout )
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000193{
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000194 if (timeout)
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000195 {
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000196 long sec = timeout / 1000;
197 if ((when->tv_usec += (timeout - 1000*sec) * 1000) >= 1000000)
198 {
199 when->tv_usec -= 1000000;
200 when->tv_sec++;
201 }
202 when->tv_sec += sec;
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000203 }
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000204}
205
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000206/* handle the next expired timeout */
207static void handle_timeout(void)
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000208{
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000209 struct timeout_user *user = timeout_head;
210 timeout_head = user->next;
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000211 if (user->next) user->next->prev = user->prev;
212 else timeout_tail = user->prev;
Alexandre Julliard88de35c1999-05-16 16:57:49 +0000213 user->callback( user->private );
214 free( user );
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000215}
216
Alexandre Julliardfb65f7d1999-06-22 17:27:58 +0000217/* SIGHUP handler */
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000218static void sighup_handler()
Alexandre Julliardfb65f7d1999-06-22 17:27:58 +0000219{
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000220#ifdef DEBUG_OBJECTS
221 dump_objects();
Alexandre Julliardfb65f7d1999-06-22 17:27:58 +0000222#endif
Alexandre Julliard0a707831999-11-08 05:31:47 +0000223}
224
Alexandre Julliard839dfda2001-12-26 23:11:49 +0000225/* SIGTERM handler */
226static void sigterm_handler()
227{
Alexandre Julliard88e42612002-06-20 23:18:56 +0000228 flush_registry();
Alexandre Julliard839dfda2001-12-26 23:11:49 +0000229 exit(1);
230}
231
Alexandre Julliard40043ed2002-08-16 20:02:15 +0000232/* SIGINT handler */
233static void sigint_handler()
234{
235 kill_all_processes( NULL, 1 );
236 flush_registry();
237 exit(1);
238}
239
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000240/* server main loop */
241void select_loop(void)
242{
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000243 int ret;
244 sigset_t sigset;
245 struct sigaction action;
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000246
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000247 /* block the signals we use */
248 sigemptyset( &sigset );
249 sigaddset( &sigset, SIGCHLD );
250 sigaddset( &sigset, SIGHUP );
Alexandre Julliard839dfda2001-12-26 23:11:49 +0000251 sigaddset( &sigset, SIGINT );
252 sigaddset( &sigset, SIGQUIT );
253 sigaddset( &sigset, SIGTERM );
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000254 sigprocmask( SIG_BLOCK, &sigset, NULL );
255
256 /* set the handlers */
257 action.sa_mask = sigset;
258 action.sa_flags = 0;
259 action.sa_handler = sigchld_handler;
260 sigaction( SIGCHLD, &action, NULL );
261 action.sa_handler = sighup_handler;
262 sigaction( SIGHUP, &action, NULL );
Alexandre Julliard40043ed2002-08-16 20:02:15 +0000263 action.sa_handler = sigint_handler;
Alexandre Julliard839dfda2001-12-26 23:11:49 +0000264 sigaction( SIGINT, &action, NULL );
Alexandre Julliard40043ed2002-08-16 20:02:15 +0000265 action.sa_handler = sigterm_handler;
Alexandre Julliard839dfda2001-12-26 23:11:49 +0000266 sigaction( SIGQUIT, &action, NULL );
267 sigaction( SIGTERM, &action, NULL );
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000268
269 while (active_users)
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000270 {
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000271 long diff = -1;
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000272 if (timeout_head)
273 {
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000274 struct timeval now;
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000275 gettimeofday( &now, NULL );
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000276 while (timeout_head)
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000277 {
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000278 if (!time_before( &now, &timeout_head->when )) handle_timeout();
279 else
280 {
281 diff = (timeout_head->when.tv_sec - now.tv_sec) * 1000
282 + (timeout_head->when.tv_usec - now.tv_usec) / 1000;
283 break;
284 }
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000285 }
Alexandre Julliardf5e0f0c2002-04-03 22:51:18 +0000286 if (!active_users) break; /* last user removed by a timeout */
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000287 }
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000288
289 sigprocmask( SIG_UNBLOCK, &sigset, NULL );
290
291 /* Note: we assume that the signal handlers do not manipulate the pollfd array
292 * or the timeout list, otherwise there is a race here.
293 */
294 ret = poll( pollfd, nb_users, diff );
295
296 sigprocmask( SIG_BLOCK, &sigset, NULL );
297
298 if (ret > 0)
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000299 {
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000300 int i;
301 for (i = 0; i < nb_users; i++)
Alexandre Julliardfb65f7d1999-06-22 17:27:58 +0000302 {
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000303 if (pollfd[i].revents)
304 {
Alexandre Julliard1dca5e22000-01-01 00:56:27 +0000305 poll_users[i]->ops->poll_event( poll_users[i], pollfd[i].revents );
Alexandre Julliard247b8ae1999-12-13 00:16:44 +0000306 if (!--ret) break;
307 }
Alexandre Julliardfb65f7d1999-06-22 17:27:58 +0000308 }
Alexandre Julliardc6e45ed1998-12-27 08:35:39 +0000309 }
310 }
311}