blob: 75c6ab09d9ce95d5a3b437b353a2e8a542768c1e [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijonod4787662008-09-23 09:40:11 +00003 * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19/*
20 * ioqueue_epoll.c
21 *
22 * This is the implementation of IOQueue framework using /dev/epoll
23 * API in _both_ Linux user-mode and kernel-mode.
24 */
25
26#include <pj/ioqueue.h>
27#include <pj/os.h>
28#include <pj/lock.h>
29#include <pj/log.h>
30#include <pj/list.h>
31#include <pj/pool.h>
32#include <pj/string.h>
33#include <pj/assert.h>
34#include <pj/errno.h>
35#include <pj/sock.h>
36#include <pj/compat/socket.h>
37
38#if !defined(PJ_LINUX_KERNEL) || PJ_LINUX_KERNEL==0
39 /*
40 * Linux user mode
41 */
42# include <sys/epoll.h>
43# include <errno.h>
44# include <unistd.h>
45
46# define epoll_data data.ptr
47# define epoll_data_type void*
48# define ioctl_val_type unsigned long
49# define getsockopt_val_ptr int*
50# define os_getsockopt getsockopt
51# define os_ioctl ioctl
52# define os_read read
53# define os_close close
54# define os_epoll_create epoll_create
55# define os_epoll_ctl epoll_ctl
56# define os_epoll_wait epoll_wait
57#else
58 /*
59 * Linux kernel mode.
60 */
61# include <linux/config.h>
62# include <linux/version.h>
63# if defined(MODVERSIONS)
64# include <linux/modversions.h>
65# endif
66# include <linux/kernel.h>
67# include <linux/poll.h>
68# include <linux/eventpoll.h>
69# include <linux/syscalls.h>
70# include <linux/errno.h>
71# include <linux/unistd.h>
72# include <asm/ioctls.h>
73 enum EPOLL_EVENTS
74 {
75 EPOLLIN = 0x001,
76 EPOLLOUT = 0x004,
77 EPOLLERR = 0x008,
78 };
79# define os_epoll_create sys_epoll_create
80 static int os_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
81 {
82 long rc;
83 mm_segment_t oldfs = get_fs();
84 set_fs(KERNEL_DS);
85 rc = sys_epoll_ctl(epfd, op, fd, event);
86 set_fs(oldfs);
87 if (rc) {
88 errno = -rc;
89 return -1;
90 } else {
91 return 0;
92 }
93 }
94 static int os_epoll_wait(int epfd, struct epoll_event *events,
95 int maxevents, int timeout)
96 {
97 int count;
98 mm_segment_t oldfs = get_fs();
99 set_fs(KERNEL_DS);
100 count = sys_epoll_wait(epfd, events, maxevents, timeout);
101 set_fs(oldfs);
102 return count;
103 }
104# define os_close sys_close
105# define os_getsockopt pj_sock_getsockopt
106 static int os_read(int fd, void *buf, size_t len)
107 {
108 long rc;
109 mm_segment_t oldfs = get_fs();
110 set_fs(KERNEL_DS);
111 rc = sys_read(fd, buf, len);
112 set_fs(oldfs);
113 if (rc) {
114 errno = -rc;
115 return -1;
116 } else {
117 return 0;
118 }
119 }
120# define socklen_t unsigned
121# define ioctl_val_type unsigned long
122 int ioctl(int fd, int opt, ioctl_val_type value);
123 static int os_ioctl(int fd, int opt, ioctl_val_type value)
124 {
125 int rc;
126 mm_segment_t oldfs = get_fs();
127 set_fs(KERNEL_DS);
128 rc = ioctl(fd, opt, value);
129 set_fs(oldfs);
130 if (rc < 0) {
131 errno = -rc;
132 return rc;
133 } else
134 return rc;
135 }
136# define getsockopt_val_ptr char*
137
138# define epoll_data data
139# define epoll_data_type __u32
140#endif
141
142#define THIS_FILE "ioq_epoll"
143
Benny Prijono63ab3562006-07-08 19:46:43 +0000144//#define TRACE_(expr) PJ_LOG(3,expr)
145#define TRACE_(expr)
Benny Prijono9033e312005-11-21 02:08:39 +0000146
147/*
148 * Include common ioqueue abstraction.
149 */
150#include "ioqueue_common_abs.h"
151
152/*
153 * This describes each key.
154 */
155struct pj_ioqueue_key_t
156{
157 DECLARE_COMMON_KEY
158};
159
Benny Prijono63ab3562006-07-08 19:46:43 +0000160struct queue
161{
162 pj_ioqueue_key_t *key;
163 enum ioqueue_event_type event_type;
164};
165
Benny Prijono9033e312005-11-21 02:08:39 +0000166/*
167 * This describes the I/O queue.
168 */
169struct pj_ioqueue_t
170{
171 DECLARE_COMMON_IOQUEUE
172
173 unsigned max, count;
Benny Prijonod4787662008-09-23 09:40:11 +0000174 //pj_ioqueue_key_t hlist;
175 pj_ioqueue_key_t active_list;
Benny Prijono9033e312005-11-21 02:08:39 +0000176 int epfd;
Benny Prijonod4787662008-09-23 09:40:11 +0000177 //struct epoll_event *events;
178 //struct queue *queue;
Benny Prijono99eec382008-09-18 21:22:16 +0000179
180#if PJ_IOQUEUE_HAS_SAFE_UNREG
181 pj_mutex_t *ref_cnt_mutex;
Benny Prijono99eec382008-09-18 21:22:16 +0000182 pj_ioqueue_key_t closing_list;
183 pj_ioqueue_key_t free_list;
184#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000185};
186
187/* Include implementation for common abstraction after we declare
188 * pj_ioqueue_key_t and pj_ioqueue_t.
189 */
190#include "ioqueue_common_abs.c"
191
Benny Prijono99eec382008-09-18 21:22:16 +0000192#if PJ_IOQUEUE_HAS_SAFE_UNREG
193/* Scan closing keys to be put to free list again */
194static void scan_closing_keys(pj_ioqueue_t *ioqueue);
195#endif
196
Benny Prijono9033e312005-11-21 02:08:39 +0000197/*
198 * pj_ioqueue_name()
199 */
200PJ_DEF(const char*) pj_ioqueue_name(void)
201{
202#if defined(PJ_LINUX_KERNEL) && PJ_LINUX_KERNEL!=0
203 return "epoll-kernel";
204#else
205 return "epoll";
206#endif
207}
208
209/*
210 * pj_ioqueue_create()
211 *
212 * Create select ioqueue.
213 */
214PJ_DEF(pj_status_t) pj_ioqueue_create( pj_pool_t *pool,
215 pj_size_t max_fd,
216 pj_ioqueue_t **p_ioqueue)
217{
218 pj_ioqueue_t *ioqueue;
219 pj_status_t rc;
220 pj_lock_t *lock;
Benny Prijono99eec382008-09-18 21:22:16 +0000221 int i;
Benny Prijono9033e312005-11-21 02:08:39 +0000222
223 /* Check that arguments are valid. */
224 PJ_ASSERT_RETURN(pool != NULL && p_ioqueue != NULL &&
225 max_fd > 0, PJ_EINVAL);
226
227 /* Check that size of pj_ioqueue_op_key_t is sufficient */
228 PJ_ASSERT_RETURN(sizeof(pj_ioqueue_op_key_t)-sizeof(void*) >=
229 sizeof(union operation_key), PJ_EBUG);
230
231 ioqueue = pj_pool_alloc(pool, sizeof(pj_ioqueue_t));
232
233 ioqueue_init(ioqueue);
234
235 ioqueue->max = max_fd;
236 ioqueue->count = 0;
Benny Prijonod4787662008-09-23 09:40:11 +0000237 pj_list_init(&ioqueue->active_list);
Benny Prijono9033e312005-11-21 02:08:39 +0000238
Benny Prijono99eec382008-09-18 21:22:16 +0000239#if PJ_IOQUEUE_HAS_SAFE_UNREG
240 /* When safe unregistration is used (the default), we pre-create
241 * all keys and put them in the free list.
242 */
243
244 /* Mutex to protect key's reference counter
245 * We don't want to use key's mutex or ioqueue's mutex because
246 * that would create deadlock situation in some cases.
247 */
248 rc = pj_mutex_create_simple(pool, NULL, &ioqueue->ref_cnt_mutex);
249 if (rc != PJ_SUCCESS)
250 return rc;
251
252
253 /* Init key list */
254 pj_list_init(&ioqueue->free_list);
255 pj_list_init(&ioqueue->closing_list);
256
257
258 /* Pre-create all keys according to max_fd */
259 for ( i=0; i<max_fd; ++i) {
260 pj_ioqueue_key_t *key;
261
262 key = PJ_POOL_ALLOC_T(pool, pj_ioqueue_key_t);
263 key->ref_count = 0;
264 rc = pj_mutex_create_recursive(pool, NULL, &key->mutex);
265 if (rc != PJ_SUCCESS) {
266 key = ioqueue->free_list.next;
267 while (key != &ioqueue->free_list) {
268 pj_mutex_destroy(key->mutex);
269 key = key->next;
270 }
271 pj_mutex_destroy(ioqueue->ref_cnt_mutex);
272 return rc;
273 }
274
275 pj_list_push_back(&ioqueue->free_list, key);
276 }
277#endif
278
Benny Prijono9033e312005-11-21 02:08:39 +0000279 rc = pj_lock_create_simple_mutex(pool, "ioq%p", &lock);
280 if (rc != PJ_SUCCESS)
281 return rc;
282
283 rc = pj_ioqueue_set_lock(ioqueue, lock, PJ_TRUE);
284 if (rc != PJ_SUCCESS)
285 return rc;
286
287 ioqueue->epfd = os_epoll_create(max_fd);
288 if (ioqueue->epfd < 0) {
289 ioqueue_destroy(ioqueue);
290 return PJ_RETURN_OS_ERROR(pj_get_native_os_error());
291 }
292
Benny Prijonod4787662008-09-23 09:40:11 +0000293 /*ioqueue->events = pj_pool_calloc(pool, max_fd, sizeof(struct epoll_event));
Benny Prijono63ab3562006-07-08 19:46:43 +0000294 PJ_ASSERT_RETURN(ioqueue->events != NULL, PJ_ENOMEM);
295
296 ioqueue->queue = pj_pool_calloc(pool, max_fd, sizeof(struct queue));
297 PJ_ASSERT_RETURN(ioqueue->queue != NULL, PJ_ENOMEM);
Benny Prijonod4787662008-09-23 09:40:11 +0000298 */
Benny Prijono9033e312005-11-21 02:08:39 +0000299 PJ_LOG(4, ("pjlib", "epoll I/O Queue created (%p)", ioqueue));
300
301 *p_ioqueue = ioqueue;
302 return PJ_SUCCESS;
303}
304
305/*
306 * pj_ioqueue_destroy()
307 *
308 * Destroy ioqueue.
309 */
310PJ_DEF(pj_status_t) pj_ioqueue_destroy(pj_ioqueue_t *ioqueue)
311{
Benny Prijono99eec382008-09-18 21:22:16 +0000312 pj_ioqueue_key_t *key;
313
Benny Prijono9033e312005-11-21 02:08:39 +0000314 PJ_ASSERT_RETURN(ioqueue, PJ_EINVAL);
315 PJ_ASSERT_RETURN(ioqueue->epfd > 0, PJ_EINVALIDOP);
316
317 pj_lock_acquire(ioqueue->lock);
318 os_close(ioqueue->epfd);
319 ioqueue->epfd = 0;
Benny Prijono99eec382008-09-18 21:22:16 +0000320
321#if PJ_IOQUEUE_HAS_SAFE_UNREG
322 /* Destroy reference counters */
323 key = ioqueue->active_list.next;
324 while (key != &ioqueue->active_list) {
325 pj_mutex_destroy(key->mutex);
326 key = key->next;
327 }
328
329 key = ioqueue->closing_list.next;
330 while (key != &ioqueue->closing_list) {
331 pj_mutex_destroy(key->mutex);
332 key = key->next;
333 }
334
335 key = ioqueue->free_list.next;
336 while (key != &ioqueue->free_list) {
337 pj_mutex_destroy(key->mutex);
338 key = key->next;
339 }
340
341 pj_mutex_destroy(ioqueue->ref_cnt_mutex);
342#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000343 return ioqueue_destroy(ioqueue);
344}
345
346/*
347 * pj_ioqueue_register_sock()
348 *
349 * Register a socket to ioqueue.
350 */
351PJ_DEF(pj_status_t) pj_ioqueue_register_sock( pj_pool_t *pool,
352 pj_ioqueue_t *ioqueue,
353 pj_sock_t sock,
354 void *user_data,
355 const pj_ioqueue_callback *cb,
356 pj_ioqueue_key_t **p_key)
357{
358 pj_ioqueue_key_t *key = NULL;
359 pj_uint32_t value;
360 struct epoll_event ev;
361 int status;
362 pj_status_t rc = PJ_SUCCESS;
363
364 PJ_ASSERT_RETURN(pool && ioqueue && sock != PJ_INVALID_SOCKET &&
365 cb && p_key, PJ_EINVAL);
366
367 pj_lock_acquire(ioqueue->lock);
368
369 if (ioqueue->count >= ioqueue->max) {
370 rc = PJ_ETOOMANY;
371 TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: too many files"));
372 goto on_return;
373 }
374
375 /* Set socket to nonblocking. */
376 value = 1;
377 if ((rc=os_ioctl(sock, FIONBIO, (ioctl_val_type)&value))) {
378 TRACE_((THIS_FILE, "pj_ioqueue_register_sock error: ioctl rc=%d",
379 rc));
380 rc = pj_get_netos_error();
381 goto on_return;
382 }
383
Benny Prijono99eec382008-09-18 21:22:16 +0000384 /* If safe unregistration (PJ_IOQUEUE_HAS_SAFE_UNREG) is used, get
385 * the key from the free list. Otherwise allocate a new one.
386 */
387#if PJ_IOQUEUE_HAS_SAFE_UNREG
388
389 /* Scan closing_keys first to let them come back to free_list */
390 scan_closing_keys(ioqueue);
391
392 pj_assert(!pj_list_empty(&ioqueue->free_list));
393 if (pj_list_empty(&ioqueue->free_list)) {
394 rc = PJ_ETOOMANY;
395 goto on_return;
396 }
397
398 key = ioqueue->free_list.next;
399 pj_list_erase(key);
400#else
Benny Prijono9033e312005-11-21 02:08:39 +0000401 /* Create key. */
402 key = (pj_ioqueue_key_t*)pj_pool_zalloc(pool, sizeof(pj_ioqueue_key_t));
Benny Prijono99eec382008-09-18 21:22:16 +0000403#endif
404
Benny Prijono9033e312005-11-21 02:08:39 +0000405 rc = ioqueue_init_key(pool, ioqueue, key, sock, user_data, cb);
406 if (rc != PJ_SUCCESS) {
407 key = NULL;
408 goto on_return;
409 }
410
Benny Prijonofe9c9b62006-07-06 20:43:07 +0000411 /* Create key's mutex */
Benny Prijono99eec382008-09-18 21:22:16 +0000412 /* rc = pj_mutex_create_recursive(pool, NULL, &key->mutex);
Benny Prijonofe9c9b62006-07-06 20:43:07 +0000413 if (rc != PJ_SUCCESS) {
414 key = NULL;
415 goto on_return;
416 }
Benny Prijono99eec382008-09-18 21:22:16 +0000417*/
Benny Prijono9033e312005-11-21 02:08:39 +0000418 /* os_epoll_ctl. */
Benny Prijono63ab3562006-07-08 19:46:43 +0000419 ev.events = EPOLLIN | EPOLLERR;
Benny Prijono9033e312005-11-21 02:08:39 +0000420 ev.epoll_data = (epoll_data_type)key;
421 status = os_epoll_ctl(ioqueue->epfd, EPOLL_CTL_ADD, sock, &ev);
422 if (status < 0) {
423 rc = pj_get_os_error();
Benny Prijonofe9c9b62006-07-06 20:43:07 +0000424 pj_mutex_destroy(key->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000425 key = NULL;
426 TRACE_((THIS_FILE,
427 "pj_ioqueue_register_sock error: os_epoll_ctl rc=%d",
428 status));
429 goto on_return;
430 }
431
432 /* Register */
Benny Prijonod4787662008-09-23 09:40:11 +0000433 pj_list_insert_before(&ioqueue->active_list, key);
Benny Prijono9033e312005-11-21 02:08:39 +0000434 ++ioqueue->count;
435
Benny Prijono63ab3562006-07-08 19:46:43 +0000436 //TRACE_((THIS_FILE, "socket registered, count=%d", ioqueue->count));
437
Benny Prijono9033e312005-11-21 02:08:39 +0000438on_return:
439 *p_key = key;
440 pj_lock_release(ioqueue->lock);
441
442 return rc;
443}
444
Benny Prijono99eec382008-09-18 21:22:16 +0000445#if PJ_IOQUEUE_HAS_SAFE_UNREG
446/* Increment key's reference counter */
447static void increment_counter(pj_ioqueue_key_t *key)
448{
449 pj_mutex_lock(key->ioqueue->ref_cnt_mutex);
450 ++key->ref_count;
451 pj_mutex_unlock(key->ioqueue->ref_cnt_mutex);
452}
453
454/* Decrement the key's reference counter, and when the counter reach zero,
455 * destroy the key.
456 *
457 * Note: MUST NOT CALL THIS FUNCTION WHILE HOLDING ioqueue's LOCK.
458 */
459static void decrement_counter(pj_ioqueue_key_t *key)
460{
461 pj_lock_acquire(key->ioqueue->lock);
462 pj_mutex_lock(key->ioqueue->ref_cnt_mutex);
463 --key->ref_count;
464 if (key->ref_count == 0) {
465
466 pj_assert(key->closing == 1);
467 pj_gettimeofday(&key->free_time);
468 key->free_time.msec += PJ_IOQUEUE_KEY_FREE_DELAY;
469 pj_time_val_normalize(&key->free_time);
470
471 pj_list_erase(key);
472 pj_list_push_back(&key->ioqueue->closing_list, key);
473
474 }
475 pj_mutex_unlock(key->ioqueue->ref_cnt_mutex);
476 pj_lock_release(key->ioqueue->lock);
477}
478#endif
479
Benny Prijono9033e312005-11-21 02:08:39 +0000480/*
481 * pj_ioqueue_unregister()
482 *
483 * Unregister handle from ioqueue.
484 */
485PJ_DEF(pj_status_t) pj_ioqueue_unregister( pj_ioqueue_key_t *key)
486{
487 pj_ioqueue_t *ioqueue;
488 struct epoll_event ev;
489 int status;
490
491 PJ_ASSERT_RETURN(key != NULL, PJ_EINVAL);
492
493 ioqueue = key->ioqueue;
Benny Prijono9489e7a2008-09-19 22:18:50 +0000494
495 /* Lock the key to make sure no callback is simultaneously modifying
496 * the key. We need to lock the key before ioqueue here to prevent
497 * deadlock.
498 */
499 pj_mutex_lock(key->mutex);
500
501 /* Also lock ioqueue */
Benny Prijono9033e312005-11-21 02:08:39 +0000502 pj_lock_acquire(ioqueue->lock);
503
504 pj_assert(ioqueue->count > 0);
505 --ioqueue->count;
Benny Prijono99eec382008-09-18 21:22:16 +0000506#if !PJ_IOQUEUE_HAS_SAFE_UNREG
Benny Prijono9033e312005-11-21 02:08:39 +0000507 pj_list_erase(key);
Benny Prijono99eec382008-09-18 21:22:16 +0000508#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000509
510 ev.events = 0;
511 ev.epoll_data = (epoll_data_type)key;
512 status = os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_DEL, key->fd, &ev);
513 if (status != 0) {
514 pj_status_t rc = pj_get_os_error();
515 pj_lock_release(ioqueue->lock);
516 return rc;
517 }
518
Benny Prijono9033e312005-11-21 02:08:39 +0000519 /* Destroy the key. */
Benny Prijonofe9c9b62006-07-06 20:43:07 +0000520 pj_sock_close(key->fd);
Benny Prijono99eec382008-09-18 21:22:16 +0000521
522 pj_lock_release(ioqueue->lock);
523
524
525#if PJ_IOQUEUE_HAS_SAFE_UNREG
526 /* Mark key is closing. */
527 key->closing = 1;
528
529 /* Decrement counter. */
530 decrement_counter(key);
531
532 /* Done. */
533 pj_mutex_unlock(key->mutex);
534#else
Benny Prijonofe9c9b62006-07-06 20:43:07 +0000535 pj_mutex_destroy(key->mutex);
Benny Prijono99eec382008-09-18 21:22:16 +0000536#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000537
538 return PJ_SUCCESS;
539}
540
541/* ioqueue_remove_from_set()
542 * This function is called from ioqueue_dispatch_event() to instruct
543 * the ioqueue to remove the specified descriptor from ioqueue's descriptor
544 * set for the specified event.
545 */
546static void ioqueue_remove_from_set( pj_ioqueue_t *ioqueue,
Benny Prijono63ab3562006-07-08 19:46:43 +0000547 pj_ioqueue_key_t *key,
Benny Prijono9033e312005-11-21 02:08:39 +0000548 enum ioqueue_event_type event_type)
549{
Benny Prijono63ab3562006-07-08 19:46:43 +0000550 if (event_type == WRITEABLE_EVENT) {
551 struct epoll_event ev;
552
553 ev.events = EPOLLIN | EPOLLERR;
554 ev.epoll_data = (epoll_data_type)key;
555 os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_MOD, key->fd, &ev);
556 }
Benny Prijono9033e312005-11-21 02:08:39 +0000557}
558
559/*
560 * ioqueue_add_to_set()
561 * This function is called from pj_ioqueue_recv(), pj_ioqueue_send() etc
562 * to instruct the ioqueue to add the specified handle to ioqueue's descriptor
563 * set for the specified event.
564 */
565static void ioqueue_add_to_set( pj_ioqueue_t *ioqueue,
Benny Prijono63ab3562006-07-08 19:46:43 +0000566 pj_ioqueue_key_t *key,
Benny Prijono9033e312005-11-21 02:08:39 +0000567 enum ioqueue_event_type event_type )
568{
Benny Prijono63ab3562006-07-08 19:46:43 +0000569 if (event_type == WRITEABLE_EVENT) {
570 struct epoll_event ev;
571
572 ev.events = EPOLLIN | EPOLLOUT | EPOLLERR;
573 ev.epoll_data = (epoll_data_type)key;
574 os_epoll_ctl( ioqueue->epfd, EPOLL_CTL_MOD, key->fd, &ev);
575 }
Benny Prijono9033e312005-11-21 02:08:39 +0000576}
577
Benny Prijono99eec382008-09-18 21:22:16 +0000578#if PJ_IOQUEUE_HAS_SAFE_UNREG
579/* Scan closing keys to be put to free list again */
580static void scan_closing_keys(pj_ioqueue_t *ioqueue)
581{
582 pj_time_val now;
583 pj_ioqueue_key_t *h;
584
585 pj_gettimeofday(&now);
586 h = ioqueue->closing_list.next;
587 while (h != &ioqueue->closing_list) {
588 pj_ioqueue_key_t *next = h->next;
589
590 pj_assert(h->closing != 0);
591
592 if (PJ_TIME_VAL_GTE(now, h->free_time)) {
593 pj_list_erase(h);
594 pj_list_push_back(&ioqueue->free_list, h);
595 }
596 h = next;
597 }
598}
599#endif
600
Benny Prijono9033e312005-11-21 02:08:39 +0000601/*
602 * pj_ioqueue_poll()
603 *
604 */
605PJ_DEF(int) pj_ioqueue_poll( pj_ioqueue_t *ioqueue, const pj_time_val *timeout)
606{
607 int i, count, processed;
Benny Prijono9033e312005-11-21 02:08:39 +0000608 int msec;
Benny Prijonod4787662008-09-23 09:40:11 +0000609 //struct epoll_event *events = ioqueue->events;
610 //struct queue *queue = ioqueue->queue;
611 struct epoll_event events[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
612 struct queue queue[PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL];
Benny Prijono63ab3562006-07-08 19:46:43 +0000613 pj_timestamp t1, t2;
Benny Prijono9033e312005-11-21 02:08:39 +0000614
615 PJ_CHECK_STACK();
616
617 msec = timeout ? PJ_TIME_VAL_MSEC(*timeout) : 9000;
Benny Prijono63ab3562006-07-08 19:46:43 +0000618
619 TRACE_((THIS_FILE, "start os_epoll_wait, msec=%d", msec));
620 pj_get_timestamp(&t1);
621
Benny Prijonod4787662008-09-23 09:40:11 +0000622 //count = os_epoll_wait( ioqueue->epfd, events, ioqueue->max, msec);
623 count = os_epoll_wait( ioqueue->epfd, events, PJ_IOQUEUE_MAX_EVENTS_IN_SINGLE_POLL, msec);
Benny Prijono63ab3562006-07-08 19:46:43 +0000624 if (count == 0) {
Benny Prijono99eec382008-09-18 21:22:16 +0000625#if PJ_IOQUEUE_HAS_SAFE_UNREG
626 /* Check the closing keys only when there's no activity and when there are
627 * pending closing keys.
628 */
629 if (count == 0 && !pj_list_empty(&ioqueue->closing_list)) {
630 pj_lock_acquire(ioqueue->lock);
631 scan_closing_keys(ioqueue);
632 pj_lock_release(ioqueue->lock);
633 }
634#endif
Benny Prijono63ab3562006-07-08 19:46:43 +0000635 TRACE_((THIS_FILE, "os_epoll_wait timed out"));
Benny Prijono9033e312005-11-21 02:08:39 +0000636 return count;
Benny Prijono63ab3562006-07-08 19:46:43 +0000637 }
638 else if (count < 0) {
639 TRACE_((THIS_FILE, "os_epoll_wait error"));
Benny Prijono37e8d332006-01-20 21:03:36 +0000640 return -pj_get_netos_error();
Benny Prijono63ab3562006-07-08 19:46:43 +0000641 }
642
643 pj_get_timestamp(&t2);
644 TRACE_((THIS_FILE, "os_epoll_wait returns %d, time=%d usec",
645 count, pj_elapsed_usec(&t1, &t2)));
Benny Prijono9033e312005-11-21 02:08:39 +0000646
647 /* Lock ioqueue. */
648 pj_lock_acquire(ioqueue->lock);
649
650 for (processed=0, i=0; i<count; ++i) {
651 pj_ioqueue_key_t *h = (pj_ioqueue_key_t*)(epoll_data_type)
652 events[i].epoll_data;
653
Benny Prijono63ab3562006-07-08 19:46:43 +0000654 TRACE_((THIS_FILE, "event %d: events=%d", i, events[i].events));
655
Benny Prijono9033e312005-11-21 02:08:39 +0000656 /*
657 * Check readability.
658 */
659 if ((events[i].events & EPOLLIN) &&
Benny Prijonod4787662008-09-23 09:40:11 +0000660 (key_has_pending_read(h) || key_has_pending_accept(h)) && !IS_CLOSING(h) ) {
Benny Prijono99eec382008-09-18 21:22:16 +0000661
662#if PJ_IOQUEUE_HAS_SAFE_UNREG
663 increment_counter(h);
664#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000665 queue[processed].key = h;
666 queue[processed].event_type = READABLE_EVENT;
667 ++processed;
668 }
669
670 /*
671 * Check for writeability.
672 */
Benny Prijonod4787662008-09-23 09:40:11 +0000673 if ((events[i].events & EPOLLOUT) && key_has_pending_write(h) && !IS_CLOSING(h)) {
Benny Prijono99eec382008-09-18 21:22:16 +0000674
675#if PJ_IOQUEUE_HAS_SAFE_UNREG
676 increment_counter(h);
677#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000678 queue[processed].key = h;
679 queue[processed].event_type = WRITEABLE_EVENT;
680 ++processed;
681 }
682
683#if PJ_HAS_TCP
684 /*
685 * Check for completion of connect() operation.
686 */
Benny Prijonod4787662008-09-23 09:40:11 +0000687 if ((events[i].events & EPOLLOUT) && (h->connecting) && !IS_CLOSING(h)) {
Benny Prijono99eec382008-09-18 21:22:16 +0000688
689#if PJ_IOQUEUE_HAS_SAFE_UNREG
690 increment_counter(h);
691#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000692 queue[processed].key = h;
693 queue[processed].event_type = WRITEABLE_EVENT;
694 ++processed;
695 }
696#endif /* PJ_HAS_TCP */
697
698 /*
699 * Check for error condition.
700 */
Benny Prijonod4787662008-09-23 09:40:11 +0000701 if (events[i].events & EPOLLERR && (h->connecting) && !IS_CLOSING(h)) {
Benny Prijono99eec382008-09-18 21:22:16 +0000702
703#if PJ_IOQUEUE_HAS_SAFE_UNREG
704 increment_counter(h);
705#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000706 queue[processed].key = h;
707 queue[processed].event_type = EXCEPTION_EVENT;
708 ++processed;
709 }
710 }
711 pj_lock_release(ioqueue->lock);
712
713 /* Now process the events. */
714 for (i=0; i<processed; ++i) {
715 switch (queue[i].event_type) {
716 case READABLE_EVENT:
717 ioqueue_dispatch_read_event(ioqueue, queue[i].key);
718 break;
719 case WRITEABLE_EVENT:
720 ioqueue_dispatch_write_event(ioqueue, queue[i].key);
721 break;
722 case EXCEPTION_EVENT:
723 ioqueue_dispatch_exception_event(ioqueue, queue[i].key);
724 break;
725 case NO_EVENT:
726 pj_assert(!"Invalid event!");
727 break;
728 }
Benny Prijono99eec382008-09-18 21:22:16 +0000729
730#if PJ_IOQUEUE_HAS_SAFE_UNREG
731 decrement_counter(queue[i].key);
732#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000733 }
734
Benny Prijono09413ca2006-02-27 23:52:06 +0000735 /* Special case:
736 * When epoll returns > 0 but no descriptors are actually set!
737 */
738 if (count > 0 && !processed && msec > 0) {
739 pj_thread_sleep(msec);
740 }
Benny Prijono63ab3562006-07-08 19:46:43 +0000741
742 pj_get_timestamp(&t1);
743 TRACE_((THIS_FILE, "ioqueue_poll() returns %d, time=%d usec",
744 processed, pj_elapsed_usec(&t2, &t1)));
745
Benny Prijono9033e312005-11-21 02:08:39 +0000746 return processed;
747}
748