/src/libev/ev_select.c

http://github.com/jacksonh/manos · C · 307 lines · 208 code · 44 blank · 55 comment · 37 complexity · 16463f0018b1196f37c1c8cd96ae39c4 MD5 · raw file

  1. /*
  2. * libev select fd activity backend
  3. *
  4. * Copyright (c) 2007,2008,2009,2010 Marc Alexander Lehmann <libev@schmorp.de>
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without modifica-
  8. * tion, are permitted provided that the following conditions are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright notice,
  11. * this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  18. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
  19. * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
  20. * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
  21. * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  22. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  23. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  24. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
  25. * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  26. * OF THE POSSIBILITY OF SUCH DAMAGE.
  27. *
  28. * Alternatively, the contents of this file may be used under the terms of
  29. * the GNU General Public License ("GPL") version 2 or any later version,
  30. * in which case the provisions of the GPL are applicable instead of
  31. * the above. If you wish to allow the use of your version of this file
  32. * only under the terms of the GPL and not to allow others to use your
  33. * version of this file under the BSD license, indicate your decision
  34. * by deleting the provisions above and replace them with the notice
  35. * and other provisions required by the GPL. If you do not delete the
  36. * provisions above, a recipient may use your version of this file under
  37. * either the BSD or the GPL.
  38. */
  39. #ifndef _WIN32
  40. /* for unix systems */
  41. # include <sys/select.h>
  42. # include <inttypes.h>
  43. #endif
  44. #ifndef EV_SELECT_USE_FD_SET
  45. # ifdef NFDBITS
  46. # define EV_SELECT_USE_FD_SET 0
  47. # else
  48. # define EV_SELECT_USE_FD_SET 1
  49. # endif
  50. #endif
  51. #if EV_SELECT_IS_WINSOCKET
  52. # undef EV_SELECT_USE_FD_SET
  53. # define EV_SELECT_USE_FD_SET 1
  54. # undef NFDBITS
  55. # define NFDBITS 0
  56. #endif
  57. #if !EV_SELECT_USE_FD_SET
  58. # define NFDBYTES (NFDBITS / 8)
  59. #endif
  60. #include <string.h>
  61. static void
  62. select_modify (EV_P_ int fd, int oev, int nev)
  63. {
  64. if (oev == nev)
  65. return;
  66. {
  67. #if EV_SELECT_USE_FD_SET
  68. #if EV_SELECT_IS_WINSOCKET
  69. SOCKET handle = anfds [fd].handle;
  70. #else
  71. int handle = fd;
  72. #endif
  73. assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE));
  74. /* FD_SET is broken on windows (it adds the fd to a set twice or more,
  75. * which eventually leads to overflows). Need to call it only on changes.
  76. */
  77. #if EV_SELECT_IS_WINSOCKET
  78. if ((oev ^ nev) & EV_READ)
  79. #endif
  80. if (nev & EV_READ)
  81. FD_SET (handle, (fd_set *)vec_ri);
  82. else
  83. FD_CLR (handle, (fd_set *)vec_ri);
  84. #if EV_SELECT_IS_WINSOCKET
  85. if ((oev ^ nev) & EV_WRITE)
  86. #endif
  87. if (nev & EV_WRITE)
  88. FD_SET (handle, (fd_set *)vec_wi);
  89. else
  90. FD_CLR (handle, (fd_set *)vec_wi);
  91. #else
  92. int word = fd / NFDBITS;
  93. fd_mask mask = 1UL << (fd % NFDBITS);
  94. if (expect_false (vec_max <= word))
  95. {
  96. int new_max = word + 1;
  97. vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES);
  98. vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */
  99. vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES);
  100. vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */
  101. #ifdef _WIN32
  102. vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */
  103. #endif
  104. for (; vec_max < new_max; ++vec_max)
  105. ((fd_mask *)vec_ri) [vec_max] =
  106. ((fd_mask *)vec_wi) [vec_max] = 0;
  107. }
  108. ((fd_mask *)vec_ri) [word] |= mask;
  109. if (!(nev & EV_READ))
  110. ((fd_mask *)vec_ri) [word] &= ~mask;
  111. ((fd_mask *)vec_wi) [word] |= mask;
  112. if (!(nev & EV_WRITE))
  113. ((fd_mask *)vec_wi) [word] &= ~mask;
  114. #endif
  115. }
  116. }
  117. static void
  118. select_poll (EV_P_ ev_tstamp timeout)
  119. {
  120. struct timeval tv;
  121. int res;
  122. int fd_setsize;
  123. EV_RELEASE_CB;
  124. EV_TV_SET (tv, timeout);
  125. #if EV_SELECT_USE_FD_SET
  126. fd_setsize = sizeof (fd_set);
  127. #else
  128. fd_setsize = vec_max * NFDBYTES;
  129. #endif
  130. memcpy (vec_ro, vec_ri, fd_setsize);
  131. memcpy (vec_wo, vec_wi, fd_setsize);
  132. #ifdef _WIN32
  133. /* pass in the write set as except set.
  134. * the idea behind this is to work around a windows bug that causes
  135. * errors to be reported as an exception and not by setting
  136. * the writable bit. this is so uncontrollably lame.
  137. */
  138. memcpy (vec_eo, vec_wi, fd_setsize);
  139. res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv);
  140. #elif EV_SELECT_USE_FD_SET
  141. fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE;
  142. res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
  143. #else
  144. res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
  145. #endif
  146. EV_ACQUIRE_CB;
  147. if (expect_false (res < 0))
  148. {
  149. #if EV_SELECT_IS_WINSOCKET
  150. errno = WSAGetLastError ();
  151. #endif
  152. #ifdef WSABASEERR
  153. /* on windows, select returns incompatible error codes, fix this */
  154. if (errno >= WSABASEERR && errno < WSABASEERR + 1000)
  155. if (errno == WSAENOTSOCK)
  156. errno = EBADF;
  157. else
  158. errno -= WSABASEERR;
  159. #endif
  160. #ifdef _WIN32
  161. /* select on windows erroneously returns EINVAL when no fd sets have been
  162. * provided (this is documented). what microsoft doesn't tell you that this bug
  163. * exists even when the fd sets _are_ provided, so we have to check for this bug
  164. * here and emulate by sleeping manually.
  165. * we also get EINVAL when the timeout is invalid, but we ignore this case here
  166. * and assume that EINVAL always means: you have to wait manually.
  167. */
  168. if (errno == EINVAL)
  169. {
  170. ev_sleep (timeout);
  171. return;
  172. }
  173. #endif
  174. if (errno == EBADF)
  175. fd_ebadf (EV_A);
  176. else if (errno == ENOMEM && !syserr_cb)
  177. fd_enomem (EV_A);
  178. else if (errno != EINTR)
  179. ev_syserr ("(libev) select");
  180. return;
  181. }
  182. #if EV_SELECT_USE_FD_SET
  183. {
  184. int fd;
  185. for (fd = 0; fd < anfdmax; ++fd)
  186. if (anfds [fd].events)
  187. {
  188. int events = 0;
  189. #if EV_SELECT_IS_WINSOCKET
  190. SOCKET handle = anfds [fd].handle;
  191. #else
  192. int handle = fd;
  193. #endif
  194. if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ;
  195. if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE;
  196. #ifdef _WIN32
  197. if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE;
  198. #endif
  199. if (expect_true (events))
  200. fd_event (EV_A_ fd, events);
  201. }
  202. }
  203. #else
  204. {
  205. int word, bit;
  206. for (word = vec_max; word--; )
  207. {
  208. fd_mask word_r = ((fd_mask *)vec_ro) [word];
  209. fd_mask word_w = ((fd_mask *)vec_wo) [word];
  210. #ifdef _WIN32
  211. word_w |= ((fd_mask *)vec_eo) [word];
  212. #endif
  213. if (word_r || word_w)
  214. for (bit = NFDBITS; bit--; )
  215. {
  216. fd_mask mask = 1UL << bit;
  217. int events = 0;
  218. events |= word_r & mask ? EV_READ : 0;
  219. events |= word_w & mask ? EV_WRITE : 0;
  220. if (expect_true (events))
  221. fd_event (EV_A_ word * NFDBITS + bit, events);
  222. }
  223. }
  224. }
  225. #endif
  226. }
  227. int inline_size
  228. select_init (EV_P_ int flags)
  229. {
  230. backend_fudge = 0.; /* posix says this is zero */
  231. backend_modify = select_modify;
  232. backend_poll = select_poll;
  233. #if EV_SELECT_USE_FD_SET
  234. vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri);
  235. vec_ro = ev_malloc (sizeof (fd_set));
  236. vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi);
  237. vec_wo = ev_malloc (sizeof (fd_set));
  238. #ifdef _WIN32
  239. vec_eo = ev_malloc (sizeof (fd_set));
  240. #endif
  241. #else
  242. vec_max = 0;
  243. vec_ri = 0;
  244. vec_ro = 0;
  245. vec_wi = 0;
  246. vec_wo = 0;
  247. #ifdef _WIN32
  248. vec_eo = 0;
  249. #endif
  250. #endif
  251. return EVBACKEND_SELECT;
  252. }
  253. void inline_size
  254. select_destroy (EV_P)
  255. {
  256. ev_free (vec_ri);
  257. ev_free (vec_ro);
  258. ev_free (vec_wi);
  259. ev_free (vec_wo);
  260. #ifdef _WIN32
  261. ev_free (vec_eo);
  262. #endif
  263. }