aboutsummaryrefslogtreecommitdiffstats
path: root/python/gevent/libev/callbacks.c
diff options
context:
space:
mode:
Diffstat (limited to 'python/gevent/libev/callbacks.c')
-rw-r--r--python/gevent/libev/callbacks.c225
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 */