libev_vfd.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #ifdef _WIN32
  2. #ifdef _WIN64
  3. typedef PY_LONG_LONG vfd_socket_t;
  4. #define vfd_socket_object PyLong_FromLongLong
  5. #else
  6. typedef long vfd_socket_t;
  7. #define vfd_socket_object PyInt_FromLong
  8. #endif
  9. #ifdef LIBEV_EMBED
  10. /*
  11. * If libev on win32 is embedded, then we can use an
  12. * arbitrary mapping between integer fds and OS
  13. * handles. Then by defining special macros libev
  14. * will use our functions.
  15. */
  16. #define WIN32_LEAN_AND_MEAN
  17. #include <winsock2.h>
  18. #include <windows.h>
  19. typedef struct vfd_entry_t
  20. {
  21. vfd_socket_t handle; /* OS handle, i.e. SOCKET */
  22. int count; /* Reference count, 0 if free */
  23. int next; /* Next free fd, -1 if last */
  24. } vfd_entry;
  25. #define VFD_INCREMENT 128
  26. static int vfd_num = 0; /* num allocated fds */
  27. static int vfd_max = 0; /* max allocated fds */
  28. static int vfd_next = -1; /* next free fd for reuse */
  29. static PyObject* vfd_map = NULL; /* map OS handle -> virtual fd */
  30. static vfd_entry* vfd_entries = NULL; /* list of virtual fd entries */
  31. #ifdef WITH_THREAD
  32. static CRITICAL_SECTION* volatile vfd_lock = NULL;
  33. static CRITICAL_SECTION* vfd_make_lock()
  34. {
  35. if (vfd_lock == NULL) {
  36. /* must use malloc and not PyMem_Malloc here */
  37. CRITICAL_SECTION* lock = malloc(sizeof(CRITICAL_SECTION));
  38. InitializeCriticalSection(lock);
  39. if (InterlockedCompareExchangePointer(&vfd_lock, lock, NULL) != NULL) {
  40. /* another thread initialized lock first */
  41. DeleteCriticalSection(lock);
  42. free(lock);
  43. }
  44. }
  45. return vfd_lock;
  46. }
  47. #define VFD_LOCK_ENTER EnterCriticalSection(vfd_make_lock())
  48. #define VFD_LOCK_LEAVE LeaveCriticalSection(vfd_lock)
  49. #define VFD_GIL_DECLARE PyGILState_STATE ___save
  50. #define VFD_GIL_ENSURE ___save = PyGILState_Ensure()
  51. #define VFD_GIL_RELEASE PyGILState_Release(___save)
  52. #else
  53. #define VFD_LOCK_ENTER
  54. #define VFD_LOCK_LEAVE
  55. #define VFD_GIL_DECLARE
  56. #define VFD_GIL_ENSURE
  57. #define VFD_GIL_RELEASE
  58. #endif
  59. /*
  60. * Given a virtual fd returns an OS handle or -1
  61. * This function is speed critical, so it cannot use GIL
  62. */
  63. static vfd_socket_t vfd_get(int fd)
  64. {
  65. int handle = -1;
  66. VFD_LOCK_ENTER;
  67. if (vfd_entries != NULL && fd >= 0 && fd < vfd_num)
  68. handle = vfd_entries[fd].handle;
  69. VFD_LOCK_LEAVE;
  70. return handle;
  71. }
  72. #define EV_FD_TO_WIN32_HANDLE(fd) vfd_get((fd))
  73. /*
  74. * Given an OS handle finds or allocates a virtual fd
  75. * Returns -1 on failure and sets Python exception if pyexc is non-zero
  76. */
  77. static int vfd_open_(vfd_socket_t handle, int pyexc)
  78. {
  79. VFD_GIL_DECLARE;
  80. int fd = -1;
  81. unsigned long arg;
  82. PyObject* key = NULL;
  83. PyObject* value;
  84. if (!pyexc) {
  85. VFD_GIL_ENSURE;
  86. }
  87. if (ioctlsocket(handle, FIONREAD, &arg) != 0) {
  88. if (pyexc)
  89. PyErr_Format(PyExc_IOError,
  90. #ifdef _WIN64
  91. "%lld is not a socket (files are not supported)",
  92. #else
  93. "%ld is not a socket (files are not supported)",
  94. #endif
  95. handle);
  96. goto done;
  97. }
  98. if (vfd_map == NULL) {
  99. vfd_map = PyDict_New();
  100. if (vfd_map == NULL)
  101. goto done;
  102. }
  103. key = vfd_socket_object(handle);
  104. /* check if it's already in the dict */
  105. value = PyDict_GetItem(vfd_map, key);
  106. if (value != NULL) {
  107. /* is it safe to use PyInt_AS_LONG(value) here? */
  108. fd = PyInt_AsLong(value);
  109. if (fd >= 0) {
  110. ++vfd_entries[fd].count;
  111. goto done;
  112. }
  113. }
  114. /* use the free entry, if available */
  115. if (vfd_next >= 0) {
  116. fd = vfd_next;
  117. vfd_next = vfd_entries[fd].next;
  118. VFD_LOCK_ENTER;
  119. goto allocated;
  120. }
  121. /* check if it would be out of bounds */
  122. if (vfd_num >= FD_SETSIZE) {
  123. /* libev's select doesn't support more that FD_SETSIZE fds */
  124. if (pyexc)
  125. PyErr_Format(PyExc_IOError, "cannot watch more than %d sockets", (int)FD_SETSIZE);
  126. goto done;
  127. }
  128. /* allocate more space if needed */
  129. VFD_LOCK_ENTER;
  130. if (vfd_num >= vfd_max) {
  131. int newsize = vfd_max + VFD_INCREMENT;
  132. vfd_entry* entries = PyMem_Realloc(vfd_entries, sizeof(vfd_entry) * newsize);
  133. if (entries == NULL) {
  134. VFD_LOCK_LEAVE;
  135. if (pyexc)
  136. PyErr_NoMemory();
  137. goto done;
  138. }
  139. vfd_entries = entries;
  140. vfd_max = newsize;
  141. }
  142. fd = vfd_num++;
  143. allocated:
  144. /* vfd_lock must be acquired when entering here */
  145. vfd_entries[fd].handle = handle;
  146. vfd_entries[fd].count = 1;
  147. VFD_LOCK_LEAVE;
  148. value = PyInt_FromLong(fd);
  149. PyDict_SetItem(vfd_map, key, value);
  150. Py_DECREF(value);
  151. done:
  152. Py_XDECREF(key);
  153. if (!pyexc) {
  154. VFD_GIL_RELEASE;
  155. }
  156. return fd;
  157. }
  158. #define vfd_open(fd) vfd_open_((fd), 1)
  159. #define EV_WIN32_HANDLE_TO_FD(handle) vfd_open_((handle), 0)
  160. static void vfd_free_(int fd, int needclose)
  161. {
  162. VFD_GIL_DECLARE;
  163. PyObject* key;
  164. if (needclose) {
  165. VFD_GIL_ENSURE;
  166. }
  167. if (fd < 0 || fd >= vfd_num)
  168. goto done; /* out of bounds */
  169. if (vfd_entries[fd].count <= 0)
  170. goto done; /* free entry, ignore */
  171. if (!--vfd_entries[fd].count) {
  172. /* fd has just been freed */
  173. vfd_socket_t handle = vfd_entries[fd].handle;
  174. vfd_entries[fd].handle = -1;
  175. vfd_entries[fd].next = vfd_next;
  176. vfd_next = fd;
  177. if (needclose)
  178. closesocket(handle);
  179. /* vfd_map is assumed to be != NULL */
  180. key = vfd_socket_object(handle);
  181. PyDict_DelItem(vfd_map, key);
  182. Py_DECREF(key);
  183. }
  184. done:
  185. if (needclose) {
  186. VFD_GIL_RELEASE;
  187. }
  188. }
  189. #define vfd_free(fd) vfd_free_((fd), 0)
  190. #define EV_WIN32_CLOSE_FD(fd) vfd_free_((fd), 1)
  191. #else
  192. /*
  193. * If libev on win32 is not embedded in gevent, then
  194. * the only way to map vfds is to use the default of
  195. * using runtime fds in libev. Note that it will leak
  196. * fds, because there's no way of closing them safely
  197. */
  198. #define vfd_get(fd) _get_osfhandle((fd))
  199. #define vfd_open(fd) _open_osfhandle((fd), 0)
  200. #define vfd_free(fd)
  201. #endif
  202. #else
  203. /*
  204. * On non-win32 platforms vfd_* are noop macros
  205. */
  206. typedef int vfd_socket_t;
  207. #define vfd_get(fd) (fd)
  208. #define vfd_open(fd) ((int)(fd))
  209. #define vfd_free(fd)
  210. #endif