2 * Server main select() loop
4 * Copyright (C) 1998 Alexandre Julliard
14 #include <sys/types.h>
22 struct timeout_user
*next
; /* next in sorted timeout list */
23 struct timeout_user
*prev
; /* prev in sorted timeout list */
24 struct timeval when
; /* timeout expiry (absolute time) */
25 timeout_callback callback
; /* callback function */
26 void *private; /* callback private data */
29 static struct select_user
*users
[FD_SETSIZE
]; /* users array */
30 static fd_set read_set
, write_set
, except_set
; /* current select sets */
31 static int nb_users
; /* current number of users */
32 static int max_fd
; /* max fd in use */
33 static struct timeout_user
*timeout_head
; /* sorted timeouts list head */
34 static struct timeout_user
*timeout_tail
; /* sorted timeouts list tail */
38 void register_select_user( struct select_user
*user
)
40 assert( !users
[user
->fd
] );
42 users
[user
->fd
] = user
;
43 if (user
->fd
> max_fd
) max_fd
= user
->fd
;
48 void unregister_select_user( struct select_user
*user
)
50 assert( users
[user
->fd
] == user
);
52 FD_CLR( user
->fd
, &read_set
);
53 FD_CLR( user
->fd
, &write_set
);
54 FD_CLR( user
->fd
, &except_set
);
55 users
[user
->fd
] = NULL
;
56 if (max_fd
== user
->fd
) while (max_fd
&& !users
[max_fd
]) max_fd
--;
60 /* set the events that select waits for on this fd */
61 void set_select_events( struct select_user
*user
, int events
)
63 assert( users
[user
->fd
] == user
);
64 if (events
& READ_EVENT
) FD_SET( user
->fd
, &read_set
);
65 else FD_CLR( user
->fd
, &read_set
);
66 if (events
& WRITE_EVENT
) FD_SET( user
->fd
, &write_set
);
67 else FD_CLR( user
->fd
, &write_set
);
68 if (events
& EXCEPT_EVENT
) FD_SET( user
->fd
, &except_set
);
69 else FD_CLR( user
->fd
, &except_set
);
72 /* check if events are pending */
73 int check_select_events( struct select_user
*user
, int events
)
75 fd_set read_fds
, write_fds
, except_fds
;
76 struct timeval tv
= { 0, 0 };
79 FD_ZERO( &write_fds
);
80 FD_ZERO( &except_fds
);
81 if (events
& READ_EVENT
) FD_SET( user
->fd
, &read_fds
);
82 if (events
& WRITE_EVENT
) FD_SET( user
->fd
, &write_fds
);
83 if (events
& EXCEPT_EVENT
) FD_SET( user
->fd
, &except_fds
);
84 return select( user
->fd
+ 1, &read_fds
, &write_fds
, &except_fds
, &tv
) > 0;
87 /* add a timeout user */
88 struct timeout_user
*add_timeout_user( struct timeval
*when
, timeout_callback func
, void *private )
90 struct timeout_user
*user
;
91 struct timeout_user
*pos
;
93 if (!(user
= mem_alloc( sizeof(*user
) ))) return NULL
;
95 user
->callback
= func
;
96 user
->private = private;
98 /* Now insert it in the linked list */
100 for (pos
= timeout_head
; pos
; pos
= pos
->next
)
102 if (pos
->when
.tv_sec
> user
->when
.tv_sec
) break;
103 if ((pos
->when
.tv_sec
== user
->when
.tv_sec
) &&
104 (pos
->when
.tv_usec
> user
->when
.tv_usec
)) break;
107 if (pos
) /* insert it before 'pos' */
109 if ((user
->prev
= pos
->prev
)) user
->prev
->next
= user
;
110 else timeout_head
= user
;
114 else /* insert it at the tail */
117 if (timeout_tail
) timeout_tail
->next
= user
;
118 else timeout_head
= user
;
119 user
->prev
= timeout_tail
;
125 /* remove a timeout user */
126 void remove_timeout_user( struct timeout_user
*user
)
128 if (user
->next
) user
->next
->prev
= user
->prev
;
129 else timeout_tail
= user
->prev
;
130 if (user
->prev
) user
->prev
->next
= user
->next
;
131 else timeout_head
= user
->next
;
135 /* make an absolute timeout value from a relative timeout in milliseconds */
136 void make_timeout( struct timeval
*when
, int timeout
)
138 gettimeofday( when
, 0 );
139 if (!timeout
) return;
140 if ((when
->tv_usec
+= (timeout
% 1000) * 1000) >= 1000000)
142 when
->tv_usec
-= 1000000;
145 when
->tv_sec
+= timeout
/ 1000;
148 /* handle an expired timeout */
149 static void handle_timeout( struct timeout_user
*user
)
151 if (user
->next
) user
->next
->prev
= user
->prev
;
152 else timeout_tail
= user
->prev
;
153 if (user
->prev
) user
->prev
->next
= user
->next
;
154 else timeout_head
= user
->next
;
155 user
->callback( user
->private );
160 static int do_dump_objects
;
169 /* dummy SIGCHLD handler */
170 static void sigchld()
174 /* server main loop */
175 void select_loop(void)
180 signal( SIGPIPE
, SIG_IGN
);
181 signal( SIGCHLD
, sigchld
);
183 signal( SIGHUP
, sighup
);
188 fd_set read
= read_set
, write
= write_set
, except
= except_set
;
191 struct timeval tv
, now
;
192 gettimeofday( &now
, NULL
);
193 if ((timeout_head
->when
.tv_sec
< now
.tv_sec
) ||
194 ((timeout_head
->when
.tv_sec
== now
.tv_sec
) &&
195 (timeout_head
->when
.tv_usec
< now
.tv_usec
)))
197 handle_timeout( timeout_head
);
200 tv
.tv_sec
= timeout_head
->when
.tv_sec
- now
.tv_sec
;
201 if ((tv
.tv_usec
= timeout_head
->when
.tv_usec
- now
.tv_usec
) < 0)
203 tv
.tv_usec
+= 1000000;
207 printf( "select: " );
208 for (i
= 0; i
<= max_fd
; i
++) printf( "%c", FD_ISSET( i
, &read_set
) ? 'r' :
209 (FD_ISSET( i
, &write_set
) ? 'w' : '-') );
210 printf( " timeout %d.%06d\n", tv
.tv_sec
, tv
.tv_usec
);
212 ret
= select( max_fd
+ 1, &read
, &write
, &except
, &tv
);
214 else /* no timeout */
217 printf( "select: " );
218 for (i
= 0; i
<= max_fd
; i
++) printf( "%c", FD_ISSET( i
, &read_set
) ? 'r' :
219 (FD_ISSET( i
, &write_set
) ? 'w' : '-') );
220 printf( " no timeout\n" );
222 ret
= select( max_fd
+ 1, &read
, &write
, &except
, NULL
);
230 if (do_dump_objects
) dump_objects();
233 wait4_thread( NULL
, 0 );
240 for (i
= 0; i
<= max_fd
; i
++)
243 if (FD_ISSET( i
, &except
)) event
|= EXCEPT_EVENT
;
244 if (FD_ISSET( i
, &write
)) event
|= WRITE_EVENT
;
245 if (FD_ISSET( i
, &read
)) event
|= READ_EVENT
;
247 /* Note: users[i] might be NULL here, because an event routine
248 called in an earlier pass of this loop might have removed
249 the current user ... */
250 if (event
&& users
[i
])
251 users
[i
]->func( event
, users
[i
]->private );