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) { ...@@ -37,12 +37,13 @@ static inline void gevent_check_signals(struct PyGeventLoopObject* loop) {
if (PyErr_Occurred()) gevent_handle_error(loop, Py_None); 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))) ((struct PY_TYPE *)(((char *)EV_PTR) - offsetof(struct PY_TYPE, MEMBER)))
#ifdef WITH_THREAD #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); #define GIL_RELEASE PyGILState_Release(___save);
#else #else
#define GIL_ENSURE #define GIL_ENSURE
...@@ -50,53 +51,44 @@ static inline void gevent_check_signals(struct PyGeventLoopObject* loop) { ...@@ -50,53 +51,44 @@ static inline void gevent_check_signals(struct PyGeventLoopObject* loop) {
#endif #endif
static inline void gevent_stop(struct PyGeventTimerObject* watcher) { static void gevent_stop(PyObject* watcher, struct PyGeventLoopObject* loop) {
PyObject *result, *callable; PyObject *result, *method;
result = ((struct __pyx_vtabstruct_6gevent_4core_timer *)watcher->__pyx_vtab)->stop(watcher, 0); method = PyObject_GetAttrString(watcher, "stop"); // XXX replace with GetAttr
if (result) { if (method) {
Py_DECREF(result); result = PyObject_Call(method, __pyx_empty_tuple, NULL);
} if (result) {
else { Py_DECREF(result);
gevent_handle_error(watcher->loop, (PyObject*)watcher); return;
}
Py_DECREF(method);
} }
gevent_handle_error(loop, watcher);
} }
#define io_offsetof offsetof(struct PyGeventIOObject, _watcher) static void gevent_callback(struct PyGeventLoopObject* loop, PyObject* callback, PyObject* args, PyObject* watcher, void *c_watcher, int revents) {
#define timer_offsetof offsetof(struct PyGeventTimerObject, _watcher) GIL_DECLARE;
#define signal_offsetof offsetof(struct PyGeventSignalObject, _watcher) PyObject *result, *py_events;
#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;
long length; long length;
py_events = 0; py_events = 0;
GIL_ENSURE; GIL_ENSURE;
/* we use this callback for all watchers, not just timer Py_INCREF(loop);
* we can do this, because layout of struct members is the same for all watchers */ Py_INCREF(callback);
watcher = ((struct PyGeventTimerObject *)(((char *)c_watcher) - timer_offsetof)); Py_INCREF(args);
Py_INCREF((PyObject*)watcher); Py_INCREF(watcher);
gevent_check_signals(watcher->loop); gevent_check_signals(loop);
args = watcher->args;
if (args == Py_None) { if (args == Py_None) {
args = __pyx_empty_tuple; args = __pyx_empty_tuple;
} }
Py_INCREF(args);
length = PyTuple_Size(args); length = PyTuple_Size(args);
if (length < 0) { if (length < 0) {
gevent_handle_error(watcher->loop, (PyObject*)watcher); gevent_handle_error(loop, watcher);
goto end; goto end;
} }
if (length > 0 && PyTuple_GET_ITEM(args, 0) == GEVENT_CORE_EVENTS) { if (length > 0 && PyTuple_GET_ITEM(args, 0) == GEVENT_CORE_EVENTS) {
py_events = PyInt_FromLong(revents); py_events = PyInt_FromLong(revents);
if (!py_events) { if (!py_events) {
gevent_handle_error(watcher->loop, (PyObject*)watcher); gevent_handle_error(loop, watcher);
goto end; goto end;
} }
PyTuple_SET_ITEM(args, 0, py_events); PyTuple_SET_ITEM(args, 0, py_events);
...@@ -104,47 +96,59 @@ static void gevent_callback(struct ev_loop *_loop, void *c_watcher, int revents) ...@@ -104,47 +96,59 @@ static void gevent_callback(struct ev_loop *_loop, void *c_watcher, int revents)
else { else {
py_events = NULL; py_events = NULL;
} }
/* The callback can clear watcher->args and thus drop reference of args to zero; result = PyObject_Call(callback, args, NULL);
* that's why we need to incref args above. */
result = PyObject_Call(watcher->_callback, args, NULL);
if (result) { if (result) {
Py_DECREF(result); Py_DECREF(result);
} }
else { else {
gevent_handle_error(watcher->loop, (PyObject*)watcher); gevent_handle_error(loop, watcher);
if (revents & (EV_READ|EV_WRITE)) { 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 */ /* 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; goto end;
} }
} }
if (!ev_is_active(c_watcher)) { if (!ev_is_active(c_watcher)) {
/* watcher will never be run again: calling stop() will clear 'callback' and 'args' */ /* watcher will never be run again: calling stop() will clear 'callback' and 'args' */
gevent_stop(watcher); gevent_stop(watcher, loop);
} }
end: end:
if (py_events) { if (py_events) {
Py_DECREF(py_events); Py_DECREF(py_events);
PyTuple_SET_ITEM(args, 0, GEVENT_CORE_EVENTS); PyTuple_SET_ITEM(args, 0, GEVENT_CORE_EVENTS);
} }
Py_DECREF((PyObject*)watcher); Py_DECREF(watcher);
Py_DECREF(args); Py_DECREF(args);
Py_DECREF(callback);
Py_DECREF(loop);
GIL_RELEASE; 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) { 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; GIL_ENSURE;
gevent_check_signals(GET_OBJECT(watcher, PyGeventLoopObject, _signal_checker)); gevent_check_signals(GET_OBJECT(PyGeventLoopObject, watcher, _signal_checker));
GIL_RELEASE; GIL_RELEASE;
} }
#if defined(_WIN32) #if defined(_WIN32)
static void gevent_periodic_signal_check(struct ev_loop *_loop, void *watcher, int revents) { static void gevent_periodic_signal_check(struct ev_loop *_loop, void *watcher, int revents) {
GIL_DECLARE;
GIL_ENSURE; GIL_ENSURE;
gevent_check_signals(GET_OBJECT(watcher, PyGeventLoopObject, _periodic_signal_checker)); gevent_check_signals(GET_OBJECT(PyGeventLoopObject, watcher, _periodic_signal_checker));
GIL_RELEASE; 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); static void gevent_signal_check(struct ev_loop *, void *, int);
struct PyGeventLoopObject; struct PyGeventLoopObject;
static void gevent_handle_error(struct PyGeventLoopObject* loop, PyObject* where); static void gevent_handle_error(struct PyGeventLoopObject* loop, PyObject* where);
......
...@@ -31,7 +31,12 @@ cdef extern from "frameobject.h": ...@@ -31,7 +31,12 @@ cdef extern from "frameobject.h":
PyThreadState* PyThreadState_GET() PyThreadState* PyThreadState_GET()
cdef extern from "callbacks.h": 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_signal_check(libev.ev_loop, void*, int)
void gevent_periodic_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 ...@@ -410,7 +415,7 @@ define(WATCHER_BASE, `cdef public loop loop
def __del__(self): def __del__(self):
self._callback = None self._callback = None
cpdef stop(self): def stop(self):
libev.ev_$1_stop(self.loop._ptr, &self._watcher) libev.ev_$1_stop(self.loop._ptr, &self._watcher)
self._callback = None self._callback = None
self.args = None self.args = None
...@@ -434,12 +439,6 @@ define(WATCHER_BASE, `cdef public loop loop ...@@ -434,12 +439,6 @@ define(WATCHER_BASE, `cdef public loop loop
libev.ev_set_priority(&self._watcher, priority) libev.ev_set_priority(&self._watcher, priority)
def feed(self, int revents, object callback, *args): 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.callback = callback
self.args = args self.args = args
libev.ev_feed_event(self.loop._ptr, &self._watcher, revents) libev.ev_feed_event(self.loop._ptr, &self._watcher, revents)
...@@ -453,12 +452,6 @@ define(ACTIVE, `property active: ...@@ -453,12 +452,6 @@ define(ACTIVE, `property active:
define(START, `def start(self, object callback, *args): 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.callback = callback
self.args = args self.args = args
libev.ev_$1_start(self.loop._ptr, &self._watcher) libev.ev_$1_start(self.loop._ptr, &self._watcher)
...@@ -473,7 +466,7 @@ define(WATCHER, `WATCHER_BASE($1) ...@@ -473,7 +466,7 @@ define(WATCHER, `WATCHER_BASE($1)
define(INIT, `def __init__(self, loop loop$2): 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.loop = loop
self._incref = 0') self._incref = 0')
...@@ -526,7 +519,7 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]: ...@@ -526,7 +519,7 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]:
IFDEF_WINDOWS() IFDEF_WINDOWS()
fd = _open_osfhandle(fd) fd = _open_osfhandle(fd)
ENDIF() 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.loop = loop
self._incref = 0 self._incref = 0
...@@ -538,7 +531,7 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]: ...@@ -538,7 +531,7 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]:
def __set__(self, int fd): def __set__(self, int fd):
if libev.ev_is_active(&self._watcher): if libev.ev_is_active(&self._watcher):
raise AttributeError("'io' watcher attribute 'fd' is read-only while watcher is active") 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: property events:
...@@ -548,7 +541,7 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]: ...@@ -548,7 +541,7 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]:
def __set__(self, int events): def __set__(self, int events):
if libev.ev_is_active(&self._watcher): if libev.ev_is_active(&self._watcher):
raise AttributeError("'io' watcher attribute 'events' is read-only while watcher is active") 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: property events_str:
...@@ -613,12 +606,6 @@ cdef public class callback(watcher) [object PyGeventCallbackObject, type PyGeven ...@@ -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) libev.ev_feed_event(self.loop._ptr, &self._watcher, libev.EV_CUSTOM)
INCREF 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: property active:
def __get__(self): 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