You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

314 lines
8.6 KiB

11 years ago
  1. /*
  2. * libev select fd activity backend
  3. *
  4. * Copyright (c) 2007,2008,2009,2010,2011 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 <inttypes.h>
  42. # ifndef __hpux
  43. /* for REAL unix systems */
  44. # include <sys/select.h>
  45. # endif
  46. #endif
  47. #ifndef EV_SELECT_USE_FD_SET
  48. # ifdef NFDBITS
  49. # define EV_SELECT_USE_FD_SET 0
  50. # else
  51. # define EV_SELECT_USE_FD_SET 1
  52. # endif
  53. #endif
  54. #if EV_SELECT_IS_WINSOCKET
  55. # undef EV_SELECT_USE_FD_SET
  56. # define EV_SELECT_USE_FD_SET 1
  57. # undef NFDBITS
  58. # define NFDBITS 0
  59. #endif
  60. #if !EV_SELECT_USE_FD_SET
  61. # define NFDBYTES (NFDBITS / 8)
  62. #endif
  63. #include <string.h>
  64. static void
  65. select_modify (EV_P_ int fd, int oev, int nev)
  66. {
  67. if (oev == nev)
  68. return;
  69. {
  70. #if EV_SELECT_USE_FD_SET
  71. #if EV_SELECT_IS_WINSOCKET
  72. SOCKET handle = anfds [fd].handle;
  73. #else
  74. int handle = fd;
  75. #endif
  76. assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE));
  77. /* FD_SET is broken on windows (it adds the fd to a set twice or more,
  78. * which eventually leads to overflows). Need to call it only on changes.
  79. */
  80. #if EV_SELECT_IS_WINSOCKET
  81. if ((oev ^ nev) & EV_READ)
  82. #endif
  83. if (nev & EV_READ)
  84. FD_SET (handle, (fd_set *)vec_ri);
  85. else
  86. FD_CLR (handle, (fd_set *)vec_ri);
  87. #if EV_SELECT_IS_WINSOCKET
  88. if ((oev ^ nev) & EV_WRITE)
  89. #endif
  90. if (nev & EV_WRITE)
  91. FD_SET (handle, (fd_set *)vec_wi);
  92. else
  93. FD_CLR (handle, (fd_set *)vec_wi);
  94. #else
  95. int word = fd / NFDBITS;
  96. fd_mask mask = 1UL << (fd % NFDBITS);
  97. if (expect_false (vec_max <= word))
  98. {
  99. int new_max = word + 1;
  100. vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES);
  101. vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */
  102. vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES);
  103. vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */
  104. #ifdef _WIN32
  105. vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */
  106. #endif
  107. for (; vec_max < new_max; ++vec_max)
  108. ((fd_mask *)vec_ri) [vec_max] =
  109. ((fd_mask *)vec_wi) [vec_max] = 0;
  110. }
  111. ((fd_mask *)vec_ri) [word] |= mask;
  112. if (!(nev & EV_READ))
  113. ((fd_mask *)vec_ri) [word] &= ~mask;
  114. ((fd_mask *)vec_wi) [word] |= mask;
  115. if (!(nev & EV_WRITE))
  116. ((fd_mask *)vec_wi) [word] &= ~mask;
  117. #endif
  118. }
  119. }
  120. static void
  121. select_poll (EV_P_ ev_tstamp timeout)
  122. {
  123. struct timeval tv;
  124. int res;
  125. int fd_setsize;
  126. EV_RELEASE_CB;
  127. EV_TV_SET (tv, timeout);
  128. #if EV_SELECT_USE_FD_SET
  129. fd_setsize = sizeof (fd_set);
  130. #else
  131. fd_setsize = vec_max * NFDBYTES;
  132. #endif
  133. memcpy (vec_ro, vec_ri, fd_setsize);
  134. memcpy (vec_wo, vec_wi, fd_setsize);
  135. #ifdef _WIN32
  136. /* pass in the write set as except set.
  137. * the idea behind this is to work around a windows bug that causes
  138. * errors to be reported as an exception and not by setting
  139. * the writable bit. this is so uncontrollably lame.
  140. */
  141. memcpy (vec_eo, vec_wi, fd_setsize);
  142. res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv);
  143. #elif EV_SELECT_USE_FD_SET
  144. fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE;
  145. res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
  146. #else
  147. res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
  148. #endif
  149. EV_ACQUIRE_CB;
  150. if (expect_false (res < 0))
  151. {
  152. #if EV_SELECT_IS_WINSOCKET
  153. errno = WSAGetLastError ();
  154. #endif
  155. #ifdef WSABASEERR
  156. /* on windows, select returns incompatible error codes, fix this */
  157. if (errno >= WSABASEERR && errno < WSABASEERR + 1000)
  158. if (errno == WSAENOTSOCK)
  159. errno = EBADF;
  160. else
  161. errno -= WSABASEERR;
  162. #endif
  163. #ifdef _WIN32
  164. /* select on windows erroneously returns EINVAL when no fd sets have been
  165. * provided (this is documented). what microsoft doesn't tell you that this bug
  166. * exists even when the fd sets _are_ provided, so we have to check for this bug
  167. * here and emulate by sleeping manually.
  168. * we also get EINVAL when the timeout is invalid, but we ignore this case here
  169. * and assume that EINVAL always means: you have to wait manually.
  170. */
  171. if (errno == EINVAL)
  172. {
  173. if (timeout)
  174. {
  175. unsigned long ms = timeout * 1e3;
  176. Sleep (ms ? ms : 1);
  177. }
  178. return;
  179. }
  180. #endif
  181. if (errno == EBADF)
  182. fd_ebadf (EV_A);
  183. else if (errno == ENOMEM && !syserr_cb)
  184. fd_enomem (EV_A);
  185. else if (errno != EINTR)
  186. ev_syserr ("(libev) select");
  187. return;
  188. }
  189. #if EV_SELECT_USE_FD_SET
  190. {
  191. int fd;
  192. for (fd = 0; fd < anfdmax; ++fd)
  193. if (anfds [fd].events)
  194. {
  195. int events = 0;
  196. #if EV_SELECT_IS_WINSOCKET
  197. SOCKET handle = anfds [fd].handle;
  198. #else
  199. int handle = fd;
  200. #endif
  201. if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ;
  202. if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE;
  203. #ifdef _WIN32
  204. if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE;
  205. #endif
  206. if (expect_true (events))
  207. fd_event (EV_A_ fd, events);
  208. }
  209. }
  210. #else
  211. {
  212. int word, bit;
  213. for (word = vec_max; word--; )
  214. {
  215. fd_mask word_r = ((fd_mask *)vec_ro) [word];
  216. fd_mask word_w = ((fd_mask *)vec_wo) [word];
  217. #ifdef _WIN32
  218. word_w |= ((fd_mask *)vec_eo) [word];
  219. #endif
  220. if (word_r || word_w)
  221. for (bit = NFDBITS; bit--; )
  222. {
  223. fd_mask mask = 1UL << bit;
  224. int events = 0;
  225. events |= word_r & mask ? EV_READ : 0;
  226. events |= word_w & mask ? EV_WRITE : 0;
  227. if (expect_true (events))
  228. fd_event (EV_A_ word * NFDBITS + bit, events);
  229. }
  230. }
  231. }
  232. #endif
  233. }
  234. int inline_size
  235. select_init (EV_P_ int flags)
  236. {
  237. backend_mintime = 1e-6;
  238. backend_modify = select_modify;
  239. backend_poll = select_poll;
  240. #if EV_SELECT_USE_FD_SET
  241. vec_ri = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri);
  242. vec_ro = ev_malloc (sizeof (fd_set));
  243. vec_wi = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi);
  244. vec_wo = ev_malloc (sizeof (fd_set));
  245. #ifdef _WIN32
  246. vec_eo = ev_malloc (sizeof (fd_set));
  247. #endif
  248. #else
  249. vec_max = 0;
  250. vec_ri = 0;
  251. vec_ro = 0;
  252. vec_wi = 0;
  253. vec_wo = 0;
  254. #ifdef _WIN32
  255. vec_eo = 0;
  256. #endif
  257. #endif
  258. return EVBACKEND_SELECT;
  259. }
  260. void inline_size
  261. select_destroy (EV_P)
  262. {
  263. ev_free (vec_ri);
  264. ev_free (vec_ro);
  265. ev_free (vec_wi);
  266. ev_free (vec_wo);
  267. #ifdef _WIN32
  268. ev_free (vec_eo);
  269. #endif
  270. }