00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifdef USE_TCP
00037
00038 #ifdef HAVE_EPOLL
00039 #include <unistd.h>
00040 #endif
00041 #ifdef HAVE_DEVPOLL
00042 #include <sys/types.h>
00043 #include <sys/stat.h>
00044 #include <fcntl.h>
00045 #include <unistd.h>
00046 #endif
00047
00048 #include <sys/utsname.h>
00049 #include <stdlib.h>
00050 #include "io_wait.h"
00051
00052
00053 #include "mem/mem.h"
00054
00055 #ifndef local_malloc
00056 #define local_malloc pkg_malloc
00057 #endif
00058 #ifndef local_free
00059 #define local_free pkg_free
00060 #endif
00061
00062 char* poll_support="poll"
00063 #ifdef HAVE_EPOLL
00064 ", epoll_lt, epoll_et"
00065 #endif
00066 #ifdef HAVE_SIGIO_RT
00067 ", sigio_rt"
00068 #endif
00069 #ifdef HAVE_SELECT
00070 ", select"
00071 #endif
00072 #ifdef HAVE_KQUEUE
00073 ", kqueue"
00074 #endif
00075 #ifdef HAVE_DEVPOLL
00076 ", /dev/poll"
00077 #endif
00078 ;
00079
00080
00081 char* poll_method_str[POLL_END]={ "none", "poll", "epoll_lt", "epoll_et",
00082 "sigio_rt", "select", "kqueue", "/dev/poll"
00083 };
00084
00085 #ifdef HAVE_SIGIO_RT
00086 static int _sigio_init=0;
00087 static int _sigio_crt_rtsig;
00088 static sigset_t _sigio_rtsig_used;
00089 #endif
00090
00091
00092
00093 #ifdef HAVE_SIGIO_RT
00094
00095
00096
00097
00098
00099
00100 static int init_sigio(io_wait_h* h, int rsig)
00101 {
00102 int r;
00103 int n;
00104 int signo;
00105 int start_sig;
00106 sigset_t oldset;
00107
00108 if (!_sigio_init){
00109 _sigio_init=1;
00110 _sigio_crt_rtsig=SIGRTMIN;
00111 sigemptyset(&_sigio_rtsig_used);
00112 }
00113 h->signo=0;
00114
00115 if (rsig==0){
00116 start_sig=_sigio_crt_rtsig;
00117 n=SIGRTMAX-SIGRTMIN;
00118 }else{
00119 if ((rsig < SIGRTMIN) || (rsig >SIGRTMAX)){
00120 LM_CRIT("real time signal %d out of"
00121 " range [%d, %d]\n", rsig, SIGRTMIN, SIGRTMAX);
00122 goto error;
00123 }
00124 start_sig=rsig;
00125 n=0;
00126 }
00127
00128 sigemptyset(&h->sset);
00129 sigemptyset(&oldset);
00130 retry1:
00131
00132 if (sigprocmask(SIG_BLOCK, &h->sset, &oldset )==-1){
00133 if (errno==EINTR) goto retry1;
00134 LM_ERR("1st sigprocmask failed: %s [%d]\n",
00135 strerror(errno), errno);
00136
00137 }
00138
00139 for (r=start_sig; r<=(n+start_sig); r++){
00140 signo=(r>SIGRTMAX)?r-SIGRTMAX+SIGRTMIN:r;
00141 if (! sigismember(&_sigio_rtsig_used, signo) &&
00142 ! sigismember(&oldset, signo)){
00143 sigaddset(&_sigio_rtsig_used, signo);
00144 h->signo=signo;
00145 _sigio_crt_rtsig=(signo<SIGRTMAX)?signo+1:SIGRTMIN;
00146 break;
00147 }
00148 }
00149
00150 if (h->signo==0){
00151 LM_CRIT("init_sigio: %s\n",
00152 rsig?"could not assign requested real-time signal":
00153 "out of real-time signals");
00154 goto error;
00155 }
00156
00157 LM_DBG("trying signal %d... \n", h->signo);
00158
00159 if (sigaddset(&h->sset, h->signo)==-1){
00160 LM_ERR("sigaddset failed for %d: %s [%d]\n",
00161 h->signo, strerror(errno), errno);
00162 goto error;
00163 }
00164 if (sigaddset(&h->sset, SIGIO)==-1){
00165 LM_ERR("sigaddset failed for %d: %s [%d]\n",
00166 SIGIO, strerror(errno), errno);
00167 goto error;
00168 }
00169 retry:
00170 if (sigprocmask(SIG_BLOCK, &h->sset, 0)==-1){
00171 if (errno==EINTR) goto retry;
00172 LM_ERR("sigprocmask failed: %s [%d]\n",
00173 strerror(errno), errno);
00174 goto error;
00175 }
00176 return 0;
00177 error:
00178 h->signo=0;
00179 sigemptyset(&h->sset);
00180 return -1;
00181 }
00182
00183
00184
00185
00186
00187
00188
00189 static void destroy_sigio(io_wait_h* h)
00190 {
00191 if (h->signo){
00192 sigprocmask(SIG_UNBLOCK, &h->sset, 0);
00193 sigemptyset(&h->sset);
00194 sigdelset(&_sigio_rtsig_used, h->signo);
00195 h->signo=0;
00196 }
00197 }
00198 #endif
00199
00200
00201
00202 #ifdef HAVE_EPOLL
00203
00204
00205
00206
00207
00208 static int init_epoll(io_wait_h* h)
00209 {
00210 again:
00211 h->epfd=epoll_create(h->max_fd_no);
00212 if (h->epfd==-1){
00213 if (errno==EINTR) goto again;
00214 LM_ERR("epoll_create: %s [%d]\n",
00215 strerror(errno), errno);
00216 return -1;
00217 }
00218 return 0;
00219 }
00220
00221
00222
00223
00224
00225 static void destroy_epoll(io_wait_h* h)
00226 {
00227 if (h->epfd!=-1){
00228 close(h->epfd);
00229 h->epfd=-1;
00230 }
00231 }
00232 #endif
00233
00234
00235
00236 #ifdef HAVE_KQUEUE
00237
00238
00239
00240
00241
00242 static int init_kqueue(io_wait_h* h)
00243 {
00244 again:
00245 h->kq_fd=kqueue();
00246 if (h->kq_fd==-1){
00247 if (errno==EINTR) goto again;
00248 LM_ERR("kqueue: %s [%d]\n",
00249 strerror(errno), errno);
00250 return -1;
00251 }
00252 return 0;
00253 }
00254
00255
00256
00257
00258
00259
00260 static void destroy_kqueue(io_wait_h* h)
00261 {
00262 if (h->kq_fd!=-1){
00263 close(h->kq_fd);
00264 h->kq_fd=-1;
00265 }
00266 }
00267 #endif
00268
00269
00270
00271 #ifdef HAVE_DEVPOLL
00272
00273
00274
00275
00276 static int init_devpoll(io_wait_h* h)
00277 {
00278 again:
00279 h->dpoll_fd=open("/dev/poll", O_RDWR);
00280 if (h->dpoll_fd==-1){
00281 if (errno==EINTR) goto again;
00282 LM_ERR("open: %s [%d]\n",
00283 strerror(errno), errno);
00284 return -1;
00285 }
00286 return 0;
00287 }
00288
00289
00290
00291
00292
00293
00294 static void destroy_devpoll(io_wait_h* h)
00295 {
00296 if (h->dpoll_fd!=-1){
00297 close(h->dpoll_fd);
00298 h->dpoll_fd=-1;
00299 }
00300 }
00301 #endif
00302
00303
00304
00305 #ifdef HAVE_SELECT
00306
00307
00308
00309
00310
00311
00312 static int init_select(io_wait_h* h)
00313 {
00314 FD_ZERO(&h->master_set);
00315 return 0;
00316 }
00317 #endif
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331 static unsigned int get_sys_version(int* major, int* minor, int* minor2)
00332 {
00333 struct utsname un;
00334 int m1;
00335 int m2;
00336 int m3;
00337 char* p;
00338
00339 memset (&un, 0, sizeof(un));
00340 m1=m2=m3=0;
00341
00342 uname(&un);
00343 m1=strtol(un.release, &p, 10);
00344 if (*p=='.'){
00345 p++;
00346 m2=strtol(p, &p, 10);
00347 if (*p=='.'){
00348 p++;
00349 m3=strtol(p, &p, 10);
00350 }
00351 }
00352 if (major) *major=m1;
00353 if (minor) *minor=m2;
00354 if (minor2) *minor2=m3;
00355 return ((m1<<16)|(m2<<8)|(m3));
00356 }
00357
00358
00359
00360
00361
00362
00363
00364
00365 char* check_poll_method(enum poll_types poll_method)
00366 {
00367 char* ret;
00368 unsigned int os_ver;
00369
00370 ret=0;
00371 os_ver=get_sys_version(0,0,0);
00372 switch(poll_method){
00373 case POLL_NONE:
00374 break;
00375 case POLL_POLL:
00376
00377 break;
00378 case POLL_SELECT:
00379
00380 #ifndef HAVE_SELECT
00381 ret="select not supported, try re-compiling with -DHAVE_SELECT";
00382 #endif
00383 break;
00384 case POLL_EPOLL_LT:
00385 case POLL_EPOLL_ET:
00386 #ifndef HAVE_EPOLL
00387 ret="epoll not supported, try re-compiling with -DHAVE_EPOLL";
00388 #else
00389
00390 if (os_ver<0x020542)
00391 ret="epoll not supported on kernels < 2.6";
00392 #endif
00393 break;
00394 case POLL_SIGIO_RT:
00395 #ifndef HAVE_SIGIO_RT
00396 ret="sigio_rt not supported, try re-compiling with"
00397 " -DHAVE_SIGIO_RT";
00398 #else
00399
00400 if (os_ver<0x020200)
00401 ret="epoll not supported on kernels < 2.2 (?)";
00402 #endif
00403 break;
00404 case POLL_KQUEUE:
00405 #ifndef HAVE_KQUEUE
00406 ret="kqueue not supported, try re-compiling with -DHAVE_KQUEUE";
00407 #else
00408
00409 #ifdef __OS_freebsd
00410 if (os_ver<0x0401)
00411 ret="kqueue not supported on FreeBSD < 4.1";
00412 #elif defined (__OS_netbsd)
00413 if (os_ver<0x020000)
00414 ret="kqueue not supported on NetBSD < 2.0";
00415 #elif defined (__OS_openbsd)
00416 if (os_ver<0x0209)
00417 ret="kqueue not supported on OpenBSD < 2.9 (?)";
00418 #endif
00419 #endif
00420 break;
00421 case POLL_DEVPOLL:
00422 #ifndef HAVE_DEVPOLL
00423 ret="/dev/poll not supported, try re-compiling with"
00424 " -DHAVE_DEVPOLL";
00425 #else
00426
00427 #ifdef __OS_solaris
00428 if (os_ver<0x0507)
00429 ret="/dev/poll not supported on Solaris < 7.0 (SunOS 5.7)";
00430 #endif
00431 #endif
00432 break;
00433
00434 default:
00435 ret="unknown not supported method";
00436 }
00437 return ret;
00438 }
00439
00440
00441
00442
00443
00444
00445 enum poll_types choose_poll_method(void)
00446 {
00447 enum poll_types poll_method;
00448 unsigned int os_ver;
00449
00450 os_ver=get_sys_version(0,0,0);
00451 poll_method=0;
00452 #ifdef HAVE_EPOLL
00453 if (os_ver>=0x020542)
00454 poll_method=POLL_EPOLL_LT;
00455
00456 #endif
00457 #ifdef HAVE_KQUEUE
00458 if (poll_method==0)
00459
00460 #ifdef __OS_freebsd
00461 if (os_ver>=0x0401)
00462 #elif defined (__OS_netbsd)
00463 if (os_ver>=0x020000)
00464 #elif defined (__OS_openbsd)
00465 if (os_ver>=0x0209)
00466 #endif
00467 poll_method=POLL_KQUEUE;
00468 #endif
00469 #ifdef HAVE_DEVPOLL
00470 #ifdef __OS_solaris
00471 if (poll_method==0)
00472
00473 if (os_ver>=0x0507)
00474 poll_method=POLL_DEVPOLL;
00475 #endif
00476 #endif
00477 #ifdef HAVE_SIGIO_RT
00478 if (poll_method==0)
00479 if (os_ver>=0x020200)
00480 poll_method=POLL_SIGIO_RT;
00481 #endif
00482 if (poll_method==0) poll_method=POLL_POLL;
00483 return poll_method;
00484 }
00485
00486
00487
00488
00489
00490
00491 char* poll_method_name(enum poll_types poll_method)
00492 {
00493 if ( poll_method<POLL_END )
00494 return poll_method_str[poll_method];
00495 else
00496 return "invalid poll method";
00497 }
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 enum poll_types get_poll_type(char* s)
00508 {
00509 int r;
00510 unsigned int l;
00511
00512 l=strlen(s);
00513 for (r=POLL_END-1; r>POLL_NONE; r--)
00514 if ((strlen(poll_method_str[r])==l) &&
00515 (strncasecmp(poll_method_str[r], s, l)==0))
00516 break;
00517 return r;
00518 }
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528 int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method)
00529 {
00530 char * poll_err;
00531
00532 memset(h, 0, sizeof(*h));
00533 h->max_fd_no=max_fd;
00534 #ifdef HAVE_EPOLL
00535 h->epfd=-1;
00536 #endif
00537 #ifdef HAVE_KQUEUE
00538 h->kq_fd=-1;
00539 #endif
00540 #ifdef HAVE_DEVPOLL
00541 h->dpoll_fd=-1;
00542 #endif
00543 poll_err=check_poll_method(poll_method);
00544
00545
00546 if (poll_err || (poll_method==0)){
00547 poll_method=choose_poll_method();
00548 if (poll_err){
00549 LM_ERR("%s, using %s instead\n",
00550 poll_err, poll_method_str[poll_method]);
00551 }else{
00552 LM_INFO("using %s as the io watch method"
00553 " (auto detected)\n", poll_method_str[poll_method]);
00554 }
00555 }
00556
00557 h->poll_method=poll_method;
00558
00559
00560 h->fd_hash=local_malloc(sizeof(*(h->fd_hash))*h->max_fd_no);
00561 if (h->fd_hash==0){
00562 LM_CRIT("could not alloc fd hashtable (%ld bytes)\n",
00563 (long)sizeof(*(h->fd_hash))*h->max_fd_no );
00564 goto error;
00565 }
00566 memset((void*)h->fd_hash, 0, sizeof(*(h->fd_hash))*h->max_fd_no);
00567
00568 switch(poll_method){
00569 case POLL_POLL:
00570 #ifdef HAVE_SELECT
00571 case POLL_SELECT:
00572 #endif
00573 #ifdef HAVE_SIGIO_RT
00574 case POLL_SIGIO_RT:
00575 #endif
00576 #ifdef HAVE_DEVPOLL
00577 case POLL_DEVPOLL:
00578 #endif
00579 h->fd_array=local_malloc(sizeof(*(h->fd_array))*h->max_fd_no);
00580 if (h->fd_array==0){
00581 LM_CRIT("could not alloc fd array (%ld bytes)\n",
00582 (long)sizeof(*(h->fd_hash))*h->max_fd_no);
00583 goto error;
00584 }
00585 memset((void*)h->fd_array, 0, sizeof(*(h->fd_array))*h->max_fd_no);
00586 #ifdef HAVE_SIGIO_RT
00587 if ((poll_method==POLL_SIGIO_RT) && (init_sigio(h, 0)<0)){
00588 LM_CRIT("sigio init failed\n");
00589 goto error;
00590 }
00591 #endif
00592 #ifdef HAVE_DEVPOLL
00593 if ((poll_method==POLL_DEVPOLL) && (init_devpoll(h)<0)){
00594 LM_CRIT("/dev/poll init failed\n");
00595 goto error;
00596 }
00597 #endif
00598 #ifdef HAVE_SELECT
00599 if ((poll_method==POLL_SELECT) && (init_select(h)<0)){
00600 LM_CRIT("select init failed\n");
00601 goto error;
00602 }
00603 #endif
00604
00605 break;
00606 #ifdef HAVE_EPOLL
00607 case POLL_EPOLL_LT:
00608 case POLL_EPOLL_ET:
00609 h->ep_array=local_malloc(sizeof(*(h->ep_array))*h->max_fd_no);
00610 if (h->ep_array==0){
00611 LM_CRIT("could not alloc epoll array\n");
00612 goto error;
00613 }
00614 memset((void*)h->ep_array, 0, sizeof(*(h->ep_array))*h->max_fd_no);
00615 if (init_epoll(h)<0){
00616 LM_CRIT("epoll init failed\n");
00617 goto error;
00618 }
00619 break;
00620 #endif
00621 #ifdef HAVE_KQUEUE
00622 case POLL_KQUEUE:
00623 h->kq_array=local_malloc(sizeof(*(h->kq_array))*h->max_fd_no);
00624 if (h->kq_array==0){
00625 LM_CRIT("could not alloc kqueue event array\n");
00626 goto error;
00627 }
00628 h->kq_changes_size=KQ_CHANGES_ARRAY_SIZE;
00629 h->kq_changes=local_malloc(sizeof(*(h->kq_changes))*
00630 h->kq_changes_size);
00631 if (h->kq_changes==0){
00632 LM_CRIT("could not alloc kqueue changes array\n");
00633 goto error;
00634 }
00635 h->kq_nchanges=0;
00636 memset((void*)h->kq_array, 0, sizeof(*(h->kq_array))*h->max_fd_no);
00637 memset((void*)h->kq_changes, 0,
00638 sizeof(*(h->kq_changes))* h->kq_changes_size);
00639 if (init_kqueue(h)<0){
00640 LM_CRIT("kqueue init failed\n");
00641 goto error;
00642 }
00643 break;
00644 #endif
00645 default:
00646 LM_CRIT("unknown/unsupported poll method %s (%d)\n",
00647 poll_method_str[poll_method], poll_method);
00648 goto error;
00649 }
00650 return 0;
00651 error:
00652 return -1;
00653 }
00654
00655
00656
00657
00658
00659
00660
00661 void destroy_io_wait(io_wait_h* h)
00662 {
00663 switch(h->poll_method){
00664 #ifdef HAVE_EPOLL
00665 case POLL_EPOLL_LT:
00666 case POLL_EPOLL_ET:
00667 destroy_epoll(h);
00668 if (h->ep_array){
00669 local_free(h->ep_array);
00670 h->ep_array=0;
00671 }
00672 break;
00673 #endif
00674 #ifdef HAVE_KQUEUE
00675 case POLL_KQUEUE:
00676 destroy_kqueue(h);
00677 if (h->kq_array){
00678 local_free(h->kq_array);
00679 h->kq_array=0;
00680 }
00681 if (h->kq_changes){
00682 local_free(h->kq_changes);
00683 h->kq_changes=0;
00684 }
00685 break;
00686 #endif
00687 #ifdef HAVE_SIGIO_RT
00688 case POLL_SIGIO_RT:
00689 destroy_sigio(h);
00690 break;
00691 #endif
00692 #ifdef HAVE_DEVPOLL
00693 case POLL_DEVPOLL:
00694 destroy_devpoll(h);
00695 break;
00696 #endif
00697 default:
00698 ;
00699 }
00700 if (h->fd_array){
00701 local_free(h->fd_array);
00702 h->fd_array=0;
00703 }
00704 if (h->fd_hash){
00705 local_free(h->fd_hash);
00706 h->fd_hash=0;
00707 }
00708 }
00709
00710
00711 #endif