blob: d4f93728ce11a6a8a70ef1acdd70d0d172074340 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21/*
22 * sock_select.c
23 *
24 * This is the implementation of IOQueue using pj_sock_select().
25 * It runs anywhere where pj_sock_select() is available (currently
26 * Win32, Linux, Linux kernel, etc.).
27 */
28
29#include <pj/ioqueue.h>
30#include <pj/os.h>
31#include <pj/lock.h>
32#include <pj/log.h>
33#include <pj/list.h>
34#include <pj/pool.h>
35#include <pj/string.h>
36#include <pj/assert.h>
37#include <pj/sock.h>
38#include <pj/compat/socket.h>
39#include <pj/sock_select.h>
40#include <pj/errno.h>
41
Benny Prijono40fe9082008-02-08 15:21:41 +000042/* Now that we have access to OS'es <sys/select>, lets check again that
43 * PJ_IOQUEUE_MAX_HANDLES is not greater than FD_SETSIZE
44 */
45#if PJ_IOQUEUE_MAX_HANDLES > FD_SETSIZE
46# error "PJ_IOQUEUE_MAX_HANDLES cannot be greater than FD_SETSIZE"
47#endif
48
49
Benny Prijono9033e312005-11-21 02:08:39 +000050/*
51 * Include declaration from common abstraction.
52 */
53#include "ioqueue_common_abs.h"
54
55/*
56 * ISSUES with ioqueue_select()
57 *
58 * EAGAIN/EWOULDBLOCK error in recv():
59 * - when multiple threads are working with the ioqueue, application
60 * may receive EAGAIN or EWOULDBLOCK in the receive callback.
61 * This error happens because more than one thread is watching for
62 * the same descriptor set, so when all of them call recv() or recvfrom()
63 * simultaneously, only one will succeed and the rest will get the error.
64 *
65 */
66#define THIS_FILE "ioq_select"
67
68/*
69 * The select ioqueue relies on socket functions (pj_sock_xxx()) to return
70 * the correct error code.
71 */
72#if PJ_RETURN_OS_ERROR(100) != PJ_STATUS_FROM_OS(100)
73# error "Error reporting must be enabled for this function to work!"
74#endif
75
Benny Prijono9033e312005-11-21 02:08:39 +000076/*
77 * During debugging build, VALIDATE_FD_SET is set.
78 * This will check the validity of the fd_sets.
79 */
80/*
81#if defined(PJ_DEBUG) && PJ_DEBUG != 0
82# define VALIDATE_FD_SET 1
83#else
84# define VALIDATE_FD_SET 0
85#endif
86*/
87#define VALIDATE_FD_SET 0
88
Benny Prijono42c5b9e2006-05-10 19:24:40 +000089#if 0
90# define TRACE__(args) PJ_LOG(3,args)
91#else
92# define TRACE__(args)
93#endif
94
Benny Prijono9033e312005-11-21 02:08:39 +000095/*
96 * This describes each key.
97 */
98struct pj_ioqueue_key_t
99{
100 DECLARE_COMMON_KEY
101};
102
103/*
104 * This describes the I/O queue itself.
105 */
106struct pj_ioqueue_t
107{
108 DECLARE_COMMON_IOQUEUE
109
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000110 unsigned max, count; /* Max and current key count */
111 int nfds; /* The largest fd value (for select)*/
112 pj_ioqueue_key_t active_list; /* List of active keys. */
Benny Prijono9033e312005-11-21 02:08:39 +0000113 pj_fd_set_t rfdset;
114 pj_fd_set_t wfdset;
115#if PJ_HAS_TCP
116 pj_fd_set_t xfdset;
117#endif
Benny Prijono5accbd02006-03-30 16:32:18 +0000118
119#if PJ_IOQUEUE_HAS_SAFE_UNREG
120 pj_mutex_t *ref_cnt_mutex;
121 pj_ioqueue_key_t closing_list;
122 pj_ioqueue_key_t free_list;
123#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000124};
125
126/* Include implementation for common abstraction after we declare
127 * pj_ioqueue_key_t and pj_ioqueue_t.
128 */
129#include "ioqueue_common_abs.c"
130
Benny Prijonocde71422007-09-19 12:03:28 +0000131#if PJ_IOQUEUE_HAS_SAFE_UNREG
132/* Scan closing keys to be put to free list again */
133static void scan_closing_keys(pj_ioqueue_t *ioqueue);
134#endif
135
Benny Prijono9033e312005-11-21 02:08:39 +0000136/*
137 * pj_ioqueue_name()
138 */
139PJ_DEF(const char*) pj_ioqueue_name(void)
140{
141 return "select";
142}
143
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000144/*
145 * Scan the socket descriptor sets for the largest descriptor.
146 * This value is needed by select().
147 */
148#if defined(PJ_SELECT_NEEDS_NFDS) && PJ_SELECT_NEEDS_NFDS!=0
149static void rescan_fdset(pj_ioqueue_t *ioqueue)
150{
151 pj_ioqueue_key_t *key = ioqueue->active_list.next;
152 int max = 0;
153
154 while (key != &ioqueue->active_list) {
155 if (key->fd > max)
156 max = key->fd;
157 key = key->next;
158 }
159
160 ioqueue->nfds = max;
161}
162#else
163static void rescan_fdset(pj_ioqueue_t *ioqueue)
164{
165 ioqueue->nfds = FD_SETSIZE-1;
166}
167#endif
168
169
Benny Prijono9033e312005-11-21 02:08:39 +0000170/*
171 * pj_ioqueue_create()
172 *
173 * Create select ioqueue.
174 */
175PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
176 pj_size_t max_fd,
177 pj_ioqueue_t **p_ioqueue)
178{
179 pj_ioqueue_t *ioqueue;
180 pj_lock_t *lock;
Benny Prijono5accbd02006-03-30 16:32:18 +0000181 unsigned i;
Benny Prijono9033e312005-11-21 02:08:39 +0000182 pj_status_t rc;
183
184 /* Check that arguments are valid. */
185 PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL &&
186 max_fd > 0 && max_fd <= PJ_IOQUEUE_MAX_HANDLES,
187 PJ_EINVAL);
188
189 /* Check that size of pj_ioqueue_op_key_t is sufficient */
190 PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
191 sizeof(union operation_key), PJ_EBUG);
192
Benny Prijono5accbd02006-03-30 16:32:18 +0000193 /* Create and init common ioqueue stuffs */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000194 ioqueue = PJ_POOL_ALLOC_T(pool, pj_ioqueue_t);
Benny Prijono9033e312005-11-21 02:08:39 +0000195 ioqueue_init(ioqueue);
196
197 ioqueue->max = max_fd;
198 ioqueue->count = 0;
199 PJ_FD_ZERO(&ioqueue->rfdset);
200 PJ_FD_ZERO(&ioqueue->wfdset);
201#if PJ_HAS_TCP
202 PJ_FD_ZERO(&ioqueue->xfdset);
203#endif
Benny Prijono5accbd02006-03-30 16:32:18 +0000204 pj_list_init(&ioqueue->active_list);
Benny Prijono9033e312005-11-21 02:08:39 +0000205
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000206 rescan_fdset(ioqueue);
207
Benny Prijono5accbd02006-03-30 16:32:18 +0000208#if PJ_IOQUEUE_HAS_SAFE_UNREG
209 /* When safe unregistration is used (the default), we pre-create
210 * all keys and put them in the free list.
211 */
212
213 /* Mutex to protect key's reference counter
214 * We don't want to use key's mutex or ioqueue's mutex because
215 * that would create deadlock situation in some cases.
216 */
217 rc = pj_mutex_create_simple(pool, NULL, &ioqueue->ref_cnt_mutex);
218 if (rc != PJ_SUCCESS)
219 return rc;
220
221
222 /* Init key list */
223 pj_list_init(&ioqueue->free_list);
224 pj_list_init(&ioqueue->closing_list);
225
226
227 /* Pre-create all keys according to max_fd */
228 for (i=0; i<max_fd; ++i) {
229 pj_ioqueue_key_t *key;
230
Benny Prijonoa1e69682007-05-11 15:14:34 +0000231 key = PJ_POOL_ALLOC_T(pool, pj_ioqueue_key_t);
Benny Prijono5accbd02006-03-30 16:32:18 +0000232 key->ref_count = 0;
233 rc = pj_mutex_create_recursive(pool, NULL, &key->mutex);
234 if (rc != PJ_SUCCESS) {
235 key = ioqueue->free_list.next;
236 while (key != &ioqueue->free_list) {
237 pj_mutex_destroy(key->mutex);
238 key = key->next;
239 }
240 pj_mutex_destroy(ioqueue->ref_cnt_mutex);
241 return rc;
242 }
243
244 pj_list_push_back(&ioqueue->free_list, key);
245 }
246#endif
247
248 /* Create and init ioqueue mutex */
Benny Prijono9033e312005-11-21 02:08:39 +0000249 rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
250 if (rc != PJ_SUCCESS)
251 return rc;
252
253 rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
254 if (rc != PJ_SUCCESS)
255 return rc;
256
257 PJ_LOG(4, ("pjlib", "select() I/O Queue created (%p)", ioqueue));
258
259 *p_ioqueue = ioqueue;
260 return PJ_SUCCESS;
261}
262
263/*
264 * pj_ioqueue_destroy()
265 *
266 * Destroy ioqueue.
267 */
268PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
269{
Benny Prijono5accbd02006-03-30 16:32:18 +0000270 pj_ioqueue_key_t *key;
271
Benny Prijono9033e312005-11-21 02:08:39 +0000272 PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
273
274 pj_lock_acquire(ioqueue->lock);
Benny Prijono5accbd02006-03-30 16:32:18 +0000275
276#if PJ_IOQUEUE_HAS_SAFE_UNREG
277 /* Destroy reference counters */
278 key = ioqueue->active_list.next;
279 while (key != &ioqueue->active_list) {
280 pj_mutex_destroy(key->mutex);
281 key = key->next;
282 }
283
284 key = ioqueue->closing_list.next;
285 while (key != &ioqueue->closing_list) {
286 pj_mutex_destroy(key->mutex);
287 key = key->next;
288 }
289
290 key = ioqueue->free_list.next;
291 while (key != &ioqueue->free_list) {
292 pj_mutex_destroy(key->mutex);
293 key = key->next;
294 }
295
296 pj_mutex_destroy(ioqueue->ref_cnt_mutex);
297#endif
298
Benny Prijono9033e312005-11-21 02:08:39 +0000299 return ioqueue_destroy(ioqueue);
300}
301
302
303/*
304 * pj_ioqueue_register_sock()
305 *
Benny Prijono5accbd02006-03-30 16:32:18 +0000306 * Register socket handle to ioqueue.
Benny Prijono9033e312005-11-21 02:08:39 +0000307 */
308PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
309 pj_ioqueue_t *ioqueue,
310 pj_sock_t sock,
311 void *user_data,
312 const pj_ioqueue_callback *cb,
313 pj_ioqueue_key_t **p_key)
314{
315 pj_ioqueue_key_t *key = NULL;
Benny Prijonofc24e692007-01-27 18:31:51 +0000316#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
317 defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
318 u_long value;
319#else
Benny Prijono9033e312005-11-21 02:08:39 +0000320 pj_uint32_t value;
Benny Prijonofc24e692007-01-27 18:31:51 +0000321#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000322 pj_status_t rc = PJ_SUCCESS;
323
324 PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
325 cb && p_key, PJ_EINVAL);
326
327 pj_lock_acquire(ioqueue->lock);
328
329 if (ioqueue->count >= ioqueue->max) {
330 rc = PJ_ETOOMANY;
331 goto on_return;
332 }
333
Benny Prijono5accbd02006-03-30 16:32:18 +0000334 /* If safe unregistration (PJ_IOQUEUE_HAS_SAFE_UNREG) is used, get
335 * the key from the free list. Otherwise allocate a new one.
336 */
337#if PJ_IOQUEUE_HAS_SAFE_UNREG
Benny Prijonocde71422007-09-19 12:03:28 +0000338
339 /* Scan closing_keys first to let them come back to free_list */
340 scan_closing_keys(ioqueue);
341
Benny Prijono5accbd02006-03-30 16:32:18 +0000342 pj_assert(!pj_list_empty(&ioqueue->free_list));
343 if (pj_list_empty(&ioqueue->free_list)) {
344 rc = PJ_ETOOMANY;
345 goto on_return;
346 }
347
348 key = ioqueue->free_list.next;
349 pj_list_erase(key);
350#else
351 key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
352#endif
353
354 rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
355 if (rc != PJ_SUCCESS) {
356 key = NULL;
357 goto on_return;
358 }
359
Benny Prijono9033e312005-11-21 02:08:39 +0000360 /* Set socket to nonblocking. */
361 value = 1;
Benny Prijono9cf138e2006-01-19 03:58:29 +0000362#if defined(PJ_WIN32) && PJ_WIN32!=0 || \
363 defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
Benny Prijonofc24e692007-01-27 18:31:51 +0000364 if (ioctlsocket(sock, FIONBIO, &value)) {
Benny Prijono9033e312005-11-21 02:08:39 +0000365#else
366 if (ioctl(sock, FIONBIO, &value)) {
367#endif
368 rc = pj_get_netos_error();
369 goto on_return;
370 }
371
Benny Prijono9033e312005-11-21 02:08:39 +0000372
Benny Prijono5accbd02006-03-30 16:32:18 +0000373 /* Put in active list. */
374 pj_list_insert_before(&ioqueue->active_list, key);
Benny Prijono9033e312005-11-21 02:08:39 +0000375 ++ioqueue->count;
376
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000377 /* Rescan fdset to get max descriptor */
378 rescan_fdset(ioqueue);
379
Benny Prijono9033e312005-11-21 02:08:39 +0000380on_return:
381 /* On error, socket may be left in non-blocking mode. */
382 *p_key = key;
383 pj_lock_release(ioqueue->lock);
384
385 return rc;
386}
387
Benny Prijono5accbd02006-03-30 16:32:18 +0000388#if PJ_IOQUEUE_HAS_SAFE_UNREG
389/* Increment key's reference counter */
390static void increment_counter(pj_ioqueue_key_t *key)
391{
392 pj_mutex_lock(key->ioqueue->ref_cnt_mutex);
393 ++key->ref_count;
394 pj_mutex_unlock(key->ioqueue->ref_cnt_mutex);
395}
396
397/* Decrement the key's reference counter, and when the counter reach zero,
398 * destroy the key.
399 *
400 * Note: MUST NOT CALL THIS FUNCTION WHILE HOLDING ioqueue's LOCK.
401 */
402static void decrement_counter(pj_ioqueue_key_t *key)
403{
Benny Prijono324409e2007-10-31 07:53:17 +0000404 pj_lock_acquire(key->ioqueue->lock);
Benny Prijono5accbd02006-03-30 16:32:18 +0000405 pj_mutex_lock(key->ioqueue->ref_cnt_mutex);
406 --key->ref_count;
407 if (key->ref_count == 0) {
408
409 pj_assert(key->closing == 1);
410 pj_gettimeofday(&key->free_time);
411 key->free_time.msec += PJ_IOQUEUE_KEY_FREE_DELAY;
412 pj_time_val_normalize(&key->free_time);
413
Benny Prijono5accbd02006-03-30 16:32:18 +0000414 pj_list_erase(key);
415 pj_list_push_back(&key->ioqueue->closing_list, key);
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000416 /* Rescan fdset to get max descriptor */
417 rescan_fdset(key->ioqueue);
Benny Prijono5accbd02006-03-30 16:32:18 +0000418 }
419 pj_mutex_unlock(key->ioqueue->ref_cnt_mutex);
Benny Prijono324409e2007-10-31 07:53:17 +0000420 pj_lock_release(key->ioqueue->lock);
Benny Prijono5accbd02006-03-30 16:32:18 +0000421}
422#endif
423
424
Benny Prijono9033e312005-11-21 02:08:39 +0000425/*
426 * pj_ioqueue_unregister()
427 *
428 * Unregister handle from ioqueue.
429 */
430PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
431{
432 pj_ioqueue_t *ioqueue;
433
434 PJ_ASSERT_RETURN(key, PJ_EINVAL);
435
436 ioqueue = key->ioqueue;
437
Benny Prijono5accbd02006-03-30 16:32:18 +0000438 /* Lock the key to make sure no callback is simultaneously modifying
439 * the key. We need to lock the key before ioqueue here to prevent
440 * deadlock.
441 */
442 pj_mutex_lock(key->mutex);
443
444 /* Also lock ioqueue */
Benny Prijono9033e312005-11-21 02:08:39 +0000445 pj_lock_acquire(ioqueue->lock);
446
447 pj_assert(ioqueue->count > 0);
448 --ioqueue->count;
Benny Prijono9969d182008-04-02 18:36:35 +0000449#if !PJ_IOQUEUE_HAS_SAFE_UNREG
450 /* Ticket #520, key will be erased more than once */
Benny Prijono9033e312005-11-21 02:08:39 +0000451 pj_list_erase(key);
Benny Prijono9969d182008-04-02 18:36:35 +0000452#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000453 PJ_FD_CLR(key->fd, &ioqueue->rfdset);
454 PJ_FD_CLR(key->fd, &ioqueue->wfdset);
455#if PJ_HAS_TCP
456 PJ_FD_CLR(key->fd, &ioqueue->xfdset);
457#endif
458
Benny Prijono5accbd02006-03-30 16:32:18 +0000459 /* Close socket. */
460 pj_sock_close(key->fd);
461
462 /* Clear callback */
463 key->cb.on_accept_complete = NULL;
464 key->cb.on_connect_complete = NULL;
465 key->cb.on_read_complete = NULL;
466 key->cb.on_write_complete = NULL;
467
468 /* Must release ioqueue lock first before decrementing counter, to
469 * prevent deadlock.
Benny Prijono9033e312005-11-21 02:08:39 +0000470 */
471 pj_lock_release(ioqueue->lock);
472
Benny Prijono5accbd02006-03-30 16:32:18 +0000473#if PJ_IOQUEUE_HAS_SAFE_UNREG
474 /* Mark key is closing. */
475 key->closing = 1;
476
477 /* Decrement counter. */
478 decrement_counter(key);
479
480 /* Done. */
481 pj_mutex_unlock(key->mutex);
482#else
483 pj_mutex_destroy(key->mutex);
484#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000485
486 return PJ_SUCCESS;
487}
488
489
490/* This supposed to check whether the fd_set values are consistent
491 * with the operation currently set in each key.
492 */
493#if VALIDATE_FD_SET
494static void validate_sets(const pj_ioqueue_t *ioqueue,
495 const pj_fd_set_t *rfdset,
496 const pj_fd_set_t *wfdset,
497 const pj_fd_set_t *xfdset)
498{
499 pj_ioqueue_key_t *key;
500
501 /*
502 * This basicly would not work anymore.
503 * We need to lock key before performing the check, but we can't do
504 * so because we're holding ioqueue mutex. If we acquire key's mutex
505 * now, the will cause deadlock.
506 */
507 pj_assert(0);
508
Benny Prijono5accbd02006-03-30 16:32:18 +0000509 key = ioqueue->active_list.next;
510 while (key != &ioqueue->active_list) {
Benny Prijono9033e312005-11-21 02:08:39 +0000511 if (!pj_list_empty(&key->read_list)
512#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
513 || !pj_list_empty(&key->accept_list)
514#endif
515 )
516 {
517 pj_assert(PJ_FD_ISSET(key->fd, rfdset));
518 }
519 else {
520 pj_assert(PJ_FD_ISSET(key->fd, rfdset) == 0);
521 }
522 if (!pj_list_empty(&key->write_list)
523#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
524 || key->connecting
525#endif
526 )
527 {
528 pj_assert(PJ_FD_ISSET(key->fd, wfdset));
529 }
530 else {
531 pj_assert(PJ_FD_ISSET(key->fd, wfdset) == 0);
532 }
533#if defined(PJ_HAS_TCP) && PJ_HAS_TCP != 0
534 if (key->connecting)
535 {
536 pj_assert(PJ_FD_ISSET(key->fd, xfdset));
537 }
538 else {
539 pj_assert(PJ_FD_ISSET(key->fd, xfdset) == 0);
540 }
541#endif /* PJ_HAS_TCP */
542
543 key = key->next;
544 }
545}
546#endif /* VALIDATE_FD_SET */
547
548
549/* ioqueue_remove_from_set()
550 * This function is called from ioqueue_dispatch_event() to instruct
551 * the ioqueue to remove the specified descriptor from ioqueue's descriptor
552 * set for the specified event.
553 */
554static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
Benny Prijono63ab3562006-07-08 19:46:43 +0000555 pj_ioqueue_key_t *key,
Benny Prijono9033e312005-11-21 02:08:39 +0000556 enum ioqueue_event_type event_type)
557{
558 pj_lock_acquire(ioqueue->lock);
559
560 if (event_type == READABLE_EVENT)
Benny Prijono63ab3562006-07-08 19:46:43 +0000561 PJ_FD_CLR((pj_sock_t)key->fd, &ioqueue->rfdset);
Benny Prijono9033e312005-11-21 02:08:39 +0000562 else if (event_type == WRITEABLE_EVENT)
Benny Prijono63ab3562006-07-08 19:46:43 +0000563 PJ_FD_CLR((pj_sock_t)key->fd, &ioqueue->wfdset);
Benny Prijono3569c0d2007-04-06 10:29:20 +0000564#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
Benny Prijono9033e312005-11-21 02:08:39 +0000565 else if (event_type == EXCEPTION_EVENT)
Benny Prijono63ab3562006-07-08 19:46:43 +0000566 PJ_FD_CLR((pj_sock_t)key->fd, &ioqueue->xfdset);
Benny Prijono3569c0d2007-04-06 10:29:20 +0000567#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000568 else
569 pj_assert(0);
570
571 pj_lock_release(ioqueue->lock);
572}
573
574/*
575 * ioqueue_add_to_set()
576 * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
577 * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
578 * set for the specified event.
579 */
580static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
Benny Prijono63ab3562006-07-08 19:46:43 +0000581 pj_ioqueue_key_t *key,
Benny Prijono9033e312005-11-21 02:08:39 +0000582 enum ioqueue_event_type event_type )
583{
584 pj_lock_acquire(ioqueue->lock);
585
586 if (event_type == READABLE_EVENT)
Benny Prijono63ab3562006-07-08 19:46:43 +0000587 PJ_FD_SET((pj_sock_t)key->fd, &ioqueue->rfdset);
Benny Prijono9033e312005-11-21 02:08:39 +0000588 else if (event_type == WRITEABLE_EVENT)
Benny Prijono63ab3562006-07-08 19:46:43 +0000589 PJ_FD_SET((pj_sock_t)key->fd, &ioqueue->wfdset);
Benny Prijono3569c0d2007-04-06 10:29:20 +0000590#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
Benny Prijono9033e312005-11-21 02:08:39 +0000591 else if (event_type == EXCEPTION_EVENT)
Benny Prijono63ab3562006-07-08 19:46:43 +0000592 PJ_FD_SET((pj_sock_t)key->fd, &ioqueue->xfdset);
Benny Prijono3569c0d2007-04-06 10:29:20 +0000593#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000594 else
595 pj_assert(0);
596
597 pj_lock_release(ioqueue->lock);
598}
599
Benny Prijono5accbd02006-03-30 16:32:18 +0000600#if PJ_IOQUEUE_HAS_SAFE_UNREG
601/* Scan closing keys to be put to free list again */
602static void scan_closing_keys(pj_ioqueue_t *ioqueue)
603{
604 pj_time_val now;
605 pj_ioqueue_key_t *h;
606
607 pj_gettimeofday(&now);
608 h = ioqueue->closing_list.next;
609 while (h != &ioqueue->closing_list) {
610 pj_ioqueue_key_t *next = h->next;
611
612 pj_assert(h->closing != 0);
613
614 if (PJ_TIME_VAL_GTE(now, h->free_time)) {
615 pj_list_erase(h);
616 pj_list_push_back(&ioqueue->free_list, h);
617 }
618 h = next;
619 }
620}
621#endif
622
623
Benny Prijono9033e312005-11-21 02:08:39 +0000624/*
625 * pj_ioqueue_poll()
626 *
627 * Few things worth written:
628 *
629 * - we used to do only one callback called per poll, but it didn't go
630 * very well. The reason is because on some situation, the write
631 * callback gets called all the time, thus doesn't give the read
632 * callback to get called. This happens, for example, when user
633 * submit write operation inside the write callback.
634 * As the result, we changed the behaviour so that now multiple
635 * callbacks are called in a single poll. It should be fast too,
636 * just that we need to be carefull with the ioqueue data structs.
637 *
638 * - to guarantee preemptiveness etc, the poll function must strictly
639 * work on fd_set copy of the ioqueue (not the original one).
640 */
641PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
642{
643 pj_fd_set_t rfdset, wfdset, xfdset;
644 int count, counter;
645 pj_ioqueue_key_t *h;
646 struct event
647 {
648 pj_ioqueue_key_t *key;
649 enum ioqueue_event_type event_type;
650 } event[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
651
Benny Prijono37e8d332006-01-20 21:03:36 +0000652 PJ_ASSERT_RETURN(ioqueue, -PJ_EINVAL);
Benny Prijono9033e312005-11-21 02:08:39 +0000653
654 /* Lock ioqueue before making fd_set copies */
655 pj_lock_acquire(ioqueue->lock);
656
657 /* We will only do select() when there are sockets to be polled.
658 * Otherwise select() will return error.
659 */
660 if (PJ_FD_COUNT(&ioqueue->rfdset)==0 &&
Benny Prijono3569c0d2007-04-06 10:29:20 +0000661 PJ_FD_COUNT(&ioqueue->wfdset)==0
662#if defined(PJ_HAS_TCP) && PJ_HAS_TCP!=0
663 && PJ_FD_COUNT(&ioqueue->xfdset)==0
664#endif
665 )
Benny Prijono9033e312005-11-21 02:08:39 +0000666 {
Benny Prijono5accbd02006-03-30 16:32:18 +0000667#if PJ_IOQUEUE_HAS_SAFE_UNREG
668 scan_closing_keys(ioqueue);
669#endif
670 pj_lock_release(ioqueue->lock);
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000671 TRACE__((THIS_FILE, " poll: no fd is set"));
Benny Prijono9033e312005-11-21 02:08:39 +0000672 if (timeout)
673 pj_thread_sleep(PJ_TIME_VAL_MSEC(*timeout));
674 return 0;
675 }
676
677 /* Copy ioqueue's pj_fd_set_t to local variables. */
678 pj_memcpy(&rfdset, &ioqueue->rfdset, sizeof(pj_fd_set_t));
679 pj_memcpy(&wfdset, &ioqueue->wfdset, sizeof(pj_fd_set_t));
680#if PJ_HAS_TCP
681 pj_memcpy(&xfdset, &ioqueue->xfdset, sizeof(pj_fd_set_t));
682#else
683 PJ_FD_ZERO(&xfdset);
684#endif
685
686#if VALIDATE_FD_SET
687 validate_sets(ioqueue, &rfdset, &wfdset, &xfdset);
688#endif
689
690 /* Unlock ioqueue before select(). */
691 pj_lock_release(ioqueue->lock);
692
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000693 count = pj_sock_select(ioqueue->nfds+1, &rfdset, &wfdset, &xfdset,
694 timeout);
Benny Prijono9033e312005-11-21 02:08:39 +0000695
Benny Prijono34b00742008-03-13 21:51:51 +0000696 if (count == 0)
697 return 0;
698 else if (count < 0)
Benny Prijono37e8d332006-01-20 21:03:36 +0000699 return -pj_get_netos_error();
Benny Prijono9033e312005-11-21 02:08:39 +0000700 else if (count > PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL)
701 count = PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL;
702
703 /* Scan descriptor sets for event and add the events in the event
704 * array to be processed later in this function. We do this so that
705 * events can be processed in parallel without holding ioqueue lock.
706 */
707 pj_lock_acquire(ioqueue->lock);
708
709 counter = 0;
710
711 /* Scan for writable sockets first to handle piggy-back data
712 * coming with accept().
713 */
Benny Prijono5accbd02006-03-30 16:32:18 +0000714 h = ioqueue->active_list.next;
715 for ( ; h!=&ioqueue->active_list && counter<count; h = h->next) {
716
Benny Prijono9033e312005-11-21 02:08:39 +0000717 if ( (key_has_pending_write(h) || key_has_pending_connect(h))
Benny Prijono3059eb62006-10-04 20:46:27 +0000718 && PJ_FD_ISSET(h->fd, &wfdset) && !IS_CLOSING(h))
Benny Prijono9033e312005-11-21 02:08:39 +0000719 {
Benny Prijono5accbd02006-03-30 16:32:18 +0000720#if PJ_IOQUEUE_HAS_SAFE_UNREG
721 increment_counter(h);
722#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000723 event[counter].key = h;
724 event[counter].event_type = WRITEABLE_EVENT;
725 ++counter;
726 }
727
728 /* Scan for readable socket. */
729 if ((key_has_pending_read(h) || key_has_pending_accept(h))
Benny Prijonoccf3e242009-03-26 11:16:06 +0000730 && PJ_FD_ISSET(h->fd, &rfdset) && !IS_CLOSING(h) &&
731 counter<count)
Benny Prijono9033e312005-11-21 02:08:39 +0000732 {
Benny Prijono5accbd02006-03-30 16:32:18 +0000733#if PJ_IOQUEUE_HAS_SAFE_UNREG
734 increment_counter(h);
735#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000736 event[counter].key = h;
737 event[counter].event_type = READABLE_EVENT;
738 ++counter;
739 }
740
741#if PJ_HAS_TCP
Benny Prijono5accbd02006-03-30 16:32:18 +0000742 if (key_has_pending_connect(h) && PJ_FD_ISSET(h->fd, &xfdset) &&
Benny Prijonoccf3e242009-03-26 11:16:06 +0000743 !IS_CLOSING(h) && counter<count)
Benny Prijono5accbd02006-03-30 16:32:18 +0000744 {
745#if PJ_IOQUEUE_HAS_SAFE_UNREG
746 increment_counter(h);
747#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000748 event[counter].key = h;
749 event[counter].event_type = EXCEPTION_EVENT;
750 ++counter;
751 }
752#endif
753 }
754
755 pj_lock_release(ioqueue->lock);
756
757 count = counter;
758
759 /* Now process all events. The dispatch functions will take care
760 * of locking in each of the key
761 */
762 for (counter=0; counter<count; ++counter) {
763 switch (event[counter].event_type) {
764 case READABLE_EVENT:
765 ioqueue_dispatch_read_event(ioqueue, event[counter].key);
766 break;
767 case WRITEABLE_EVENT:
768 ioqueue_dispatch_write_event(ioqueue, event[counter].key);
769 break;
770 case EXCEPTION_EVENT:
771 ioqueue_dispatch_exception_event(ioqueue, event[counter].key);
772 break;
773 case NO_EVENT:
774 pj_assert(!"Invalid event!");
775 break;
776 }
Benny Prijono5accbd02006-03-30 16:32:18 +0000777
778#if PJ_IOQUEUE_HAS_SAFE_UNREG
779 decrement_counter(event[counter].key);
780#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000781 }
782
Benny Prijono5accbd02006-03-30 16:32:18 +0000783
Benny Prijono9033e312005-11-21 02:08:39 +0000784 return count;
785}
786