Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix compilation with Cython 3 #1603

Merged
merged 3 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Fix compilation with Cython 3.
The double-dunder name changes broke some things.

Fixes #1599
  • Loading branch information
jamadden committed May 6, 2020
commit 1ef22cc9ad3f5c1d2750e7ae9101058014e5d31b
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ jobs:
# First, the build dependencies (see setup.cfg)
# so that we don't have to use build isolation and can better use the cache;
# Note that we can't use -U for cffi and greenlet on PyPy.
- &build-gevent-deps pip install -U setuptools wheel twine && pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"' 'cffi;platform_python_implementation=="CPython"' cython 'greenlet;platform_python_implementation=="CPython"'
- &build-gevent-deps pip install -U setuptools wheel twine && pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"' 'cffi;platform_python_implementation=="CPython"' 'cython>=3.0a4' 'greenlet;platform_python_implementation=="CPython"'
# Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure
# output (pip install uses a random temporary directory, making this difficult)
- python setup.py bdist_wheel
Expand Down
2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ build_script:
# Build the compiled extension
# Try to get some things that don't wind up in the pip cache as
# built wheels if they're built during an isolated build.
- "%CMD_IN_ENV% %PYEXE% -m pip install -U wheel cython setuptools cffi"
- "%CMD_IN_ENV% %PYEXE% -m pip install -U --pre wheel cython setuptools cffi"
- if not "%GWHEEL_ONLY%"=="true" %PYEXE% -m pip install -U -e .[test]

test_script:
Expand Down
4 changes: 4 additions & 0 deletions docs/changes/1599.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
gevent can now be built using Cython 3.0a2 and newer.

The libev extension was incompatible with this. As part of this,
certain internal, undocumented names have been changed.
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ requires = [
# name to be created so that we can have both foo.py and _foo.so
# at the same time. 0.29 fixes some issues with Python 3.7,
# and adds the 3str mode for transition to Python 3. 0.29.14+ is
# required for Python 3.8. As of now, we can't build with Cython 3.0a3
# https://github.com/gevent/gevent/issues/1599
"Cython >= 0.29.14, < 3",
# required for Python 3.8.
"Cython >= 3.0a4",
# See version requirements in setup.py
"cffi >= 1.12.3 ; platform_python_implementation == 'CPython'",
# Python 3.7 requires at least 0.4.14, which is ABI incompatible with earlier
Expand Down
82 changes: 41 additions & 41 deletions src/gevent/libev/corecext.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
self._ptr = libev.ev_loop_new(c_flags)
if not self._ptr:
raise SystemError("ev_loop_new(%s) failed" % (c_flags, ))
if default or __SYSERR_CALLBACK is None:
if default or SYSERR_CALLBACK is None:
set_syserr_cb(self._handle_syserr)

# Mark as not destroyed
Expand Down Expand Up @@ -514,7 +514,7 @@ cdef public class loop [object PyGeventLoopObject, type PyGeventLoop_Type]:
# Mark as destroyed
libev.ev_set_userdata(ptr, NULL)
self._stop_watchers(ptr)
if __SYSERR_CALLBACK == self._handle_syserr:
if SYSERR_CALLBACK == self._handle_syserr:
set_syserr_cb(None)
libev.ev_loop_destroy(ptr)

Expand Down Expand Up @@ -835,7 +835,7 @@ cdef bint _watcher_start(watcher self, object callback, tuple args) except -1:
self.args = args
_libev_unref(self)
_python_incref(self)
self.__ss.start(self.loop._ptr, self.__watcher)
self._w_ss.start(self.loop._ptr, self._w_watcher)
return 1

cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Type]:
Expand All @@ -845,7 +845,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
cdef object _callback
cdef public tuple args

# By keeping a __watcher cached, the size of the io and timer
# By keeping a _w_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
Expand All @@ -860,7 +860,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
# IO | 120 | 152 | 160
# Child | 128 | 160 | 168
# Stat | 480 | 512 | 512
cdef libev.ev_watcher* __watcher
cdef libev.ev_watcher* _w_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
Expand All @@ -870,7 +870,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
# 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
cdef start_and_stop* _w_ss

## Int members

Expand All @@ -884,12 +884,12 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
cdef readonly unsigned int _flags

def __init__(self, loop loop, ref=True, priority=None):
if not self.__watcher or not self.__ss.start or not self.__ss.stop:
if not self._w_watcher or not self._w_ss.start or not self._w_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(self.__watcher, priority)
libev.ev_set_priority(self._w_watcher, priority)

@property
def ref(self):
Expand All @@ -912,7 +912,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._w_watcher):
libev.ev_unref(self.loop._ptr)
self._flags |= FLAG_WATCHER_NEEDS_EVREF

Expand All @@ -928,22 +928,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._w_watcher)

@priority.setter
def priority(self, int priority):
cdef libev.ev_watcher* w = self.__watcher
cdef libev.ev_watcher* w = self._w_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._w_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._w_watcher) else False

def start(self, object callback, *args):
_watcher_start(self, callback, args)
Expand All @@ -955,15 +955,15 @@ 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._w_ss.stop(self.loop._ptr, self._w_watcher)
_python_decref(self)

