Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[wine.git] / server / select.c
blob60a6fd4281073653991c53fef927a1261369a019
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/time.h>
14 #include <sys/types.h>
15 #include <unistd.h>
17 #include "object.h"
19 struct timeout_user
21 struct timeout_user *next; /* next in sorted timeout list */
22 struct timeout_user *prev; /* prev in sorted timeout list */
23 struct timeval when; /* timeout expiry (absolute time) */
24 timeout_callback callback; /* callback function */
25 void *private; /* callback private data */
28 static struct select_user *users[FD_SETSIZE]; /* users array */
29 static fd_set read_set, write_set; /* current select sets */
30 static int nb_users; /* current number of users */
31 static int max_fd; /* max fd in use */
32 static struct timeout_user *timeout_head; /* sorted timeouts list head */
33 static struct timeout_user *timeout_tail; /* sorted timeouts list tail */
36 /* register a user */
37 void register_select_user( struct select_user *user )
39 assert( !users[user->fd] );
41 users[user->fd] = user;
42 if (user->fd > max_fd) max_fd = user->fd;
43 nb_users++;
46 /* remove a user */
47 void unregister_select_user( struct select_user *user )
49 assert( users[user->fd] == user );
51 FD_CLR( user->fd, &read_set );
52 FD_CLR( user->fd, &write_set );
53 users[user->fd] = NULL;
54 if (max_fd == user->fd) while (max_fd && !users[max_fd]) max_fd--;
55 nb_users--;
58 /* set the events that select waits for on this fd */
59 void set_select_events( struct select_user *user, int events )
61 assert( users[user->fd] == user );
62 if (events & READ_EVENT) FD_SET( user->fd, &read_set );
63 else FD_CLR( user->fd, &read_set );
64 if (events & WRITE_EVENT) FD_SET( user->fd, &write_set );
65 else FD_CLR( user->fd, &write_set );
68 /* check if events are pending */
69 int check_select_events( struct select_user *user, int events )
71 fd_set read_fds, write_fds;
72 struct timeval tv = { 0, 0 };
74 FD_ZERO( &read_fds );
75 FD_ZERO( &write_fds );
76 if (events & READ_EVENT) FD_SET( user->fd, &read_fds );
77 if (events & WRITE_EVENT) FD_SET( user->fd, &write_fds );
78 return select( user->fd + 1, &read_fds, &write_fds, NULL, &tv ) > 0;
81 /* add a timeout user */
82 struct timeout_user *add_timeout_user( struct timeval *when, timeout_callback func, void *private )
84 struct timeout_user *user;
85 struct timeout_user *pos;
87 if (!(user = mem_alloc( sizeof(*user) ))) return NULL;
88 user->when = *when;
89 user->callback = func;
90 user->private = private;
92 /* Now insert it in the linked list */
94 for (pos = timeout_head; pos; pos = pos->next)
96 if (pos->when.tv_sec > user->when.tv_sec) break;
97 if ((pos->when.tv_sec == user->when.tv_sec) &&
98 (pos->when.tv_usec > user->when.tv_usec)) break;
101 if (pos) /* insert it before 'pos' */
103 if ((user->prev = pos->prev)) user->prev->next = user;
104 else timeout_head = user;
105 user->next = pos;
106 pos->prev = user;
108 else /* insert it at the tail */
110 user->next = NULL;
111 if (timeout_tail) timeout_tail->next = user;
112 else timeout_head = user;
113 user->prev = timeout_tail;
114 timeout_tail = user;
116 return user;
119 /* remove a timeout user */
120 void remove_timeout_user( struct timeout_user *user )
122 if (user->next) user->next->prev = user->prev;
123 else timeout_tail = user->prev;
124 if (user->prev) user->prev->next = user->next;
125 else timeout_head = user->next;
126 free( user );
129 /* make an absolute timeout value from a relative timeout in milliseconds */
130 void make_timeout( struct timeval *when, int timeout )
132 gettimeofday( when, 0 );
133 if (!timeout) return;
134 if ((when->tv_usec += (timeout % 1000) * 1000) >= 1000000)
136 when->tv_usec -= 1000000;
137 when->tv_sec++;
139 when->tv_sec += timeout / 1000;
142 /* handle an expired timeout */
143 static void handle_timeout( struct timeout_user *user )
145 if (user->next) user->next->prev = user->prev;
146 else timeout_tail = user->prev;
147 if (user->prev) user->prev->next = user->next;
148 else timeout_head = user->next;
149 user->callback( user->private );
150 free( user );
153 /* server main loop */
154 void select_loop(void)
156 int i, ret;
158 setsid();
159 signal( SIGPIPE, SIG_IGN );
161 while (nb_users)
163 fd_set read = read_set, write = write_set;
164 if (timeout_head)
166 struct timeval tv, now;
167 gettimeofday( &now, NULL );
168 if ((timeout_head->when.tv_sec < now.tv_sec) ||
169 ((timeout_head->when.tv_sec == now.tv_sec) &&
170 (timeout_head->when.tv_usec < now.tv_usec)))
172 handle_timeout( timeout_head );
173 continue;
175 tv.tv_sec = timeout_head->when.tv_sec - now.tv_sec;
176 if ((tv.tv_usec = timeout_head->when.tv_usec - now.tv_usec) < 0)
178 tv.tv_usec += 1000000;
179 tv.tv_sec--;
181 #if 0
182 printf( "select: " );
183 for (i = 0; i <= max_fd; i++) printf( "%c", FD_ISSET( i, &read_set ) ? 'r' :
184 (FD_ISSET( i, &write_set ) ? 'w' : '-') );
185 printf( " timeout %d.%06d\n", tv.tv_sec, tv.tv_usec );
186 #endif
187 ret = select( max_fd + 1, &read, &write, NULL, &tv );
189 else /* no timeout */
191 #if 0
192 printf( "select: " );
193 for (i = 0; i <= max_fd; i++) printf( "%c", FD_ISSET( i, &read_set ) ? 'r' :
194 (FD_ISSET( i, &write_set ) ? 'w' : '-') );
195 printf( " no timeout\n" );
196 #endif
197 ret = select( max_fd + 1, &read, &write, NULL, NULL );
200 if (!ret) continue;
201 if (ret == -1) {
202 if (errno == EINTR) continue;
203 perror("select");
206 for (i = 0; i <= max_fd; i++)
208 int event = 0;
209 if (FD_ISSET( i, &write )) event |= WRITE_EVENT;
210 if (FD_ISSET( i, &read )) event |= READ_EVENT;
212 /* Note: users[i] might be NULL here, because an event routine
213 called in an earlier pass of this loop might have removed
214 the current user ... */
215 if (event && users[i])
216 users[i]->func( event, users[i]->private );