Commit 7a24cc11 authored by Jason Madden's avatar Jason Madden

Go back to caching the watcher pointer.

parent 38451247
...@@ -22,9 +22,15 @@ ...@@ -22,9 +22,15 @@
cimport cython cimport cython
cimport libev cimport libev
# Note this is not the standard cython 'cpython' (which has a backwards compat alias of 'python')
# it's our custom def. If it's not on the include path, we get warned. from cpython.ref cimport Py_INCREF
from python cimport * from cpython.ref cimport Py_DECREF
from cpython.mem cimport PyMem_Malloc
from cpython.mem cimport PyMem_Free
cdef extern from "Python.h":
int Py_ReprEnter(object)
void Py_ReprLeave(object)
# Work around lack of absolute_import in Cython # Work around lack of absolute_import in Cython
# Note for PY3: not doing so will leave reference to locals() on import # Note for PY3: not doing so will leave reference to locals() on import
...@@ -597,7 +603,7 @@ cdef public class callback [object PyGeventCallbackObject, type PyGeventCallback ...@@ -597,7 +603,7 @@ cdef public class callback [object PyGeventCallbackObject, type PyGeventCallback
return self.callback is not None return self.callback is not None
def __repr__(self): def __repr__(self):
if Py_ReprEnter(<PyObjectPtr>self) != 0: if Py_ReprEnter(self) != 0:
return "<...>" return "<...>"
try: try:
format = self._format() format = self._format()
...@@ -612,7 +618,7 @@ cdef public class callback [object PyGeventCallbackObject, type PyGeventCallback ...@@ -612,7 +618,7 @@ cdef public class callback [object PyGeventCallbackObject, type PyGeventCallback
result += " stopped" result += " stopped"
return result + ">" return result + ">"
finally: finally:
Py_ReprLeave(<PyObjectPtr>self) Py_ReprLeave(self)
def _format(self): def _format(self):
return '' return ''
...@@ -634,12 +640,12 @@ DEF FLAG_WATCHER_MASK_UNREF_NEEDS_REF = 0x6 ...@@ -634,12 +640,12 @@ DEF FLAG_WATCHER_MASK_UNREF_NEEDS_REF = 0x6
cdef void _python_incref(watcher self): cdef void _python_incref(watcher self):
if not self._flags & FLAG_WATCHER_OWNS_PYREF: if not self._flags & FLAG_WATCHER_OWNS_PYREF:
Py_INCREF(<PyObjectPtr>self) Py_INCREF(self)
self._flags |= FLAG_WATCHER_OWNS_PYREF self._flags |= FLAG_WATCHER_OWNS_PYREF
cdef void _python_decref(watcher self): cdef void _python_decref(watcher self):
if self._flags & FLAG_WATCHER_OWNS_PYREF: if self._flags & FLAG_WATCHER_OWNS_PYREF:
Py_DECREF(<PyObjectPtr>self) Py_DECREF(self)
self._flags &= ~FLAG_WATCHER_OWNS_PYREF self._flags &= ~FLAG_WATCHER_OWNS_PYREF
cdef void _libev_ref(watcher self): cdef void _libev_ref(watcher self):
...@@ -676,28 +682,41 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty ...@@ -676,28 +682,41 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
cdef public loop loop cdef public loop loop
cdef object _callback cdef object _callback
cdef public tuple args cdef public tuple args
# By keeping a __watcher cached, the size of the io and timer
# structs becomes 152 bytes and child is 160 and stat is 512 (when
# the start_and_stop is inlined). On 64-bit macOS CPython 2.7. I
# hoped that using libev's data pointer and allocating the
# watchers directly and not as inline members would result in
# overall savings thanks to better padding, but it didn't. And it
# added lots of casts, making the code ugly.
# Table:
# gevent ver | 1.2 | This | +data
# Watcher Kind | | |
# Timer | 120 | 152 | 160
# IO | 120 | 152 | 160
# Child | 128 | 160 | 168
# Stat | 480 | 512 | 512
cdef libev.ev_watcher* __watcher
# By inlining the start_and_stop struct, instead of taking the address # By inlining the start_and_stop struct, instead of taking the address
# of a static struct or using the watcher's data pointer, we # of a static struct or using the watcher's data pointer, we
# use an additional pointer of memory and incur an additional pointer copy # use an additional pointer of memory and incur an additional pointer copy
# on creation. # on creation.
# But we use fewer pointer accesses for start/stop, and they have # But we use fewer pointer accesses for start/stop, and they have
# better cache locality. (Then again, we're bigger) # better cache locality. (Then again, we're bigger).
cdef start_and_stop __ss # Right now we're going for size, so we use the pointer. IO/Timer objects
cdef libev.ev_any_watcher _any_watcher # are then 144 bytes.
cdef start_and_stop* __ss
def __init__(self, loop loop, ref=True, priority=None): def __init__(self, loop loop, ref=True, priority=None):
cdef libev.ev_watcher* w = self.__watcher() if not self.__watcher or not self.__ss.start or not self.__ss.stop:
if not w or not self.__ss.start or not self.__ss.stop:
raise ValueError("Cannot construct a bare watcher") raise ValueError("Cannot construct a bare watcher")
self.loop = loop self.loop = loop
self._flags = 0 if ref else FLAG_WATCHER_UNREF_BEFORE_START self._flags = 0 if ref else FLAG_WATCHER_UNREF_BEFORE_START
if priority is not None: if priority is not None:
libev.ev_set_priority(w, priority) libev.ev_set_priority(self.__watcher, priority)
cdef libev.ev_watcher* __watcher(self):
# We define this as a function to save one pointer of storage
# in our struct.
return NULL
@property @property
def ref(self): def ref(self):
...@@ -720,7 +739,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty ...@@ -720,7 +739,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
if not self.ref: if not self.ref:
return # ref is already False return # ref is already False
self._flags |= FLAG_WATCHER_UNREF_BEFORE_START self._flags |= FLAG_WATCHER_UNREF_BEFORE_START
if not self._flags & FLAG_WATCHER_NEEDS_EVREF and libev.ev_is_active(self.__watcher()): if not self._flags & FLAG_WATCHER_NEEDS_EVREF and libev.ev_is_active(self.__watcher):
libev.ev_unref(self.loop._ptr) libev.ev_unref(self.loop._ptr)
self._flags |= FLAG_WATCHER_NEEDS_EVREF self._flags |= FLAG_WATCHER_NEEDS_EVREF
...@@ -736,22 +755,22 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty ...@@ -736,22 +755,22 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
@property @property
def priority(self): def priority(self):
return libev.ev_priority(self.__watcher()) return libev.ev_priority(self.__watcher)
@priority.setter @priority.setter
def priority(self, int priority): def priority(self, int priority):
cdef libev.ev_watcher* w = self.__watcher() cdef libev.ev_watcher* w = self.__watcher
if libev.ev_is_active(w): if libev.ev_is_active(w):
raise AttributeError("Cannot set priority of an active watcher") raise AttributeError("Cannot set priority of an active watcher")
libev.ev_set_priority(w, priority) libev.ev_set_priority(w, priority)
@property @property
def active(self): def active(self):
return True if libev.ev_is_active(self.__watcher()) else False return True if libev.ev_is_active(self.__watcher) else False
@property @property
def pending(self): def pending(self):
return True if libev.ev_is_pending(self.__watcher()) else False return True if libev.ev_is_pending(self.__watcher) else False
def start(self, object callback, *args): def start(self, object callback, *args):
self._watcher_start(callback, args) self._watcher_start(callback, args)
...@@ -767,7 +786,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty ...@@ -767,7 +786,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
self.args = args self.args = args
_libev_unref(self) _libev_unref(self)
_python_incref(self) _python_incref(self)
self.__ss.start(self.loop._ptr, self.__watcher()) self.__ss.start(self.loop._ptr, self.__watcher)
return 1 return 1
cpdef stop(self): cpdef stop(self):
...@@ -777,7 +796,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty ...@@ -777,7 +796,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
# so this is safe. # so this is safe.
self._callback = None self._callback = None
self.args = None self.args = None
self.__ss.stop(self.loop._ptr, self.__watcher()) self.__ss.stop(self.loop._ptr, self.__watcher)
_python_decref(self) _python_decref(self)
def feed(self, int revents, object callback, *args): def feed(self, int revents, object callback, *args):
...@@ -785,11 +804,11 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty ...@@ -785,11 +804,11 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
self.callback = callback self.callback = callback
self.args = args self.args = args
_libev_unref(self) _libev_unref(self)
libev.ev_feed_event(self.loop._ptr, self.__watcher(), revents) libev.ev_feed_event(self.loop._ptr, self.__watcher, revents)
_python_incref(self) _python_incref(self)
def __repr__(self): def __repr__(self):
if Py_ReprEnter(<PyObjectPtr>self) != 0: if Py_ReprEnter(self) != 0:
return "<...>" return "<...>"
try: try:
format = self._format() format = self._format()
...@@ -804,7 +823,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty ...@@ -804,7 +823,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
result += " args=%r" % (self.args, ) result += " args=%r" % (self.args, )
return result + ">" return result + ">"
finally: finally:
Py_ReprLeave(<PyObjectPtr>self) Py_ReprLeave(self)
def _format(self): def _format(self):
return '' return ''
...@@ -841,14 +860,12 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]: ...@@ -841,14 +860,12 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]:
# All the vfd_functions are no-ops on POSIX # All the vfd_functions are no-ops on POSIX
cdef int vfd = libev.vfd_open(fd) cdef int vfd = libev.vfd_open(fd)
libev.ev_io_init(&self._watcher, <void *>gevent_callback_io, vfd, events) libev.ev_io_init(&self._watcher, <void *>gevent_callback_io, vfd, events)
self.__ss = io_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &io_ss
def __dealloc__(self): def __dealloc__(self):
libev.vfd_free(self._watcher.fd) libev.vfd_free(self._watcher.fd)
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
@property @property
def fd(self): def fd(self):
return libev.vfd_get(self._watcher.fd) return libev.vfd_get(self._watcher.fd)
...@@ -897,7 +914,8 @@ cdef public class timer(watcher) [object PyGeventTimerObject, type PyGeventTimer ...@@ -897,7 +914,8 @@ cdef public class timer(watcher) [object PyGeventTimerObject, type PyGeventTimer
if repeat < 0.0: if repeat < 0.0:
raise ValueError("repeat must be positive or zero: %r" % repeat) raise ValueError("repeat must be positive or zero: %r" % repeat)
libev.ev_timer_init(&self._watcher, <void *>gevent_callback_timer, after, repeat) libev.ev_timer_init(&self._watcher, <void *>gevent_callback_timer, after, repeat)
self.__ss = timer_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &timer_ss
def __init__(self, loop loop, double after=0.0, double repeat=0.0, ref=True, priority=None): def __init__(self, loop loop, double after=0.0, double repeat=0.0, ref=True, priority=None):
watcher.__init__(self, loop, ref, priority) watcher.__init__(self, loop, ref, priority)
...@@ -918,8 +936,6 @@ cdef public class timer(watcher) [object PyGeventTimerObject, type PyGeventTimer ...@@ -918,8 +936,6 @@ cdef public class timer(watcher) [object PyGeventTimerObject, type PyGeventTimer
libev.ev_timer_again(self.loop._ptr, &self._watcher) libev.ev_timer_again(self.loop._ptr, &self._watcher)
_python_incref(self) _python_incref(self)
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
cdef start_and_stop signal_ss = make_ss(<void*>libev.ev_signal_start, <void*>libev.ev_signal_stop) cdef start_and_stop signal_ss = make_ss(<void*>libev.ev_signal_start, <void*>libev.ev_signal_stop)
...@@ -937,13 +953,12 @@ cdef public class signal(watcher) [object PyGeventSignalObject, type PyGeventSig ...@@ -937,13 +953,12 @@ cdef public class signal(watcher) [object PyGeventSignalObject, type PyGeventSig
# 2) "libev: a signal must not be attached to two different loops" # 2) "libev: a signal must not be attached to two different loops"
# we probably could check that in LIBEV_EMBED mode, but not in general # we probably could check that in LIBEV_EMBED mode, but not in general
libev.ev_signal_init(&self._watcher, <void *>gevent_callback_signal, signalnum) libev.ev_signal_init(&self._watcher, <void *>gevent_callback_signal, signalnum)
self.__ss = signal_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &signal_ss
def __init__(self, loop loop, int signalnum, ref=True, priority=None): def __init__(self, loop loop, int signalnum, ref=True, priority=None):
watcher.__init__(self, loop, ref, priority) watcher.__init__(self, loop, ref, priority)
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
cdef start_and_stop idle_ss = make_ss(<void*>libev.ev_idle_start, <void*>libev.ev_idle_stop) cdef start_and_stop idle_ss = make_ss(<void*>libev.ev_idle_start, <void*>libev.ev_idle_stop)
...@@ -954,10 +969,9 @@ cdef public class idle(watcher) [object PyGeventIdleObject, type PyGeventIdle_Ty ...@@ -954,10 +969,9 @@ cdef public class idle(watcher) [object PyGeventIdleObject, type PyGeventIdle_Ty
def __cinit__(self, loop loop, ref=True, priority=None): def __cinit__(self, loop loop, ref=True, priority=None):
libev.ev_idle_init(&self._watcher, <void*>gevent_callback_idle) libev.ev_idle_init(&self._watcher, <void*>gevent_callback_idle)
self.__ss = idle_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &idle_ss
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
cdef start_and_stop prepare_ss = make_ss(<void*>libev.ev_prepare_start, <void*>libev.ev_prepare_stop) cdef start_and_stop prepare_ss = make_ss(<void*>libev.ev_prepare_start, <void*>libev.ev_prepare_stop)
...@@ -968,10 +982,9 @@ cdef public class prepare(watcher) [object PyGeventPrepareObject, type PyGeventP ...@@ -968,10 +982,9 @@ cdef public class prepare(watcher) [object PyGeventPrepareObject, type PyGeventP
def __cinit__(self, loop loop, ref=True, priority=None): def __cinit__(self, loop loop, ref=True, priority=None):
libev.ev_prepare_init(&self._watcher, <void*>gevent_callback_prepare) libev.ev_prepare_init(&self._watcher, <void*>gevent_callback_prepare)
self.__ss = prepare_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &prepare_ss
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
cdef start_and_stop check_ss = make_ss(<void*>libev.ev_check_start, <void*>libev.ev_check_stop) cdef start_and_stop check_ss = make_ss(<void*>libev.ev_check_start, <void*>libev.ev_check_stop)
...@@ -982,10 +995,9 @@ cdef public class check(watcher) [object PyGeventCheckObject, type PyGeventCheck ...@@ -982,10 +995,9 @@ cdef public class check(watcher) [object PyGeventCheckObject, type PyGeventCheck
def __cinit__(self, loop loop, ref=True, priority=None): def __cinit__(self, loop loop, ref=True, priority=None):
libev.ev_check_init(&self._watcher, <void*>gevent_callback_check) libev.ev_check_init(&self._watcher, <void*>gevent_callback_check)
self.__ss = check_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &check_ss
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
cdef start_and_stop fork_ss = make_ss(<void*>libev.ev_fork_start, <void*>libev.ev_fork_stop) cdef start_and_stop fork_ss = make_ss(<void*>libev.ev_fork_start, <void*>libev.ev_fork_stop)
...@@ -996,10 +1008,8 @@ cdef public class fork(watcher) [object PyGeventForkObject, type PyGeventFork_Ty ...@@ -996,10 +1008,8 @@ cdef public class fork(watcher) [object PyGeventForkObject, type PyGeventFork_Ty
def __cinit__(self, loop loop, ref=True, priority=None): def __cinit__(self, loop loop, ref=True, priority=None):
libev.ev_fork_init(&self._watcher, <void*>gevent_callback_fork) libev.ev_fork_init(&self._watcher, <void*>gevent_callback_fork)
self.__ss = fork_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &fork_ss
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
cdef start_and_stop async_ss = make_ss(<void*>libev.ev_async_start, <void*>libev.ev_async_stop) cdef start_and_stop async_ss = make_ss(<void*>libev.ev_async_start, <void*>libev.ev_async_stop)
...@@ -1015,10 +1025,9 @@ cdef public class async_(watcher) [object PyGeventAsyncObject, type PyGeventAsyn ...@@ -1015,10 +1025,9 @@ cdef public class async_(watcher) [object PyGeventAsyncObject, type PyGeventAsyn
def __cinit__(self, loop loop, ref=True, priority=None): def __cinit__(self, loop loop, ref=True, priority=None):
libev.ev_async_init(&self._watcher, <void*>gevent_callback_async) libev.ev_async_init(&self._watcher, <void*>gevent_callback_async)
self.__ss = async_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &async_ss
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
def send(self): def send(self):
_check_loop(self.loop) _check_loop(self.loop)
...@@ -1039,13 +1048,12 @@ cdef public class child(watcher) [object PyGeventChildObject, type PyGeventChild ...@@ -1039,13 +1048,12 @@ cdef public class child(watcher) [object PyGeventChildObject, type PyGeventChild
raise TypeError('child watchers are only available on the default loop') raise TypeError('child watchers are only available on the default loop')
libev.gevent_install_sigchld_handler() libev.gevent_install_sigchld_handler()
libev.ev_child_init(&self._watcher, <void *>gevent_callback_child, pid, trace) libev.ev_child_init(&self._watcher, <void *>gevent_callback_child, pid, trace)
self.__ss = child_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &child_ss
def __init__(self, loop loop, int pid, bint trace=0, ref=True): def __init__(self, loop loop, int pid, bint trace=0, ref=True):
watcher.__init__(self, loop, ref, None) watcher.__init__(self, loop, ref, None)
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
def _format(self): def _format(self):
return ' pid=%r rstatus=%r' % (self.pid, self.rstatus) return ' pid=%r rstatus=%r' % (self.pid, self.rstatus)
...@@ -1091,13 +1099,12 @@ cdef public class stat(watcher) [object PyGeventStatObject, type PyGeventStat_Ty ...@@ -1091,13 +1099,12 @@ cdef public class stat(watcher) [object PyGeventStatObject, type PyGeventStat_Ty
paths = <bytes>path paths = <bytes>path
self._paths = paths self._paths = paths
libev.ev_stat_init(&self._watcher, <void *>gevent_callback_stat, <char*>paths, interval) libev.ev_stat_init(&self._watcher, <void *>gevent_callback_stat, <char*>paths, interval)
self.__ss = stat_ss self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &stat_ss
def __init__(self, loop loop, str path, float interval=0.0, ref=True, priority=None): def __init__(self, loop loop, str path, float interval=0.0, ref=True, priority=None):
watcher.__init__(self, loop, ref, priority) watcher.__init__(self, loop, ref, priority)
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
@property @property
def attr(self): def attr(self):
......
cdef extern from "Python.h":
struct PyObject:
pass
ctypedef PyObject* PyObjectPtr "PyObject*"
void Py_INCREF(PyObjectPtr)
void Py_DECREF(PyObjectPtr)
void Py_XDECREF(PyObjectPtr)
int Py_ReprEnter(PyObjectPtr)
void Py_ReprLeave(PyObjectPtr)
int PyCallable_Check(PyObjectPtr)
cdef extern from "frameobject.h":
ctypedef struct PyThreadState:
PyObjectPtr exc_type
PyObjectPtr exc_value
PyObjectPtr exc_traceback
PyThreadState* PyThreadState_GET()
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