def feed(self, int revents, object callback, *args):
_check_loop(self.loop)
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._w_watcher, revents)
_python_incref(self)

def __repr__(self):
Expand All @@ -974,7 +974,7 @@ cdef public class watcher [object PyGeventWatcherObject, type PyGeventWatcher_Ty
result = "<%s at 0x%x native=0x%x%s" % (
self.__class__.__name__,
id(self),
<unsigned long>self.__watcher,
<unsigned long>self._w_watcher,
format
)
if self.active:
Expand Down Expand Up @@ -1024,8 +1024,8 @@ 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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &io_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_ss = &io_ss

def __dealloc__(self):
libev.vfd_free(self._watcher.fd)
Expand Down Expand Up @@ -1069,8 +1069,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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &timer_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_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)
Expand Down Expand Up @@ -1114,8 +1114,8 @@ 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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &signal_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_ss = &signal_ss

def __init__(self, loop loop, int signalnum, ref=True, priority=None):
watcher.__init__(self, loop, ref, priority)
Expand All @@ -1130,8 +1130,8 @@ 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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &idle_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_ss = &idle_ss



Expand All @@ -1143,8 +1143,8 @@ 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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &prepare_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_ss = &prepare_ss



Expand All @@ -1156,8 +1156,8 @@ 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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &check_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_ss = &check_ss



Expand All @@ -1169,8 +1169,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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &fork_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_ss = &fork_ss


cdef start_and_stop async_ss = make_ss(<void*>libev.ev_async_start, <void*>libev.ev_async_stop)
Expand All @@ -1186,8 +1186,8 @@ 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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &async_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_ss = &async_ss


def send(self):
Expand All @@ -1209,8 +1209,8 @@ 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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &child_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_ss = &child_ss

def __init__(self, loop loop, int pid, bint trace=0, ref=True):
watcher.__init__(self, loop, ref, None)
Expand Down Expand Up @@ -1260,8 +1260,8 @@ 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.__watcher = <libev.ev_watcher*>&self._watcher
self.__ss = &stat_ss
self._w_watcher = <libev.ev_watcher*>&self._watcher
self._w_ss = &stat_ss

def __init__(self, loop loop, str path, float interval=0.0, ref=True, priority=None):
watcher.__init__(self, loop, ref, priority)
Expand All @@ -1285,12 +1285,12 @@ cdef public class stat(watcher) [object PyGeventStatObject, type PyGeventStat_Ty



__SYSERR_CALLBACK = None
cdef object SYSERR_CALLBACK = None


cdef void _syserr_cb(char* msg) with gil:
try:
__SYSERR_CALLBACK(msg, errno)
SYSERR_CALLBACK(msg, errno)
except:
set_syserr_cb(None)
print_exc = getattr(traceback, 'print_exc', None)
Expand All @@ -1299,13 +1299,13 @@ cdef void _syserr_cb(char* msg) with gil:


cpdef set_syserr_cb(callback):
global __SYSERR_CALLBACK
global SYSERR_CALLBACK
if callback is None:
libev.ev_set_syserr_cb(NULL)
__SYSERR_CALLBACK = None
SYSERR_CALLBACK = None
elif callable(callback):
libev.ev_set_syserr_cb(<void*>_syserr_cb)
__SYSERR_CALLBACK = callback
SYSERR_CALLBACK = callback
else:
raise TypeError('Expected callable or None, got %r' % (callback, ))

Expand Down
14 changes: 7 additions & 7 deletions src/gevent/libev/corecffi.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ def _init_loop(self, flags, default):
ptr = libev.ev_loop_new(c_flags)
if not ptr:
raise SystemError("ev_loop_new(%s) failed" % (c_flags, ))
if default or globals()["__SYSERR_CALLBACK"] is None:
if default or SYSERR_CALLBACK is None:
set_syserr_cb(self._handle_syserr)

# Mark this loop as being used.
Expand Down Expand Up @@ -299,7 +299,7 @@ def destroy(self):
if self._ptr:
super(loop, self).destroy()
# pylint:disable=comparison-with-callable
if globals()["__SYSERR_CALLBACK"] == self._handle_syserr:
if globals()["SYSERR_CALLBACK"] == self._handle_syserr:
set_syserr_cb(None)


Expand Down Expand Up @@ -425,23 +425,23 @@ def activecnt(self):
def _syserr_cb(msg):
try:
msg = ffi.string(msg)
__SYSERR_CALLBACK(msg, ffi.errno)
SYSERR_CALLBACK(msg, ffi.errno)
except:
set_syserr_cb(None)
raise # let cffi print the traceback


def set_syserr_cb(callback):
global __SYSERR_CALLBACK
global SYSERR_CALLBACK
if callback is None:
libev.ev_set_syserr_cb(ffi.NULL)
__SYSERR_CALLBACK = None
SYSERR_CALLBACK = None
elif callable(callback):
libev.ev_set_syserr_cb(libev._syserr_cb)
__SYSERR_CALLBACK = callback
SYSERR_CALLBACK = callback
else:
raise TypeError('Expected callable or None, got %r' % (callback, ))

__SYSERR_CALLBACK = None
SYSERR_CALLBACK = None

LIBEV_EMBED = libev.LIBEV_EMBED