2 * Server main select() loop
4 * Copyright (C) 1998 Alexandre Julliard
15 #include <sys/types.h>
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
)
48 ret
= freelist
- poll_users
;
49 freelist
= (struct object
**)poll_users
[ret
];
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
) )))
64 poll_users
= newusers
;
66 allocated_users
= new_count
;
70 pollfd
[ret
].fd
= obj
->fd
;
71 pollfd
[ret
].events
= 0;
72 pollfd
[ret
].revents
= 0;
73 poll_users
[ret
] = obj
;
79 /* remove an object from the select list and close its fd */
80 void remove_select_user( struct object
*obj
)
82 int user
= obj
->select
;
83 assert( poll_users
[user
] == obj
);
85 pollfd
[user
].events
= 0;
86 pollfd
[user
].revents
= 0;
87 poll_users
[user
] = (struct object
*)freelist
;
88 freelist
= &poll_users
[user
];
95 /* change the fd of an object (the old fd is closed) */
96 void change_select_fd( struct object
*obj
, int fd
)
98 int user
= obj
->select
;
99 assert( poll_users
[user
] == obj
);
100 pollfd
[user
].fd
= fd
;
105 /* set the events that select waits for on this fd */
106 void set_select_events( struct object
*obj
, int events
)
108 int user
= obj
->select
;
109 assert( poll_users
[user
] == obj
);
110 if (events
== -1) /* stop waiting on this fd completely */
112 pollfd
[user
].fd
= -1;
113 pollfd
[user
].events
= 0;
114 pollfd
[user
].revents
= 0;
116 else if (pollfd
[user
].fd
!= -1) pollfd
[user
].events
= events
;
119 /* check if events are pending */
120 int check_select_events( int fd
, int events
)
125 return poll( &pfd
, 1, 0 ) > 0;
128 /* add a timeout user */
129 struct timeout_user
*add_timeout_user( struct timeval
*when
, timeout_callback func
, void *private )
131 struct timeout_user
*user
;
132 struct timeout_user
*pos
;
134 if (!(user
= mem_alloc( sizeof(*user
) ))) return NULL
;
136 user
->callback
= func
;
137 user
->private = private;
139 /* Now insert it in the linked list */
141 for (pos
= timeout_head
; pos
; pos
= pos
->next
)
142 if (!time_before( &pos
->when
, when
)) break;
144 if (pos
) /* insert it before 'pos' */
146 if ((user
->prev
= pos
->prev
)) user
->prev
->next
= user
;
147 else timeout_head
= user
;
151 else /* insert it at the tail */
154 if (timeout_tail
) timeout_tail
->next
= user
;
155 else timeout_head
= user
;
156 user
->prev
= timeout_tail
;
162 /* remove a timeout user */
163 void remove_timeout_user( struct timeout_user
*user
)
165 if (user
->next
) user
->next
->prev
= user
->prev
;
166 else timeout_tail
= user
->prev
;
167 if (user
->prev
) user
->prev
->next
= user
->next
;
168 else timeout_head
= user
->next
;
172 /* add a timeout in milliseconds to an absolute time */
173 void add_timeout( struct timeval
*when
, int timeout
)
177 long sec
= timeout
/ 1000;
178 if ((when
->tv_usec
+= (timeout
- 1000*sec
) * 1000) >= 1000000)
180 when
->tv_usec
-= 1000000;
187 /* handle the next expired timeout */
188 static void handle_timeout(void)
190 struct timeout_user
*user
= timeout_head
;
191 timeout_head
= user
->next
;
192 if (user
->next
) user
->next
->prev
= user
->prev
;
193 else timeout_tail
= user
->prev
;
194 user
->callback( user
->private );
199 static void sighup_handler()
206 /* server main loop */
207 void select_loop(void)
211 struct sigaction action
;
213 /* block the signals we use */
214 sigemptyset( &sigset
);
215 sigaddset( &sigset
, SIGCHLD
);
216 sigaddset( &sigset
, SIGHUP
);
217 sigprocmask( SIG_BLOCK
, &sigset
, NULL
);
219 /* set the handlers */
220 action
.sa_mask
= sigset
;
222 action
.sa_handler
= sigchld_handler
;
223 sigaction( SIGCHLD
, &action
, NULL
);
224 action
.sa_handler
= sighup_handler
;
225 sigaction( SIGHUP
, &action
, NULL
);
233 gettimeofday( &now
, NULL
);
236 if (!time_before( &now
, &timeout_head
->when
)) handle_timeout();
239 diff
= (timeout_head
->when
.tv_sec
- now
.tv_sec
) * 1000
240 + (timeout_head
->when
.tv_usec
- now
.tv_usec
) / 1000;
246 sigprocmask( SIG_UNBLOCK
, &sigset
, NULL
);
248 /* Note: we assume that the signal handlers do not manipulate the pollfd array
249 * or the timeout list, otherwise there is a race here.
251 ret
= poll( pollfd
, nb_users
, diff
);
253 sigprocmask( SIG_BLOCK
, &sigset
, NULL
);
258 for (i
= 0; i
< nb_users
; i
++)
260 if (pollfd
[i
].revents
)
262 poll_users
[i
]->ops
->poll_event( poll_users
[i
], pollfd
[i
].revents
);