diff options
Diffstat (limited to 'python/gevent/libev/callbacks.c')
-rw-r--r-- | python/gevent/libev/callbacks.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/python/gevent/libev/callbacks.c b/python/gevent/libev/callbacks.c new file mode 100644 index 0000000..f65c67f --- /dev/null +++ b/python/gevent/libev/callbacks.c @@ -0,0 +1,225 @@ +/* Copyright (c) 2011-2012 Denis Bilenko. See LICENSE for details. */ +#ifdef Py_PYTHON_H + +/* the name changes depending on our file layout and --module-name option */ +#define _GEVENTLOOP struct __pyx_vtabstruct_6gevent_5libev_8corecext_loop + + +static void gevent_handle_error(struct PyGeventLoopObject* loop, PyObject* context) { + PyThreadState *tstate; + PyObject *type, *value, *traceback, *result; + tstate = PyThreadState_GET(); + type = tstate->curexc_type; + if (!type) + return; + value = tstate->curexc_value; + traceback = tstate->curexc_traceback; + if (!value) value = Py_None; + if (!traceback) traceback = Py_None; + + Py_INCREF(type); + Py_INCREF(value); + Py_INCREF(traceback); + + PyErr_Clear(); + + result = ((_GEVENTLOOP *)loop->__pyx_vtab)->handle_error(loop, context, type, value, traceback, 0); + + if (result) { + Py_DECREF(result); + } + else { + PyErr_Print(); + PyErr_Clear(); + } + + Py_DECREF(type); + Py_DECREF(value); + Py_DECREF(traceback); +} + + +static CYTHON_INLINE void gevent_check_signals(struct PyGeventLoopObject* loop) { + if (!ev_is_default_loop(loop->_ptr)) { + /* only reporting signals on the default loop */ + return; + } + PyErr_CheckSignals(); + if (PyErr_Occurred()) gevent_handle_error(loop, Py_None); +} + +#define GET_OBJECT(PY_TYPE, EV_PTR, MEMBER) \ + ((struct PY_TYPE *)(((char *)EV_PTR) - offsetof(struct PY_TYPE, MEMBER))) + + +#ifdef WITH_THREAD +#define GIL_DECLARE PyGILState_STATE ___save +#define GIL_ENSURE ___save = PyGILState_Ensure(); +#define GIL_RELEASE PyGILState_Release(___save); +#else +#define GIL_DECLARE +#define GIL_ENSURE +#define GIL_RELEASE +#endif + + +static void gevent_stop(PyObject* watcher, struct PyGeventLoopObject* loop) { + PyObject *result, *method; + int error; + error = 1; + method = PyObject_GetAttrString(watcher, "stop"); + if (method) { + result = PyObject_Call(method, __pyx_empty_tuple, NULL); + if (result) { + Py_DECREF(result); + error = 0; + } + Py_DECREF(method); + } + if (error) { + gevent_handle_error(loop, watcher); + } +} + + +static void gevent_callback(struct PyGeventLoopObject* loop, PyObject* callback, PyObject* args, PyObject* watcher, void *c_watcher, int revents) { + GIL_DECLARE; + PyObject *result, *py_events; + long length; + py_events = 0; + GIL_ENSURE; + Py_INCREF(loop); + Py_INCREF(callback); + Py_INCREF(args); + Py_INCREF(watcher); + gevent_check_signals(loop); + if (args == Py_None) { + args = __pyx_empty_tuple; + } + length = PyTuple_Size(args); + if (length < 0) { + gevent_handle_error(loop, watcher); + goto end; + } + if (length > 0 && PyTuple_GET_ITEM(args, 0) == GEVENT_CORE_EVENTS) { + py_events = PyInt_FromLong(revents); + if (!py_events) { + gevent_handle_error(loop, watcher); + goto end; + } + PyTuple_SET_ITEM(args, 0, py_events); + } + else { + py_events = NULL; + } + result = PyObject_Call(callback, args, NULL); + if (result) { + Py_DECREF(result); + } + else { + gevent_handle_error(loop, watcher); + if (revents & (EV_READ|EV_WRITE)) { + /* io watcher: not stopping it may cause the failing callback to be called repeatedly */ + gevent_stop(watcher, loop); + goto end; + } + } + if (!ev_is_active(c_watcher)) { + /* Watcher was stopped, maybe by libev. Let's call stop() to clean up + * 'callback' and 'args' properties, do Py_DECREF() and ev_ref() if necessary. + * BTW, we don't need to check for EV_ERROR, because libev stops the watcher in that case. */ + gevent_stop(watcher, loop); + } +end: + if (py_events) { + Py_DECREF(py_events); + PyTuple_SET_ITEM(args, 0, GEVENT_CORE_EVENTS); + } + Py_DECREF(watcher); + Py_DECREF(args); + Py_DECREF(callback); + Py_DECREF(loop); + GIL_RELEASE; +} + + +static void gevent_call(struct PyGeventLoopObject* loop, struct PyGeventCallbackObject* cb) { + /* no need for GIL here because it is only called from run_callbacks which already has GIL */ + PyObject *result, *callback, *args; + if (!loop || !cb) + return; + callback = cb->callback; + args = cb->args; + if (!callback || !args) + return; + if (callback == Py_None || args == Py_None) + return; + Py_INCREF(loop); + Py_INCREF(callback); + Py_INCREF(args); + + Py_INCREF(Py_None); + Py_DECREF(cb->callback); + cb->callback = Py_None; + + result = PyObject_Call(callback, args, NULL); + if (result) { + Py_DECREF(result); + } + else { + gevent_handle_error(loop, (PyObject*)cb); + } + + Py_INCREF(Py_None); + Py_DECREF(cb->args); + cb->args = Py_None; + + Py_DECREF(callback); + Py_DECREF(args); + Py_DECREF(loop); +} + + +#undef DEFINE_CALLBACK +#define DEFINE_CALLBACK(WATCHER_LC, WATCHER_TYPE) \ + static void gevent_callback_##WATCHER_LC(struct ev_loop *_loop, void *c_watcher, int revents) { \ + struct PyGevent##WATCHER_TYPE##Object* watcher = GET_OBJECT(PyGevent##WATCHER_TYPE##Object, c_watcher, _watcher); \ + gevent_callback(watcher->loop, watcher->_callback, watcher->args, (PyObject*)watcher, c_watcher, revents); \ + } + + +DEFINE_CALLBACKS + + +static void gevent_run_callbacks(struct ev_loop *_loop, void *watcher, int revents) { + struct PyGeventLoopObject* loop; + PyObject *result; + GIL_DECLARE; + GIL_ENSURE; + loop = GET_OBJECT(PyGeventLoopObject, watcher, _prepare); + Py_INCREF(loop); + gevent_check_signals(loop); + result = ((_GEVENTLOOP *)loop->__pyx_vtab)->_run_callbacks(loop); + if (result) { + Py_DECREF(result); + } + else { + PyErr_Print(); + PyErr_Clear(); + } + Py_DECREF(loop); + GIL_RELEASE; +} + +#if defined(_WIN32) + +static void gevent_periodic_signal_check(struct ev_loop *_loop, void *watcher, int revents) { + GIL_DECLARE; + GIL_ENSURE; + gevent_check_signals(GET_OBJECT(PyGeventLoopObject, watcher, _periodic_signal_checker)); + GIL_RELEASE; +} + +#endif /* _WIN32 */ + +#endif /* Py_PYTHON_H */ |