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

Go back to caching the watcher pointer.

parent 38451247
......@@ -22,9 +22,15 @@
cimport cython
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 python cimport *
from cpython.ref cimport Py_INCREF
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
# 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
return self.callback is not None
def __repr__(self):
if Py_ReprEnter(<PyObjectPtr>self) != 0:
if Py_ReprEnter(self) != 0:
return "<...>"
try:
format = self._format()
......@@ -612,7 +618,7 @@ cdef public class callback [object PyGeventCallbackObject, type PyGeventCallback
result += " stopped"
return result + ">"
finally:
Py_ReprLeave(<PyObjectPtr>self)
Py_ReprLeave(self)
def _format(self):
return ''
......@@ -634,12 +640,12 @@ DEF FLAG_WATCHER_MASK_UNREF_NEEDS_REF = 0x6
cdef void _python_incref(watcher self):
if not self._flags & FLAG_WATCHER_OWNS_PYREF:
Py_INCREF(<PyObjectPtr>self)
Py_INCREF(self)
self._flags |= FLAG_WATCHER_OWNS_PYREF
cdef void _python_decref(watcher self):
if self._flags & FLAG_WATCHER_OWNS_PYREF:
Py_DECREF(<PyObjectPtr>self)
Py_DECREF(self)
self._flags &= ~FLAG_WATCHER_OWNS_PYREF
cdef void _libev_ref(watcher self):
......@@ -676,28 +682,41 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
cdef public loop loop
cdef object _callback
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
# of a static struct or using the watcher's data pointer, we
# use an additional pointer of memory and incur an additional pointer copy
# on creation.
# But we use fewer pointer accesses for start/stop, and they have
# better cache locality. (Then again, we're bigger)
cdef start_and_stop __ss
cdef libev.ev_any_watcher _any_watcher
# better cache locality. (Then again, we're bigger).
# Right now we're going for size, so we use the pointer. IO/Timer objects
# are then 144 bytes.
cdef start_and_stop* __ss
def __init__(self, loop loop, ref=True, priority=None):
cdef libev.ev_watcher* w = self.__watcher()
if not w or not self.__ss.start or not self.__ss.stop:
if not self.__watcher or not self.__ss.start or not self.__ss.stop:
raise ValueError("Cannot construct a bare watcher")
self.loop = loop
self._flags = 0 if ref else FLAG_WATCHER_UNREF_BEFORE_START
if priority is not None:
libev.ev_set_priority(w, priority)
cdef libev.ev_watcher* __watcher(self):
# We define this as a function to save one pointer of storage
# in our struct.
return NULL
libev.ev_set_priority(self.__watcher, priority)
@property
def ref(self):
......@@ -720,7 +739,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
if not self.ref:
return # ref is already False
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)
self._flags |= FLAG_WATCHER_NEEDS_EVREF
......@@ -736,22 +755,22 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
@property
def priority(self):
return libev.ev_priority(self.__watcher())
return libev.ev_priority(self.__watcher)
@priority.setter
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):
raise AttributeError("Cannot set priority of an active watcher")
libev.ev_set_priority(w, priority)
@property
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
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):
self._watcher_start(callback, args)
......@@ -767,7 +786,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
self.args = args
_libev_unref(self)
_python_incref(self)
self.__ss.start(self.loop._ptr, self.__watcher())
self.__ss.start(self.loop._ptr, self.__watcher)
return 1
cpdef stop(self):
......@@ -777,7 +796,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
# so this is safe.
self._callback = None
self.args = None
self.__ss.stop(self.loop._ptr, self.__watcher())
self.__ss.stop(self.loop._ptr, self.__watcher)
_python_decref(self)
def feed(self, int revents, object callback, *args):
......@@ -785,11 +804,11 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
self.callback = callback
self.args = args
_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)
def __repr__(self):
if Py_ReprEnter(<PyObjectPtr>self) != 0:
if Py_ReprEnter(self) != 0:
return "<...>"
try:
format = self._format()
......@@ -804,7 +823,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
result += " args=%r" % (self.args, )
return result + ">"
finally:
Py_ReprLeave(<PyObjectPtr>self)
Py_ReprLeave(self)
def _format(self):
return ''
......@@ -841,14 +860,12 @@ cdef public class io(watcher) [object PyGeventIOObject, type PyGeventIO_Type]:
# All the vfd_functions are no-ops on POSIX
cdef int vfd = libev.vfd_open(fd)
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):
libev.vfd_free(self._watcher.fd)
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
@property
def fd(self):
return libev.vfd_get(self._watcher.fd)
......@@ -897,7 +914,8 @@ cdef public class timer(watcher) [object PyGeventTimerObject, type PyGeventTimer
if repeat < 0.0:
raise ValueError("repeat must be positive or zero: %r" % 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):
watcher.__init__(self, loop, ref, priority)
......@@ -918,8 +936,6 @@ cdef public class timer(watcher) [object PyGeventTimerObject, type PyGeventTimer
libev.ev_timer_again(self.loop._ptr, &self._watcher)
_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)
......@@ -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"
# we probably could check that in LIBEV_EMBED mode, but not in general
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):
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)
......@@ -954,10 +969,9 @@ cdef public class idle(watcher) [object PyGeventIdleObject, type PyGeventIdle_Ty
def __cinit__(self, loop loop, ref=True, priority=None):
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)
......@@ -968,10 +982,9 @@ cdef public class prepare(watcher) [object PyGeventPrepareObject, type PyGeventP
def __cinit__(self, loop loop, ref=True, priority=None):
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)
......@@ -982,10 +995,9 @@ cdef public class check(watcher) [object PyGeventCheckObject, type PyGeventCheck
def __cinit__(self, loop loop, ref=True, priority=None):
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)
......@@ -996,10 +1008,8 @@ cdef public class fork(watcher) [object PyGeventForkObject, type PyGeventFork_Ty
def __cinit__(self, loop loop, ref=True, priority=None):
libev.ev_fork_init(&self._watcher, <void*>gevent_callback_fork)
self.__ss = fork_ss
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
self.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &fork_ss
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
def __cinit__(self, loop loop, ref=True, priority=None):
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):
_check_loop(self.loop)
......@@ -1039,13 +1048,12 @@ cdef public class child(watcher) [object PyGeventChildObject, type PyGeventChild
raise TypeError('child watchers are only available on the default loop')
libev.gevent_install_sigchld_handler()
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):
watcher.__init__(self, loop, ref, None)
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
def _format(self):
return ' pid=%r rstatus=%r' % (self.pid, self.rstatus)
......@@ -1091,13 +1099,12 @@ cdef public class stat(watcher) [object PyGeventStatObject, type PyGeventStat_Ty
paths = <bytes>path
self._paths = paths
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):
watcher.__init__(self, loop, ref, priority)
cdef libev.ev_watcher* __watcher(self):
return <libev.ev_watcher*>&self._watcher
@property
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