io_wait.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2005 iptelorg GmbH
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. /*
  19. * tcp io wait common stuff used by tcp_main.c & tcp_read.c
  20. * (see io_wait.h)
  21. */
  22. /*
  23. * History:
  24. * --------
  25. * 2005-06-15 created by andrei
  26. * 2005-06-26 added kqueue (andrei)
  27. * 2005-07-04 added /dev/poll (andrei)
  28. */
  29. #ifndef NO_IO_WAIT
  30. #ifdef HAVE_EPOLL
  31. #include <unistd.h> /* close() */
  32. #endif
  33. #ifdef HAVE_DEVPOLL
  34. #include <sys/types.h> /* open */
  35. #include <sys/stat.h>
  36. #include <fcntl.h>
  37. #include <unistd.h> /* close, ioctl */
  38. #endif
  39. #include <stdlib.h> /* strtol() */
  40. #include "io_wait.h"
  41. #include "ut.h" /* get_sys_ver() */
  42. #include "mem/mem.h"
  43. #ifndef local_malloc
  44. #define local_malloc pkg_malloc
  45. #endif
  46. #ifndef local_free
  47. #define local_free pkg_free
  48. #endif
  49. char* poll_support="poll"
  50. #ifdef HAVE_EPOLL
  51. ", epoll_lt, epoll_et"
  52. #endif
  53. #ifdef HAVE_SIGIO_RT
  54. ", sigio_rt"
  55. #endif
  56. #ifdef HAVE_SELECT
  57. ", select"
  58. #endif
  59. #ifdef HAVE_KQUEUE
  60. ", kqueue"
  61. #endif
  62. #ifdef HAVE_DEVPOLL
  63. ", /dev/poll"
  64. #endif
  65. ;
  66. char* poll_method_str[POLL_END]={ "none", "poll", "epoll_lt", "epoll_et",
  67. "sigio_rt", "select", "kqueue", "/dev/poll"
  68. };
  69. int _os_ver=0; /* os version number */
  70. #ifdef HAVE_SIGIO_RT
  71. static int _sigio_init=0;
  72. static int _sigio_crt_rtsig;
  73. static sigset_t _sigio_rtsig_used;
  74. #endif
  75. #ifdef HAVE_SIGIO_RT
  76. /* sigio specific init
  77. * returns -1 on error, 0 on success */
  78. static int init_sigio(io_wait_h* h, int rsig)
  79. {
  80. int r;
  81. int n;
  82. int signo;
  83. int start_sig;
  84. sigset_t oldset;
  85. if (!_sigio_init){
  86. _sigio_init=1;
  87. _sigio_crt_rtsig=SIGRTMIN;
  88. sigemptyset(&_sigio_rtsig_used);
  89. }
  90. h->signo=0;
  91. if (rsig==0){
  92. start_sig=_sigio_crt_rtsig;
  93. n=SIGRTMAX-SIGRTMIN;
  94. }else{
  95. if ((rsig < SIGRTMIN) || (rsig >SIGRTMAX)){
  96. LOG(L_CRIT, "ERROR: init_sigio: real time signal %d out of"
  97. " range [%d, %d]\n", rsig, SIGRTMIN, SIGRTMAX);
  98. goto error;
  99. }
  100. start_sig=rsig;
  101. n=0;
  102. }
  103. sigemptyset(&h->sset);
  104. sigemptyset(&oldset);
  105. retry1:
  106. /* get current block mask */
  107. if (sigprocmask(SIG_BLOCK, &h->sset, &oldset )==-1){
  108. if (errno==EINTR) goto retry1;
  109. LOG(L_ERR, "ERROR: init_sigio: 1st sigprocmask failed: %s [%d]\n",
  110. strerror(errno), errno);
  111. /* try to continue */
  112. }
  113. for (r=start_sig; r<=(n+start_sig); r++){
  114. signo=(r>SIGRTMAX)?r-SIGRTMAX+SIGRTMIN:r;
  115. if (! sigismember(&_sigio_rtsig_used, signo) &&
  116. ! sigismember(&oldset, signo)){
  117. sigaddset(&_sigio_rtsig_used, signo);
  118. h->signo=signo;
  119. _sigio_crt_rtsig=(signo<SIGRTMAX)?signo+1:SIGRTMIN;
  120. break;
  121. }
  122. }
  123. if (h->signo==0){
  124. LOG(L_CRIT, "ERROR: init_sigio: %s\n",
  125. rsig?"could not assign requested real-time signal":
  126. "out of real-time signals");
  127. goto error;
  128. }
  129. DBG("init_sigio: trying signal %d... \n", h->signo);
  130. if (sigaddset(&h->sset, h->signo)==-1){
  131. LOG(L_ERR, "ERROR: init_sigio: sigaddset failed for %d: %s [%d]\n",
  132. h->signo, strerror(errno), errno);
  133. goto error;
  134. }
  135. if (sigaddset(&h->sset, SIGIO)==-1){
  136. LOG(L_ERR, "ERROR: init_sigio: sigaddset failed for %d: %s [%d]\n",
  137. SIGIO, strerror(errno), errno);
  138. goto error;
  139. }
  140. retry:
  141. if (sigprocmask(SIG_BLOCK, &h->sset, 0)==-1){
  142. if (errno==EINTR) goto retry;
  143. LOG(L_ERR, "ERROR: init_sigio: sigprocmask failed: %s [%d]\n",
  144. strerror(errno), errno);
  145. goto error;
  146. }
  147. return 0;
  148. error:
  149. h->signo=0;
  150. sigemptyset(&h->sset);
  151. return -1;
  152. }
  153. /* sigio specific destroy */
  154. static void destroy_sigio(io_wait_h* h)
  155. {
  156. if (h->signo){
  157. sigprocmask(SIG_UNBLOCK, &h->sset, 0);
  158. sigemptyset(&h->sset);
  159. sigdelset(&_sigio_rtsig_used, h->signo);
  160. h->signo=0;
  161. }
  162. }
  163. #endif
  164. #ifdef HAVE_EPOLL
  165. /* epoll specific init
  166. * returns -1 on error, 0 on success */
  167. static int init_epoll(io_wait_h* h)
  168. {
  169. again:
  170. h->epfd=epoll_create(h->max_fd_no);
  171. if (h->epfd==-1){
  172. if (errno==EINTR) goto again;
  173. LOG(L_ERR, "ERROR: init_epoll: epoll_create: %s [%d]\n",
  174. strerror(errno), errno);
  175. return -1;
  176. }
  177. return 0;
  178. }
  179. static void destroy_epoll(io_wait_h* h)
  180. {
  181. if (h->epfd!=-1){
  182. close(h->epfd);
  183. h->epfd=-1;
  184. }
  185. }
  186. #endif
  187. #ifdef HAVE_KQUEUE
  188. /* kqueue specific init
  189. * returns -1 on error, 0 on success */
  190. static int init_kqueue(io_wait_h* h)
  191. {
  192. again:
  193. h->kq_fd=kqueue();
  194. if (h->kq_fd==-1){
  195. if (errno==EINTR) goto again;
  196. LOG(L_ERR, "ERROR: init_kqueue: kqueue: %s [%d]\n",
  197. strerror(errno), errno);
  198. return -1;
  199. }
  200. return 0;
  201. }
  202. static void destroy_kqueue(io_wait_h* h)
  203. {
  204. if (h->kq_fd!=-1){
  205. close(h->kq_fd);
  206. h->kq_fd=-1;
  207. }
  208. }
  209. #endif
  210. #ifdef HAVE_DEVPOLL
  211. /* /dev/poll specific init
  212. * returns -1 on error, 0 on success */
  213. static int init_devpoll(io_wait_h* h)
  214. {
  215. again:
  216. h->dpoll_fd=open("/dev/poll", O_RDWR);
  217. if (h->dpoll_fd==-1){
  218. if (errno==EINTR) goto again;
  219. LOG(L_ERR, "ERROR: init_/dev/poll: open: %s [%d]\n",
  220. strerror(errno), errno);
  221. return -1;
  222. }
  223. return 0;
  224. }
  225. static void destroy_devpoll(io_wait_h* h)
  226. {
  227. if (h->dpoll_fd!=-1){
  228. close(h->dpoll_fd);
  229. h->dpoll_fd=-1;
  230. }
  231. }
  232. #endif
  233. #ifdef HAVE_SELECT
  234. static int init_select(io_wait_h* h)
  235. {
  236. FD_ZERO(&h->master_rset);
  237. FD_ZERO(&h->master_wset);
  238. return 0;
  239. }
  240. #endif
  241. /*
  242. * returns 0 on success, and an error message on error
  243. */
  244. char* check_poll_method(enum poll_types poll_method)
  245. {
  246. char* ret;
  247. ret=0;
  248. if (_os_ver==0)
  249. _os_ver=get_sys_version(0,0,0);
  250. switch(poll_method){
  251. case POLL_NONE:
  252. break;
  253. case POLL_POLL:
  254. /* always supported */
  255. break;
  256. case POLL_SELECT:
  257. /* should be always supported */
  258. #ifndef HAVE_SELECT
  259. ret="select not supported, try re-compiling with -DHAVE_SELECT";
  260. #endif
  261. break;
  262. case POLL_EPOLL_LT:
  263. case POLL_EPOLL_ET:
  264. #ifndef HAVE_EPOLL
  265. ret="epoll not supported, try re-compiling with -DHAVE_EPOLL";
  266. #else
  267. /* only on 2.6 + */
  268. if (_os_ver<0x020542) /* if ver < 2.5.66 */
  269. ret="epoll not supported on kernels < 2.6";
  270. #endif
  271. break;
  272. case POLL_SIGIO_RT:
  273. #ifndef HAVE_SIGIO_RT
  274. ret="sigio_rt not supported, try re-compiling with"
  275. " -DHAVE_SIGIO_RT";
  276. #else
  277. /* only on 2.2 + ?? */
  278. if (_os_ver<0x020200) /* if ver < 2.2.0 */
  279. ret="epoll not supported on kernels < 2.2 (?)";
  280. #endif
  281. break;
  282. case POLL_KQUEUE:
  283. #ifndef HAVE_KQUEUE
  284. ret="kqueue not supported, try re-compiling with -DHAVE_KQUEUE";
  285. #else
  286. /* only in FreeBSD 4.1, NETBSD 2.0, OpenBSD 2.9, Darwin */
  287. #ifdef __OS_freebsd
  288. if (_os_ver<0x0401) /* if ver < 4.1 */
  289. ret="kqueue not supported on FreeBSD < 4.1";
  290. #elif defined (__OS_netbsd)
  291. if (_os_ver<0x020000) /* if ver < 2.0 */
  292. ret="kqueue not supported on NetBSD < 2.0";
  293. #elif defined (__OS_openbsd)
  294. if (_os_ver<0x0209) /* if ver < 2.9 ? */
  295. ret="kqueue not supported on OpenBSD < 2.9 (?)";
  296. #endif /* assume that the rest support kqueue ifdef HAVE_KQUEUE */
  297. #endif
  298. break;
  299. case POLL_DEVPOLL:
  300. #ifndef HAVE_DEVPOLL
  301. ret="/dev/poll not supported, try re-compiling with"
  302. " -DHAVE_DEVPOLL";
  303. #else
  304. /* only in Solaris >= 7.0 (?) */
  305. #ifdef __OS_solaris
  306. if (_os_ver<0x0507) /* ver < 5.7 */
  307. ret="/dev/poll not supported on Solaris < 7.0 (SunOS 5.7)";
  308. #endif
  309. #endif
  310. break;
  311. default:
  312. ret="unknown not supported method";
  313. }
  314. return ret;
  315. }
  316. enum poll_types choose_poll_method()
  317. {
  318. enum poll_types poll_method;
  319. if (_os_ver==0)
  320. _os_ver=get_sys_version(0,0,0);
  321. poll_method=0;
  322. #ifdef HAVE_EPOLL
  323. if (_os_ver>=0x020542) /* if ver >= 2.5.66 */
  324. poll_method=POLL_EPOLL_LT; /* or POLL_EPOLL_ET */
  325. #endif
  326. #ifdef HAVE_KQUEUE
  327. if (poll_method==0)
  328. /* only in FreeBSD 4.1, NETBSD 2.0, OpenBSD 2.9, Darwin */
  329. #ifdef __OS_freebsd
  330. if (_os_ver>=0x0401) /* if ver >= 4.1 */
  331. #elif defined (__OS_netbsd)
  332. if (_os_ver>=0x020000) /* if ver >= 2.0 */
  333. #elif defined (__OS_openbsd)
  334. if (_os_ver>=0x0209) /* if ver >= 2.9 (?) */
  335. #endif /* assume that the rest support kqueue ifdef HAVE_KQUEUE */
  336. poll_method=POLL_KQUEUE;
  337. #endif
  338. #ifdef HAVE_DEVPOLL
  339. #ifdef __OS_solaris
  340. if (poll_method==0)
  341. /* only in Solaris >= 7.0 (?) */
  342. if (_os_ver>=0x0507) /* if ver >=SunOS 5.7 */
  343. poll_method=POLL_DEVPOLL;
  344. #endif
  345. #endif
  346. #ifdef HAVE_SIGIO_RT
  347. if (poll_method==0)
  348. if (_os_ver>=0x020200) /* if ver >= 2.2.0 */
  349. poll_method=POLL_SIGIO_RT;
  350. #endif
  351. if (poll_method==0) poll_method=POLL_POLL;
  352. return poll_method;
  353. }
  354. char* poll_method_name(enum poll_types poll_method)
  355. {
  356. if ((poll_method>=POLL_NONE) && (poll_method<POLL_END))
  357. return poll_method_str[poll_method];
  358. else
  359. return "invalid poll method";
  360. }
  361. /* converts a string into a poll_method
  362. * returns POLL_NONE (0) on error, else the corresponding poll type */
  363. enum poll_types get_poll_type(char* s)
  364. {
  365. int r;
  366. int l;
  367. l=strlen(s);
  368. for (r=POLL_END-1; r>POLL_NONE; r--)
  369. if ((strlen(poll_method_str[r])==l) &&
  370. (strncasecmp(poll_method_str[r], s, l)==0))
  371. break;
  372. return r;
  373. }
  374. /* initializes the static vars/arrays
  375. * params: h - pointer to the io_wait_h that will be initialized
  376. * max_fd - maximum allowed fd number
  377. * poll_m - poll method (0 for automatic best fit)
  378. */
  379. int init_io_wait(io_wait_h* h, int max_fd, enum poll_types poll_method)
  380. {
  381. char * poll_err;
  382. if (_os_ver==0) _os_ver=get_sys_version(0,0,0);
  383. memset(h, 0, sizeof(*h));
  384. h->max_fd_no=max_fd;
  385. #ifdef HAVE_EPOLL
  386. h->epfd=-1;
  387. #endif
  388. #ifdef HAVE_KQUEUE
  389. h->kq_fd=-1;
  390. #endif
  391. #ifdef HAVE_DEVPOLL
  392. h->dpoll_fd=-1;
  393. #endif
  394. poll_err=check_poll_method(poll_method);
  395. /* set an appropiate poll method */
  396. if (poll_err || (poll_method==0)){
  397. poll_method=choose_poll_method();
  398. if (poll_err){
  399. LOG(L_ERR, "ERROR: init_io_wait: %s, using %s instead\n",
  400. poll_err, poll_method_str[poll_method]);
  401. }else{
  402. LOG(L_INFO, "init_io_wait: using %s as the io watch method"
  403. " (auto detected)\n", poll_method_str[poll_method]);
  404. }
  405. }
  406. h->poll_method=poll_method;
  407. /* common stuff, everybody has fd_hash */
  408. h->fd_hash=local_malloc(sizeof(*(h->fd_hash))*h->max_fd_no);
  409. if (h->fd_hash==0){
  410. LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
  411. " fd hashtable (%ld bytes)\n",
  412. (long)sizeof(*(h->fd_hash))*h->max_fd_no );
  413. goto error;
  414. }
  415. memset((void*)h->fd_hash, 0, sizeof(*(h->fd_hash))*h->max_fd_no);
  416. switch(poll_method){
  417. case POLL_POLL:
  418. #ifdef HAVE_SELECT
  419. case POLL_SELECT:
  420. #endif
  421. #ifdef HAVE_SIGIO_RT
  422. case POLL_SIGIO_RT:
  423. #endif
  424. #ifdef HAVE_DEVPOLL
  425. case POLL_DEVPOLL:
  426. #endif
  427. h->fd_array=local_malloc(sizeof(*(h->fd_array))*h->max_fd_no);
  428. if (h->fd_array==0){
  429. LOG(L_CRIT, "ERROR: init_io_wait: could not"
  430. " alloc fd array (%ld bytes)\n",
  431. (long)sizeof(*(h->fd_hash))*h->max_fd_no);
  432. goto error;
  433. }
  434. memset((void*)h->fd_array, 0, sizeof(*(h->fd_array))*h->max_fd_no);
  435. #ifdef HAVE_SIGIO_RT
  436. if ((poll_method==POLL_SIGIO_RT) && (init_sigio(h, 0)<0)){
  437. LOG(L_CRIT, "ERROR: init_io_wait: sigio init failed\n");
  438. goto error;
  439. }
  440. #endif
  441. #ifdef HAVE_DEVPOLL
  442. if ((poll_method==POLL_DEVPOLL) && (init_devpoll(h)<0)){
  443. LOG(L_CRIT, "ERROR: init_io_wait: /dev/poll init failed\n");
  444. goto error;
  445. }
  446. #endif
  447. #ifdef HAVE_SELECT
  448. if ((poll_method==POLL_SELECT) && (init_select(h)<0)){
  449. LOG(L_CRIT, "ERROR: init_io_wait: select init failed\n");
  450. goto error;
  451. }
  452. #endif
  453. break;
  454. #ifdef HAVE_EPOLL
  455. case POLL_EPOLL_LT:
  456. case POLL_EPOLL_ET:
  457. h->ep_array=local_malloc(sizeof(*(h->ep_array))*h->max_fd_no);
  458. if (h->ep_array==0){
  459. LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
  460. " epoll array\n");
  461. goto error;
  462. }
  463. memset((void*)h->ep_array, 0, sizeof(*(h->ep_array))*h->max_fd_no);
  464. if (init_epoll(h)<0){
  465. LOG(L_CRIT, "ERROR: init_io_wait: epoll init failed\n");
  466. goto error;
  467. }
  468. break;
  469. #endif
  470. #ifdef HAVE_KQUEUE
  471. case POLL_KQUEUE:
  472. h->kq_array=local_malloc(sizeof(*(h->kq_array))*h->max_fd_no);
  473. if (h->kq_array==0){
  474. LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
  475. " kqueue event array\n");
  476. goto error;
  477. }
  478. h->kq_changes_size=KQ_CHANGES_ARRAY_SIZE;
  479. h->kq_changes=local_malloc(sizeof(*(h->kq_changes))*
  480. h->kq_changes_size);
  481. if (h->kq_changes==0){
  482. LOG(L_CRIT, "ERROR: init_io_wait: could not alloc"
  483. " kqueue changes array\n");
  484. goto error;
  485. }
  486. h->kq_nchanges=0;
  487. memset((void*)h->kq_array, 0, sizeof(*(h->kq_array))*h->max_fd_no);
  488. memset((void*)h->kq_changes, 0,
  489. sizeof(*(h->kq_changes))* h->kq_changes_size);
  490. if (init_kqueue(h)<0){
  491. LOG(L_CRIT, "ERROR: init_io_wait: kqueue init failed\n");
  492. goto error;
  493. }
  494. break;
  495. #endif
  496. default:
  497. LOG(L_CRIT, "BUG: init_io_wait: unknown/unsupported poll"
  498. " method %s (%d)\n",
  499. poll_method_str[poll_method], poll_method);
  500. goto error;
  501. }
  502. return 0;
  503. error:
  504. return -1;
  505. }
  506. /* destroys everything init_io_wait allocated */
  507. void destroy_io_wait(io_wait_h* h)
  508. {
  509. switch(h->poll_method){
  510. #ifdef HAVE_EPOLL
  511. case POLL_EPOLL_LT:
  512. case POLL_EPOLL_ET:
  513. destroy_epoll(h);
  514. if (h->ep_array){
  515. local_free(h->ep_array);
  516. h->ep_array=0;
  517. }
  518. break;
  519. #endif
  520. #ifdef HAVE_KQUEUE
  521. case POLL_KQUEUE:
  522. destroy_kqueue(h);
  523. if (h->kq_array){
  524. local_free(h->kq_array);
  525. h->kq_array=0;
  526. }
  527. if (h->kq_changes){
  528. local_free(h->kq_changes);
  529. h->kq_changes=0;
  530. }
  531. break;
  532. #endif
  533. #ifdef HAVE_SIGIO_RT
  534. case POLL_SIGIO_RT:
  535. destroy_sigio(h);
  536. break;
  537. #endif
  538. #ifdef HAVE_DEVPOLL
  539. case POLL_DEVPOLL:
  540. destroy_devpoll(h);
  541. break;
  542. #endif
  543. default: /*do nothing*/
  544. ;
  545. }
  546. if (h->fd_array){
  547. local_free(h->fd_array);
  548. h->fd_array=0;
  549. }
  550. if (h->fd_hash){
  551. local_free(h->fd_hash);
  552. h->fd_hash=0;
  553. }
  554. }
  555. #endif /*ifndef NO_IO_WAIT */