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