| #include <Python.h> |
| #include <ev.h> |
| |
| typedef struct libevwrapper_Loop { |
| PyObject_HEAD |
| struct ev_loop *loop; |
| } libevwrapper_Loop; |
| |
| static void |
| Loop_dealloc(libevwrapper_Loop *self) { |
| ev_loop_destroy(self->loop); |
| Py_TYPE(self)->tp_free((PyObject *)self); |
| }; |
| |
| static PyObject* |
| Loop_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { |
| libevwrapper_Loop *self; |
| |
| self = (libevwrapper_Loop *)type->tp_alloc(type, 0); |
| if (self != NULL) { |
| self->loop = ev_loop_new(EVBACKEND_SELECT); |
| if (!self->loop) { |
| PyErr_SetString(PyExc_Exception, "Error getting new ev loop"); |
| Py_DECREF(self); |
| return NULL; |
| } |
| } |
| return (PyObject *)self; |
| }; |
| |
| static int |
| Loop_init(libevwrapper_Loop *self, PyObject *args, PyObject *kwds) { |
| if (!PyArg_ParseTuple(args, "")) { |
| PyErr_SetString(PyExc_TypeError, "Loop.__init__() takes no arguments"); |
| return -1; |
| } |
| return 0; |
| }; |
| |
| static PyObject * |
| Loop_start(libevwrapper_Loop *self, PyObject *args) { |
| Py_BEGIN_ALLOW_THREADS |
| ev_run(self->loop, 0); |
| Py_END_ALLOW_THREADS |
| Py_RETURN_NONE; |
| }; |
| |
| static PyObject * |
| Loop_unref(libevwrapper_Loop *self, PyObject *args) { |
| ev_unref(self->loop); |
| Py_RETURN_NONE; |
| } |
| |
| static PyMethodDef Loop_methods[] = { |
| {"start", (PyCFunction)Loop_start, METH_NOARGS, "Start the event loop"}, |
| {"unref", (PyCFunction)Loop_unref, METH_NOARGS, "Unrefrence the event loop"}, |
| {NULL} /* Sentinel */ |
| }; |
| |
| static |
| PyTypeObject libevwrapper_LoopType = { |
| PyVarObject_HEAD_INIT(NULL, 0) |
| "cassandra.io.libevwrapper.Loop",/*tp_name*/ |
| sizeof(libevwrapper_Loop), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| (destructor)Loop_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash */ |
| 0, /*tp_call*/ |
| 0, /*tp_str*/ |
| 0, /*tp_getattro*/ |
| 0, /*tp_setattro*/ |
| 0, /*tp_as_buffer*/ |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
| "Loop objects", /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| Loop_methods, /* tp_methods */ |
| 0, /* tp_members */ |
| 0, /* tp_getset */ |
| 0, /* tp_base */ |
| 0, /* tp_dict */ |
| 0, /* tp_descr_get */ |
| 0, /* tp_descr_set */ |
| 0, /* tp_dictoffset */ |
| (initproc)Loop_init, /* tp_init */ |
| 0, /* tp_alloc */ |
| Loop_new, /* tp_new */ |
| }; |
| |
| typedef struct libevwrapper_IO { |
| PyObject_HEAD |
| struct ev_io io; |
| struct libevwrapper_Loop *loop; |
| PyObject *callback; |
| } libevwrapper_IO; |
| |
| static void |
| IO_dealloc(libevwrapper_IO *self) { |
| Py_XDECREF(self->loop); |
| Py_XDECREF(self->callback); |
| Py_TYPE(self)->tp_free((PyObject *)self); |
| }; |
| |
| static void io_callback(struct ev_loop *loop, ev_io *watcher, int revents) { |
| libevwrapper_IO *self = watcher->data; |
| PyObject *result; |
| PyGILState_STATE gstate = PyGILState_Ensure(); |
| if (revents & EV_ERROR && errno) { |
| result = PyObject_CallFunction(self->callback, "Obi", self, revents, errno); |
| } else { |
| result = PyObject_CallFunction(self->callback, "Ob", self, revents); |
| } |
| if (!result) { |
| PyErr_WriteUnraisable(self->callback); |
| } |
| Py_XDECREF(result); |
| PyGILState_Release(gstate); |
| }; |
| |
| static int |
| IO_init(libevwrapper_IO *self, PyObject *args, PyObject *kwds) { |
| PyObject *socket; |
| PyObject *callback; |
| PyObject *loop; |
| int io_flags = 0, fd = -1; |
| struct ev_io *io = NULL; |
| |
| if (!PyArg_ParseTuple(args, "OiOO", &socket, &io_flags, &loop, &callback)) { |
| return -1; |
| } |
| |
| if (loop) { |
| Py_INCREF(loop); |
| self->loop = (libevwrapper_Loop *)loop; |
| } |
| |
| if (callback) { |
| if (!PyCallable_Check(callback)) { |
| PyErr_SetString(PyExc_TypeError, "callback parameter must be callable"); |
| Py_XDECREF(loop); |
| return -1; |
| } |
| Py_INCREF(callback); |
| self->callback = callback; |
| } |
| |
| fd = PyObject_AsFileDescriptor(socket); |
| if (fd == -1) { |
| PyErr_SetString(PyExc_TypeError, "unable to get file descriptor from socket"); |
| Py_XDECREF(callback); |
| Py_XDECREF(loop); |
| return -1; |
| } |
| io = &(self->io); |
| ev_io_init(io, io_callback, fd, io_flags); |
| self->io.data = self; |
| return 0; |
| } |
| |
| static PyObject* |
| IO_start(libevwrapper_IO *self, PyObject *args) { |
| ev_io_start(self->loop->loop, &self->io); |
| Py_RETURN_NONE; |
| } |
| |
| static PyObject* |
| IO_stop(libevwrapper_IO *self, PyObject *args) { |
| ev_io_stop(self->loop->loop, &self->io); |
| Py_RETURN_NONE; |
| } |
| |
| static PyObject* |
| IO_is_active(libevwrapper_IO *self, PyObject *args) { |
| struct ev_io *io = &(self->io); |
| return PyBool_FromLong(ev_is_active(io)); |
| } |
| |
| static PyObject* |
| IO_is_pending(libevwrapper_IO *self, PyObject *args) { |
| struct ev_io *io = &(self->io); |
| return PyBool_FromLong(ev_is_pending(io)); |
| } |
| |
| static PyMethodDef IO_methods[] = { |
| {"start", (PyCFunction)IO_start, METH_NOARGS, "Start the watcher"}, |
| {"stop", (PyCFunction)IO_stop, METH_NOARGS, "Stop the watcher"}, |
| {"is_active", (PyCFunction)IO_is_active, METH_NOARGS, "Is the watcher active?"}, |
| {"is_pending", (PyCFunction)IO_is_pending, METH_NOARGS, "Is the watcher pending?"}, |
| {NULL} /* Sentinal */ |
| }; |
| |
| static PyTypeObject libevwrapper_IOType = { |
| PyVarObject_HEAD_INIT(NULL, 0) |
| "cassandra.io.libevwrapper.IO", /*tp_name*/ |
| sizeof(libevwrapper_IO), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| (destructor)IO_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash */ |
| 0, /*tp_call*/ |
| 0, /*tp_str*/ |
| 0, /*tp_getattro*/ |
| 0, /*tp_setattro*/ |
| 0, /*tp_as_buffer*/ |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
| "IO objects", /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| IO_methods, /* tp_methods */ |
| 0, /* tp_members */ |
| 0, /* tp_getset */ |
| 0, /* tp_base */ |
| 0, /* tp_dict */ |
| 0, /* tp_descr_get */ |
| 0, /* tp_descr_set */ |
| 0, /* tp_dictoffset */ |
| (initproc)IO_init, /* tp_init */ |
| }; |
| |
| typedef struct libevwrapper_Async { |
| PyObject_HEAD |
| struct ev_async async; |
| struct libevwrapper_Loop *loop; |
| } libevwrapper_Async; |
| |
| static void |
| Async_dealloc(libevwrapper_Async *self) { |
| Py_XDECREF(self->loop); |
| Py_TYPE(self)->tp_free((PyObject *)self); |
| }; |
| |
| static void async_callback(EV_P_ ev_async *watcher, int revents) {}; |
| |
| static int |
| Async_init(libevwrapper_Async *self, PyObject *args, PyObject *kwds) { |
| PyObject *loop; |
| static char *kwlist[] = {"loop", NULL}; |
| struct ev_async *async = NULL; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &loop)) { |
| PyErr_SetString(PyExc_TypeError, "unable to get file descriptor from socket"); |
| return -1; |
| } |
| |
| if (loop) { |
| Py_INCREF(loop); |
| self->loop = (libevwrapper_Loop *)loop; |
| } else { |
| return -1; |
| } |
| async = &(self->async); |
| ev_async_init(async, async_callback); |
| return 0; |
| }; |
| |
| static PyObject * |
| Async_start(libevwrapper_Async *self, PyObject *args) { |
| ev_async_start(self->loop->loop, &self->async); |
| Py_RETURN_NONE; |
| } |
| |
| static PyObject * |
| Async_send(libevwrapper_Async *self, PyObject *args) { |
| ev_async_send(self->loop->loop, &self->async); |
| Py_RETURN_NONE; |
| }; |
| |
| static PyMethodDef Async_methods[] = { |
| {"start", (PyCFunction)Async_start, METH_NOARGS, "Start the watcher"}, |
| {"send", (PyCFunction)Async_send, METH_NOARGS, "Notify the event loop"}, |
| {NULL} /* Sentinel */ |
| }; |
| |
| static PyTypeObject libevwrapper_AsyncType = { |
| PyVarObject_HEAD_INIT(NULL, 0) |
| "cassandra.io.libevwrapper.Async", /*tp_name*/ |
| sizeof(libevwrapper_Async), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| (destructor)Async_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash */ |
| 0, /*tp_call*/ |
| 0, /*tp_str*/ |
| 0, /*tp_getattro*/ |
| 0, /*tp_setattro*/ |
| 0, /*tp_as_buffer*/ |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
| "Async objects", /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| Async_methods, /* tp_methods */ |
| 0, /* tp_members */ |
| 0, /* tp_getset */ |
| 0, /* tp_base */ |
| 0, /* tp_dict */ |
| 0, /* tp_descr_get */ |
| 0, /* tp_descr_set */ |
| 0, /* tp_dictoffset */ |
| (initproc)Async_init, /* tp_init */ |
| }; |
| |
| typedef struct libevwrapper_Prepare { |
| PyObject_HEAD |
| struct ev_prepare prepare; |
| struct libevwrapper_Loop *loop; |
| PyObject *callback; |
| } libevwrapper_Prepare; |
| |
| static void |
| Prepare_dealloc(libevwrapper_Prepare *self) { |
| Py_XDECREF(self->loop); |
| Py_XDECREF(self->callback); |
| Py_TYPE(self)->tp_free((PyObject *)self); |
| } |
| |
| static void prepare_callback(struct ev_loop *loop, ev_prepare *watcher, int revents) { |
| libevwrapper_Prepare *self = watcher->data; |
| PyObject *result = NULL; |
| PyGILState_STATE gstate; |
| |
| gstate = PyGILState_Ensure(); |
| result = PyObject_CallFunction(self->callback, "O", self); |
| if (!result) { |
| PyErr_WriteUnraisable(self->callback); |
| } |
| Py_XDECREF(result); |
| |
| PyGILState_Release(gstate); |
| } |
| |
| static int |
| Prepare_init(libevwrapper_Prepare *self, PyObject *args, PyObject *kwds) { |
| PyObject *callback; |
| PyObject *loop; |
| struct ev_prepare *prepare = NULL; |
| |
| if (!PyArg_ParseTuple(args, "OO", &loop, &callback)) { |
| return -1; |
| } |
| |
| if (loop) { |
| Py_INCREF(loop); |
| self->loop = (libevwrapper_Loop *)loop; |
| } else { |
| return -1; |
| } |
| |
| if (callback) { |
| if (!PyCallable_Check(callback)) { |
| PyErr_SetString(PyExc_TypeError, "callback parameter must be callable"); |
| Py_XDECREF(loop); |
| return -1; |
| } |
| Py_INCREF(callback); |
| self->callback = callback; |
| } |
| prepare = &(self->prepare); |
| ev_prepare_init(prepare, prepare_callback); |
| self->prepare.data = self; |
| return 0; |
| } |
| |
| static PyObject * |
| Prepare_start(libevwrapper_Prepare *self, PyObject *args) { |
| ev_prepare_start(self->loop->loop, &self->prepare); |
| Py_RETURN_NONE; |
| } |
| |
| static PyObject * |
| Prepare_stop(libevwrapper_Prepare *self, PyObject *args) { |
| ev_prepare_stop(self->loop->loop, &self->prepare); |
| Py_RETURN_NONE; |
| } |
| |
| static PyMethodDef Prepare_methods[] = { |
| {"start", (PyCFunction)Prepare_start, METH_NOARGS, "Start the Prepare watcher"}, |
| {"stop", (PyCFunction)Prepare_stop, METH_NOARGS, "Stop the Prepare watcher"}, |
| {NULL} /* Sentinal */ |
| }; |
| |
| static PyTypeObject libevwrapper_PrepareType = { |
| PyVarObject_HEAD_INIT(NULL, 0) |
| "cassandra.io.libevwrapper.Prepare", /*tp_name*/ |
| sizeof(libevwrapper_Prepare), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| (destructor)Prepare_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash */ |
| 0, /*tp_call*/ |
| 0, /*tp_str*/ |
| 0, /*tp_getattro*/ |
| 0, /*tp_setattro*/ |
| 0, /*tp_as_buffer*/ |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
| "Prepare objects", /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| Prepare_methods, /* tp_methods */ |
| 0, /* tp_members */ |
| 0, /* tp_getset */ |
| 0, /* tp_base */ |
| 0, /* tp_dict */ |
| 0, /* tp_descr_get */ |
| 0, /* tp_descr_set */ |
| 0, /* tp_dictoffset */ |
| (initproc)Prepare_init, /* tp_init */ |
| }; |
| |
| typedef struct libevwrapper_Timer { |
| PyObject_HEAD |
| struct ev_timer timer; |
| struct libevwrapper_Loop *loop; |
| PyObject *callback; |
| } libevwrapper_Timer; |
| |
| static void |
| Timer_dealloc(libevwrapper_Timer *self) { |
| Py_XDECREF(self->loop); |
| Py_XDECREF(self->callback); |
| Py_TYPE(self)->tp_free((PyObject *)self); |
| } |
| |
| static void timer_callback(struct ev_loop *loop, ev_timer *watcher, int revents) { |
| libevwrapper_Timer *self = watcher->data; |
| |
| PyObject *result = NULL; |
| PyGILState_STATE gstate; |
| |
| gstate = PyGILState_Ensure(); |
| result = PyObject_CallFunction(self->callback, NULL); |
| if (!result) { |
| PyErr_WriteUnraisable(self->callback); |
| } |
| Py_XDECREF(result); |
| |
| PyGILState_Release(gstate); |
| } |
| |
| static int |
| Timer_init(libevwrapper_Timer *self, PyObject *args, PyObject *kwds) { |
| PyObject *callback; |
| PyObject *loop; |
| |
| if (!PyArg_ParseTuple(args, "OO", &loop, &callback)) { |
| return -1; |
| } |
| |
| if (loop) { |
| Py_INCREF(loop); |
| self->loop = (libevwrapper_Loop *)loop; |
| } else { |
| return -1; |
| } |
| |
| if (callback) { |
| if (!PyCallable_Check(callback)) { |
| PyErr_SetString(PyExc_TypeError, "callback parameter must be callable"); |
| Py_XDECREF(loop); |
| return -1; |
| } |
| Py_INCREF(callback); |
| self->callback = callback; |
| } |
| ev_init(&self->timer, timer_callback); |
| self->timer.data = self; |
| return 0; |
| } |
| |
| static PyObject * |
| Timer_start(libevwrapper_Timer *self, PyObject *args) { |
| double timeout; |
| if (!PyArg_ParseTuple(args, "d", &timeout)) { |
| return NULL; |
| } |
| /* some tiny non-zero number to avoid zero, and |
| make it run immediately for negative timeouts */ |
| self->timer.repeat = fmax(timeout, 0.000000001); |
| ev_timer_again(self->loop->loop, &self->timer); |
| Py_RETURN_NONE; |
| } |
| |
| static PyObject * |
| Timer_stop(libevwrapper_Timer *self, PyObject *args) { |
| ev_timer_stop(self->loop->loop, &self->timer); |
| Py_RETURN_NONE; |
| } |
| |
| static PyMethodDef Timer_methods[] = { |
| {"start", (PyCFunction)Timer_start, METH_VARARGS, "Start the Timer watcher"}, |
| {"stop", (PyCFunction)Timer_stop, METH_NOARGS, "Stop the Timer watcher"}, |
| {NULL} /* Sentinal */ |
| }; |
| |
| static PyTypeObject libevwrapper_TimerType = { |
| PyVarObject_HEAD_INIT(NULL, 0) |
| "cassandra.io.libevwrapper.Timer", /*tp_name*/ |
| sizeof(libevwrapper_Timer), /*tp_basicsize*/ |
| 0, /*tp_itemsize*/ |
| (destructor)Timer_dealloc, /*tp_dealloc*/ |
| 0, /*tp_print*/ |
| 0, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| 0, /*tp_repr*/ |
| 0, /*tp_as_number*/ |
| 0, /*tp_as_sequence*/ |
| 0, /*tp_as_mapping*/ |
| 0, /*tp_hash */ |
| 0, /*tp_call*/ |
| 0, /*tp_str*/ |
| 0, /*tp_getattro*/ |
| 0, /*tp_setattro*/ |
| 0, /*tp_as_buffer*/ |
| Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ |
| "Timer objects", /* tp_doc */ |
| 0, /* tp_traverse */ |
| 0, /* tp_clear */ |
| 0, /* tp_richcompare */ |
| 0, /* tp_weaklistoffset */ |
| 0, /* tp_iter */ |
| 0, /* tp_iternext */ |
| Timer_methods, /* tp_methods */ |
| 0, /* tp_members */ |
| 0, /* tp_getset */ |
| 0, /* tp_base */ |
| 0, /* tp_dict */ |
| 0, /* tp_descr_get */ |
| 0, /* tp_descr_set */ |
| 0, /* tp_dictoffset */ |
| (initproc)Timer_init, /* tp_init */ |
| }; |
| |
| |
| static PyMethodDef module_methods[] = { |
| {NULL} /* Sentinal */ |
| }; |
| |
| PyDoc_STRVAR(module_doc, |
| "libev wrapper methods"); |
| |
| static struct PyModuleDef moduledef = { |
| PyModuleDef_HEAD_INIT, |
| "libevwrapper", |
| module_doc, |
| -1, |
| module_methods, |
| NULL, |
| NULL, |
| NULL, |
| NULL |
| }; |
| |
| #define INITERROR return NULL |
| |
| PyObject * |
| PyInit_libevwrapper(void) |
| { |
| PyObject *module = NULL; |
| |
| if (PyType_Ready(&libevwrapper_LoopType) < 0) |
| INITERROR; |
| |
| libevwrapper_IOType.tp_new = PyType_GenericNew; |
| if (PyType_Ready(&libevwrapper_IOType) < 0) |
| INITERROR; |
| |
| libevwrapper_PrepareType.tp_new = PyType_GenericNew; |
| if (PyType_Ready(&libevwrapper_PrepareType) < 0) |
| INITERROR; |
| |
| libevwrapper_AsyncType.tp_new = PyType_GenericNew; |
| if (PyType_Ready(&libevwrapper_AsyncType) < 0) |
| INITERROR; |
| |
| libevwrapper_TimerType.tp_new = PyType_GenericNew; |
| if (PyType_Ready(&libevwrapper_TimerType) < 0) |
| INITERROR; |
| |
| module = PyModule_Create(&moduledef); |
| |
| if (module == NULL) |
| INITERROR; |
| |
| if (PyModule_AddIntConstant(module, "EV_READ", EV_READ) == -1) |
| INITERROR; |
| if (PyModule_AddIntConstant(module, "EV_WRITE", EV_WRITE) == -1) |
| INITERROR; |
| if (PyModule_AddIntConstant(module, "EV_ERROR", EV_ERROR) == -1) |
| INITERROR; |
| |
| Py_INCREF(&libevwrapper_LoopType); |
| if (PyModule_AddObject(module, "Loop", (PyObject *)&libevwrapper_LoopType) == -1) |
| INITERROR; |
| |
| Py_INCREF(&libevwrapper_IOType); |
| if (PyModule_AddObject(module, "IO", (PyObject *)&libevwrapper_IOType) == -1) |
| INITERROR; |
| |
| Py_INCREF(&libevwrapper_PrepareType); |
| if (PyModule_AddObject(module, "Prepare", (PyObject *)&libevwrapper_PrepareType) == -1) |
| INITERROR; |
| |
| Py_INCREF(&libevwrapper_AsyncType); |
| if (PyModule_AddObject(module, "Async", (PyObject *)&libevwrapper_AsyncType) == -1) |
| INITERROR; |
| |
| Py_INCREF(&libevwrapper_TimerType); |
| if (PyModule_AddObject(module, "Timer", (PyObject *)&libevwrapper_TimerType) == -1) |
| INITERROR; |
| |
| #if PY_MAJOR_VERSION < 3 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7) |
| // Since CPython 3.7, `Py_Initialize()` routing always initializes GIL. |
| // Routine `PyEval_ThreadsInitialized()` has been deprecated in CPython 3.7 |
| // and completely removed in CPython 3.13. |
| if (!PyEval_ThreadsInitialized()) { |
| PyEval_InitThreads(); |
| } |
| #endif |
| |
| return module; |
| } |