Commit aebf5c51 authored by Jason Madden's avatar Jason Madden

Per discussion in #248, start writing more CFFI in C instead of Python. This...

Per discussion in #248, start writing more CFFI in C instead of Python. This commit gets the individual watcher callbacks into C
parent 1b5a23cf
...@@ -29,7 +29,7 @@ def st_nlink_type(): ...@@ -29,7 +29,7 @@ def st_nlink_type():
from cffi import FFI from cffi import FFI
ffi = FFI() ffi = FFI()
ffi.cdef(""" _cdef = """
#define EV_MINPRI ... #define EV_MINPRI ...
#define EV_MAXPRI ... #define EV_MAXPRI ...
...@@ -204,12 +204,20 @@ void gevent_install_sigchld_handler(); ...@@ -204,12 +204,20 @@ void gevent_install_sigchld_handler();
void (*gevent_noop)(struct ev_loop *_loop, struct ev_timer *w, int revents); void (*gevent_noop)(struct ev_loop *_loop, struct ev_timer *w, int revents);
void ev_sleep (ev_tstamp delay); /* sleep for a while */ void ev_sleep (ev_tstamp delay); /* sleep for a while */
""") """
thisdir = os.path.dirname(os.path.realpath(__file__)) _watcher_types = ['ev_io',
include_dirs = [thisdir, os.path.join(thisdir, 'libev')] 'ev_timer',
libev = C = ffi.verify(""" // passed to the real C compiler 'ev_signal',
'ev_prepare',
'ev_check',
'ev_fork',
'ev_async',
'ev_child',
'ev_stat',]
_source = """ // passed to the real C compiler
#define LIBEV_EMBED 1 #define LIBEV_EMBED 1
#include "libev.h" #include "libev.h"
...@@ -217,12 +225,94 @@ static void ...@@ -217,12 +225,94 @@ static void
_gevent_noop(struct ev_loop *_loop, struct ev_timer *w, int revents) { } _gevent_noop(struct ev_loop *_loop, struct ev_timer *w, int revents) { }
void (*gevent_noop)(struct ev_loop *, struct ev_timer *, int) = &_gevent_noop; void (*gevent_noop)(struct ev_loop *, struct ev_timer *, int) = &_gevent_noop;
""", include_dirs=include_dirs) """
del thisdir, include_dirs
# Setup the watcher callbacks
_cbs = """
static int (*python_callback)(void* handle, int revents);
static void (*python_handle_error)(void* handle, int revents);
static void (*python_stop)(void* handle);
"""
_cdef += _cbs
_source += _cbs
for _watcher_type in _watcher_types:
_cdef += """
struct gevent_%s {
struct %s watcher;
void* handle;
...;
};
static void _gevent_%s_callback(struct ev_loop* loop, struct %s* watcher, int revents);
""" %(_watcher_type, _watcher_type, _watcher_type, _watcher_type)
_source += """
struct gevent_%s {
struct %s watcher;
void* handle;
};
""" %(_watcher_type, _watcher_type)
_source += """
static void _gevent_%s_callback(struct ev_loop* loop, struct %s* watcher, int revents)
{
// invoke self.callback()
void* handle = ((struct gevent_%s *)watcher)->handle;
if( python_callback(handle, revents) < 0) {
/* in case of exception, call self.loop.handle_error */
python_handle_error(handle, revents);
}
// Code to stop the event
if (!ev_is_active(watcher)) {
python_stop(handle);
}
}
""" % (_watcher_type, _watcher_type, _watcher_type)
thisdir = os.path.dirname(os.path.realpath(__file__))
include_dirs = [thisdir, os.path.join(thisdir, 'libev')]
ffi.cdef(_cdef)
libev = C = ffi.verify(_source, include_dirs=include_dirs)
del thisdir, include_dirs, _watcher_type, _watcher_types
libev.vfd_open = libev.vfd_get = lambda fd: fd libev.vfd_open = libev.vfd_get = lambda fd: fd
libev.vfd_free = lambda fd: None libev.vfd_free = lambda fd: None
@ffi.callback("int(void* handle, int revents)")
def _python_callback(handle, revents):
watcher = ffi.from_handle(handle)
try:
watcher.callback(*watcher.args)
except:
watcher._exc_info = sys.exc_info()
return -1
else:
return 0
libev.python_callback = _python_callback
@ffi.callback("void(void* handle, int revents)")
def _python_handle_error(handle, revents):
watcher = ffi.from_handle(handle)
exc_info = watcher._exc_info
del watcher._exc_info
try:
watcher.loop.handle_error(watcher, *exc_info)
finally:
if revents & (libev.EV_READ | libev.EV_WRITE):
try:
watcher.stop()
except:
watcher.loop.handle_error(watcher, *sys.exc_info())
return
libev.python_handle_error = _python_handle_error
@ffi.callback("void(void* handle)")
def _python_stop(handle):
watcher = ffi.from_handle(handle)
watcher.stop()
libev.python_stop = _python_stop
UNDEF = libev.EV_UNDEF UNDEF = libev.EV_UNDEF
NONE = libev.EV_NONE NONE = libev.EV_NONE
...@@ -717,6 +807,7 @@ class callback(object): ...@@ -717,6 +807,7 @@ class callback(object):
def __nonzero__(self): def __nonzero__(self):
# it's nonzero if it's pending or currently executing # it's nonzero if it's pending or currently executing
return self.args is not None return self.args is not None
__bool__ = __nonzero__
@property @property
def pending(self): def pending(self):
...@@ -736,11 +827,15 @@ class watcher(object): ...@@ -736,11 +827,15 @@ class watcher(object):
self._flags = 4 self._flags = 4
self.args = None self.args = None
self._callback = None self._callback = None
self._watcher = ffi.new(self._watcher_ffi_type) self._handle = ffi.new_handle(self)
self._cb = ffi.callback(self._watcher_ffi_cb, _loop._wrap_cb(self._run_callback)) self._gwatcher = ffi.new('struct gevent_' + self._watcher_type + '*')
self._watcher = ffi.addressof(self._gwatcher.watcher)
self._gwatcher.handle = self._handle
if priority is not None: if priority is not None:
libev.ev_set_priority(self._watcher, priority) libev.ev_set_priority(self._watcher, priority)
self._watcher_init(self._watcher, self._cb, *args) self._watcher_init(self._watcher,
getattr(libev, '_gevent_' + self._watcher_type + '_callback'),
*args)
# this is not needed, since we keep alive the watcher while it's started # this is not needed, since we keep alive the watcher while it's started
#def __del__(self): #def __del__(self):
...@@ -762,26 +857,6 @@ class watcher(object): ...@@ -762,26 +857,6 @@ class watcher(object):
def _format(self): def _format(self):
return '' return ''
def _run_callback(self, loop, c_watcher, revents):
try:
self.callback(*self.args)
except:
try:
self.loop.handle_error(self, *sys.exc_info())
finally:
if revents & (libev.EV_READ | libev.EV_WRITE):
# /* io watcher: not stopping it may cause the failing callback to be called repeatedly */
try:
self.stop()
except:
self.loop.handle_error(self, *sys.exc_info())
return
# callbacks' self.active differs from ev_is_active(...) at
# this point. don't use it!
if not libev.ev_is_active(c_watcher):
self.stop()
def _libev_unref(self): def _libev_unref(self):
if self._flags & 6 == 4: if self._flags & 6 == 4:
self.loop.unref() self.loop.unref()
...@@ -869,8 +944,6 @@ class io(watcher): ...@@ -869,8 +944,6 @@ class io(watcher):
_watcher_stop = libev.ev_io_stop _watcher_stop = libev.ev_io_stop
_watcher_init = libev.ev_io_init _watcher_init = libev.ev_io_init
_watcher_type = 'ev_io' _watcher_type = 'ev_io'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
def __init__(self, loop, fd, events, ref=True, priority=None): def __init__(self, loop, fd, events, ref=True, priority=None):
if fd < 0: if fd < 0:
...@@ -914,8 +987,6 @@ class timer(watcher): ...@@ -914,8 +987,6 @@ class timer(watcher):
_watcher_stop = libev.ev_timer_stop _watcher_stop = libev.ev_timer_stop
_watcher_init = libev.ev_timer_init _watcher_init = libev.ev_timer_init
_watcher_type = 'ev_timer' _watcher_type = 'ev_timer'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
def __init__(self, loop, after=0.0, repeat=0.0, ref=True, priority=None): def __init__(self, loop, after=0.0, repeat=0.0, ref=True, priority=None):
if repeat < 0.0: if repeat < 0.0:
...@@ -955,8 +1026,6 @@ class signal(watcher): ...@@ -955,8 +1026,6 @@ class signal(watcher):
_watcher_stop = libev.ev_signal_stop _watcher_stop = libev.ev_signal_stop
_watcher_init = libev.ev_signal_init _watcher_init = libev.ev_signal_init
_watcher_type = 'ev_signal' _watcher_type = 'ev_signal'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
def __init__(self, loop, signalnum, ref=True, priority=None): def __init__(self, loop, signalnum, ref=True, priority=None):
if signalnum < 1 or signalnum >= signalmodule.NSIG: if signalnum < 1 or signalnum >= signalmodule.NSIG:
...@@ -974,8 +1043,6 @@ class idle(watcher): ...@@ -974,8 +1043,6 @@ class idle(watcher):
_watcher_stop = libev.ev_idle_stop _watcher_stop = libev.ev_idle_stop
_watcher_init = libev.ev_idle_init _watcher_init = libev.ev_idle_init
_watcher_type = 'ev_idle' _watcher_type = 'ev_idle'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
class prepare(watcher): class prepare(watcher):
...@@ -983,8 +1050,6 @@ class prepare(watcher): ...@@ -983,8 +1050,6 @@ class prepare(watcher):
_watcher_stop = libev.ev_prepare_stop _watcher_stop = libev.ev_prepare_stop
_watcher_init = libev.ev_prepare_init _watcher_init = libev.ev_prepare_init
_watcher_type = 'ev_prepare' _watcher_type = 'ev_prepare'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
class check(watcher): class check(watcher):
...@@ -992,8 +1057,6 @@ class check(watcher): ...@@ -992,8 +1057,6 @@ class check(watcher):
_watcher_stop = libev.ev_check_stop _watcher_stop = libev.ev_check_stop
_watcher_init = libev.ev_check_init _watcher_init = libev.ev_check_init
_watcher_type = 'ev_check' _watcher_type = 'ev_check'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
class fork(watcher): class fork(watcher):
...@@ -1001,8 +1064,6 @@ class fork(watcher): ...@@ -1001,8 +1064,6 @@ class fork(watcher):
_watcher_stop = libev.ev_fork_stop _watcher_stop = libev.ev_fork_stop
_watcher_init = libev.ev_fork_init _watcher_init = libev.ev_fork_init
_watcher_type = 'ev_fork' _watcher_type = 'ev_fork'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
class async(watcher): class async(watcher):
...@@ -1010,8 +1071,6 @@ class async(watcher): ...@@ -1010,8 +1071,6 @@ class async(watcher):
_watcher_stop = libev.ev_async_stop _watcher_stop = libev.ev_async_stop
_watcher_init = libev.ev_async_init _watcher_init = libev.ev_async_init
_watcher_type = 'ev_async' _watcher_type = 'ev_async'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
def send(self): def send(self):
libev.ev_async_send(self.loop._ptr, self._watcher) libev.ev_async_send(self.loop._ptr, self._watcher)
...@@ -1026,8 +1085,6 @@ class child(watcher): ...@@ -1026,8 +1085,6 @@ class child(watcher):
_watcher_stop = libev.ev_child_stop _watcher_stop = libev.ev_child_stop
_watcher_init = libev.ev_child_init _watcher_init = libev.ev_child_init
_watcher_type = 'ev_child' _watcher_type = 'ev_child'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
def __init__(self, loop, pid, trace=0, ref=True): def __init__(self, loop, pid, trace=0, ref=True):
if not loop.default: if not loop.default:
...@@ -1064,8 +1121,6 @@ class stat(watcher): ...@@ -1064,8 +1121,6 @@ class stat(watcher):
_watcher_stop = libev.ev_stat_stop _watcher_stop = libev.ev_stat_stop
_watcher_init = libev.ev_stat_init _watcher_init = libev.ev_stat_init
_watcher_type = 'ev_stat' _watcher_type = 'ev_stat'
_watcher_ffi_type = "struct %s *" % _watcher_type
_watcher_ffi_cb = "void(*)(struct ev_loop *, struct %s *, int)" % _watcher_type
def __init__(self, _loop, path, interval=0.0, ref=True, priority=None): def __init__(self, _loop, path, interval=0.0, ref=True, priority=None):
if not isinstance(path, bytes): if not isinstance(path, bytes):
......
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