Commit 88cee40b authored by Denis Bilenko's avatar Denis Bilenko

use different callback for each watcher, because layout is not always the same...

use different callback for each watcher, because layout is not always the same (e.g. timer on windows)

also:
 - incref callback and loop before calling a callback
 - fix compilation problem on visual c
 - do not add cdef functions in watchers, thus removing vtab pointer
parent 0389a595
......@@ -37,12 +37,13 @@ static inline void gevent_check_signals(struct PyGeventLoopObject* loop) {
if (PyErr_Occurred()) gevent_handle_error(loop, Py_None);
}
#define GET_OBJECT(EV_PTR, PY_TYPE, MEMBER) \
#define GET_OBJECT(PY_TYPE, EV_PTR, MEMBER) \
((struct PY_TYPE *)(((char *)EV_PTR) - offsetof(struct PY_TYPE, MEMBER)))
#ifdef WITH_THREAD
#define GIL_ENSURE PyGILState_STATE ___save = PyGILState_Ensure();
#define GIL_DECLARE PyGILState_STATE ___save
#define GIL_ENSURE ___save = PyGILState_Ensure();
#define GIL_RELEASE PyGILState_Release(___save);
#else
#define GIL_ENSURE
......@@ -50,53 +51,44 @@ static inline void gevent_check_signals(struct PyGeventLoopObject* loop) {
#endif
static inline void gevent_stop(struct PyGeventTimerObject* watcher) {
PyObject *result, *callable;
result = ((struct __pyx_vtabstruct_6gevent_4core_timer *)watcher->__pyx_vtab)->stop(watcher, 0);
if (result) {
Py_DECREF(result);
}
else {
gevent_handle_error(watcher->loop, (PyObject*)watcher);
static void gevent_stop(PyObject* watcher, struct PyGeventLoopObject* loop) {
PyObject *result, *method;
method = PyObject_GetAttrString(watcher, "stop"); // XXX replace with GetAttr
if (method) {
result = PyObject_Call(method, __pyx_empty_tuple, NULL);
if (result) {
Py_DECREF(result);
return;
}
Py_DECREF(method);
}
gevent_handle_error(loop, watcher);
}
#define io_offsetof offsetof(struct PyGeventIOObject, _watcher)
#define timer_offsetof offsetof(struct PyGeventTimerObject, _watcher)
#define signal_offsetof offsetof(struct PyGeventSignalObject, _watcher)
#define idle_offsetof offsetof(struct PyGeventIdleObject, _watcher)
#define prepare_offsetof offsetof(struct PyGeventPrepareObject, _watcher)
#define callback_offsetof offsetof(struct PyGeventCallbackObject, _watcher)
#define CHECK_OFFSETOF (timer_offsetof == signal_offsetof) && (timer_offsetof == idle_offsetof) && (timer_offsetof == prepare_offsetof) && (timer_offsetof == callback_offsetof) && (timer_offsetof == io_offsetof)
static void gevent_callback(struct ev_loop *_loop, void *c_watcher, int revents) {
struct PyGeventTimerObject *watcher;
PyObject *result, *py_events, *args;
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;
/* we use this callback for all watchers, not just timer
* we can do this, because layout of struct members is the same for all watchers */
watcher = ((struct PyGeventTimerObject *)(((char *)c_watcher) - timer_offsetof));
Py_INCREF((PyObject*)watcher);
gevent_check_signals(watcher->loop);
args = watcher->args;
Py_INCREF(loop);
Py_INCREF(callback);
Py_INCREF(args);
Py_INCREF(watcher);
gevent_check_signals(loop);
if (args == Py_None) {
args = __pyx_empty_tuple;
}
Py_INCREF(args);
length = PyTuple_Size(args);
if (length < 0) {
gevent_handle_error(watcher->loop, (PyObject*)watcher);
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(watcher->loop, (PyObject*)watcher);
gevent_handle_error(loop, watcher);
goto end;
}
PyTuple_SET_ITEM(args, 0, py_events);
......@@ -104,47 +96,59 @@ static void gevent_callback(struct ev_loop *_loop, void *c_watcher, int revents)
else {
py_events = NULL;
}
/* The callback can clear watcher->args and thus drop reference of args to zero;
* that's why we need to incref args above. */
result = PyObject_Call(watcher->_callback, args, NULL);
result = PyObject_Call(callback, args, NULL);
if (result) {
Py_DECREF(result);
}
else {
gevent_handle_error(watcher->loop, (PyObject*)watcher);
gevent_handle_error(loop, watcher);
if (revents & (EV_READ|EV_WRITE)) {
/* this was an 'io' watcher: not stopping it will likely to cause the failing callback to be called repeatedly */
gevent_stop(watcher);
gevent_stop(watcher, loop);
goto end;
}
}
if (!ev_is_active(c_watcher)) {
/* watcher will never be run again: calling stop() will clear 'callback' and 'args' */
gevent_stop(watcher);
gevent_stop(watcher, loop);
}
end:
if (py_events) {
Py_DECREF(py_events);
PyTuple_SET_ITEM(args, 0, GEVENT_CORE_EVENTS);
}
Py_DECREF((PyObject*)watcher);
Py_DECREF(watcher);
Py_DECREF(args);
Py_DECREF(callback);
Py_DECREF(loop);
GIL_RELEASE;
}
#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_signal_check(struct ev_loop *_loop, void *watcher, int revents) {
char STATIC_ASSERTION__same_offsetof[(CHECK_OFFSETOF)?1:-1];
GIL_DECLARE;
GIL_ENSURE;
gevent_check_signals(GET_OBJECT(watcher, PyGeventLoopObject, _signal_checker));
gevent_check_signals(GET_OBJECT(PyGeventLoopObject, watcher, _signal_checker));
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(watcher, PyGeventLoopObject, _periodic_signal_checker));
gevent_check_signals(GET_OBJECT(PyGeventLoopObject, watcher, _periodic_signal_checker));
GIL_RELEASE;
}
......
static void gevent_callback(struct ev_loop *, void *, int);
#define DEFINE_CALLBACK(WATCHER_LC, WATCHER_TYPE) \
static void gevent_callback_##WATCHER_LC(struct ev_loop *, void *, int);
#define DEFINE_CALLBACKS \
DEFINE_CALLBACK(io, IO); \
DEFINE_CALLBACK(timer, Timer); \
DEFINE_CALLBACK(signal, Signal); \
DEFINE_CALLBACK(idle, Idle); \
DEFINE_CALLBACK(prepare, Prepare); \
DEFINE_CALLBACK(fork, Fork);
DEFINE_CALLBACKS
static void gevent_signal_check(struct ev_loop *, void *, int);
struct PyGeventLoopObject;
static void gevent_handle_error(struct PyGeventLoopObject* loop, PyObject* where);
......
......@@ -31,7 +31,12 @@ cdef extern from "frameobject.h":
PyThreadState* PyThreadState_GET()
cdef extern from "callbacks.h":
void gevent_callback(libev.ev_loop, void*, int)
void gevent_callback_io(libev.ev_loop, void*, int)
void gevent_callback_timer(libev.ev_loop, void*, int)
void gevent_callback_signal(libev.ev_loop, void*, int)
void gevent_callback_idle(libev.ev_loop, void*, int)
void gevent_callback_prepare(libev.ev_loop, void*, int)
void gevent_callback_fork(libev.ev_loop, void*, int)
void gevent_signal_check(libev.ev_loop, void*, int)
void gevent_periodic_signal_check(libev.ev_loop, void*, int)
......@@ -410,7 +415,7 @@ define(WATCHER_BASE, `cdef public loop loop
def __del__(self):
self._callback = None
cpdef stop(self):
def stop(self):
libev.ev_$1_stop(self.loop._ptr, &self._watcher)
self._callback = None
self.args = None
......@@ -434,12 +439,6 @@ define(WATCHER_BASE, `cdef public loop loop
libev.ev_set_priority(&self._watcher, priority)
def feed(self, int revents, object callback, *args):
self.callback = callback
self.args = args
libev.ev_feed_event(self.loop._ptr, &self._watcher, revents)
INCREF
cdef _feed(self, int revents, object callback, tuple args=()):
self.callback = callback
self.args = args
libev.ev_feed_event(self.loop._ptr, &self._watcher, revents)
......@@ -453,12 +452,6 @@ define(ACTIVE, `property active:
define(START, `def start(self, object callback, *args):
self.callback = callback
self.args = args
libev.ev_$1_start(self.loop._ptr, &self._watcher)
INCREF
cdef _start(self, object callback, tuple args=()):
self.callback = callback
self.args = args
libev.ev_$1_start(self.loop._ptr, &self._watcher)
......@@ -473,7 +466,7 @@ define(WATCHER, `WATCHER_BASE($1)
define(INIT, `def __init__(self, loop loop$2):
libev.ev_$1_init(&self._watcher, <void *>gevent_callback$3)
libev.ev_$1_init(&self._watcher, <void *>gevent_callback_$1$3)
self.loop = loop
self._incref = 0')
......@@ -526,7 +519,7 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]:
IFDEF_WINDOWS()
fd = _open_osfhandle(fd)
ENDIF()
libev.ev_io_init(&self._watcher, <void *>gevent_callback, fd, events)
libev.ev_io_init(&self._watcher, <void *>gevent_callback_io, fd, events)
self.loop = loop
self._incref = 0
......@@ -538,7 +531,7 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]:
def __set__(self, int fd):
if libev.ev_is_active(&self._watcher):
raise AttributeError("'io' watcher attribute 'fd' is read-only while watcher is active")
libev.ev_io_init(&self._watcher, <void *>gevent_callback, fd, self._watcher.events)
libev.ev_io_init(&self._watcher, <void *>gevent_callback_io, fd, self._watcher.events)
property events:
......@@ -548,7 +541,7 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]:
def __set__(self, int events):
if libev.ev_is_active(&self._watcher):
raise AttributeError("'io' watcher attribute 'events' is read-only while watcher is active")
libev.ev_io_init(&self._watcher, <void *>gevent_callback, self._watcher.fd, events)
libev.ev_io_init(&self._watcher, <void *>gevent_callback_io, self._watcher.fd, events)
property events_str:
......@@ -613,12 +606,6 @@ cdef public class callback(watcher) [object PyGeventCallbackObject, type PyGeven
libev.ev_feed_event(self.loop._ptr, &self._watcher, libev.EV_CUSTOM)
INCREF
cdef _start(self, object callback, tuple args=()):
self.callback = callback
self.args = args
libev.ev_feed_event(self.loop._ptr, &self._watcher, libev.EV_CUSTOM)
INCREF
property active:
def __get__(self):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment