diff --git a/Makefile b/Makefile index 4375e5d2..6a0475a9 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ _default: compile clean: - rm -fr dist/ doc/_build/ *.egg-info uvloop/loop.*.pyd + rm -fr dist/ doc/_build/ *.egg-info uvloop/loop.*.pyd uvloop/loop_d.*.pyd rm -fr uvloop/*.c uvloop/*.html uvloop/*.so rm -fr uvloop/handles/*.html uvloop/includes/*.html find . -name '__pycache__' | xargs rm -rf diff --git a/pyproject.toml b/pyproject.toml index c4f93f0b..85c59bf5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,14 +36,16 @@ test = [ # pycodestyle is a dependency of flake8, but it must be frozen because # their combination breaks too often # (example breakage: https://gitlab.com/pycqa/flake8/issues/427) - 'aiohttp>=3.8.1; python_version < "3.12"', - 'aiohttp==3.9.0b0; python_version >= "3.12"', + 'aiohttp>=3.10.5', 'flake8~=5.0', 'psutil', 'pycodestyle~=2.9.0', 'pyOpenSSL~=23.0.0', 'mypy>=0.800', - 'Cython(>=0.29.36,<0.30.0)', +] +dev = [ + 'setuptools>=60', + 'Cython~=3.0', ] docs = [ 'Sphinx~=4.1.2', @@ -55,7 +57,7 @@ docs = [ requires = [ "setuptools>=60", "wheel", - "Cython(>=0.29.36,<0.30.0)", + "Cython~=3.0", ] build-backend = "setuptools.build_meta" diff --git a/setup.py b/setup.py index c369ac80..22a61e0c 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ from setuptools.command.sdist import sdist -CYTHON_DEPENDENCY = 'Cython(>=0.29.36,<0.30.0)' +CYTHON_DEPENDENCY = 'Cython~=3.0' MACHINE = platform.machine() MODULES_CFLAGS = [os.getenv('UVLOOP_OPT_CFLAGS', '-O2')] _ROOT = pathlib.Path(__file__).parent @@ -144,7 +144,9 @@ def finalize_options(self): self.distribution.ext_modules[:] = cythonize( self.distribution.ext_modules, compiler_directives=directives, - annotate=self.cython_annotate) + annotate=self.cython_annotate, + compile_time_env=dict(DEFAULT_FREELIST_SIZE=250), + emit_linenums=self.debug) super().finalize_options() diff --git a/tests/test_tcp.py b/tests/test_tcp.py index d7a73fbf..8759383d 100644 --- a/tests/test_tcp.py +++ b/tests/test_tcp.py @@ -1631,17 +1631,22 @@ async def client(addr): self.fail("unexpected call to connection_made()") def test_ssl_connect_accepted_socket(self): - if hasattr(ssl, 'PROTOCOL_TLS'): - proto = ssl.PROTOCOL_TLS + if hasattr(ssl, 'PROTOCOL_TLS_SERVER'): + server_proto = ssl.PROTOCOL_TLS_SERVER + client_proto = ssl.PROTOCOL_TLS_CLIENT else: - proto = ssl.PROTOCOL_SSLv23 - server_context = ssl.SSLContext(proto) + if hasattr(ssl, 'PROTOCOL_TLS'): + client_proto = server_proto = ssl.PROTOCOL_TLS + else: + client_proto = server_proto = ssl.PROTOCOL_SSLv23 + + server_context = ssl.SSLContext(server_proto) server_context.load_cert_chain(self.ONLYCERT, self.ONLYKEY) if hasattr(server_context, 'check_hostname'): server_context.check_hostname = False server_context.verify_mode = ssl.CERT_NONE - client_context = ssl.SSLContext(proto) + client_context = ssl.SSLContext(client_proto) if hasattr(server_context, 'check_hostname'): client_context.check_hostname = False client_context.verify_mode = ssl.CERT_NONE @@ -2234,8 +2239,7 @@ def test_renegotiation(self): sslctx.use_privatekey_file(self.ONLYKEY) sslctx.use_certificate_chain_file(self.ONLYCERT) client_sslctx = self._create_client_ssl_context() - if hasattr(ssl, 'OP_NO_TLSv1_3'): - client_sslctx.options |= ssl.OP_NO_TLSv1_3 + client_sslctx.maximum_version = ssl.TLSVersion.TLSv1_2 def server(sock): conn = openssl_ssl.Connection(sslctx, sock) @@ -2593,8 +2597,7 @@ def test_flush_before_shutdown(self): sslctx_openssl.use_privatekey_file(self.ONLYKEY) sslctx_openssl.use_certificate_chain_file(self.ONLYCERT) client_sslctx = self._create_client_ssl_context() - if hasattr(ssl, 'OP_NO_TLSv1_3'): - client_sslctx.options |= ssl.OP_NO_TLSv1_3 + client_sslctx.maximum_version = ssl.TLSVersion.TLSv1_2 future = None diff --git a/uvloop/_testbase.py b/uvloop/_testbase.py index c4a7595b..e620e158 100644 --- a/uvloop/_testbase.py +++ b/uvloop/_testbase.py @@ -269,7 +269,9 @@ def find_free_port(start_from=50000): class SSLTestCase: def _create_server_ssl_context(self, certfile, keyfile=None): - if hasattr(ssl, 'PROTOCOL_TLS'): + if hasattr(ssl, 'PROTOCOL_TLS_SERVER'): + sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + elif hasattr(ssl, 'PROTOCOL_TLS'): sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS) else: sslcontext = ssl.SSLContext(ssl.PROTOCOL_SSLv23) diff --git a/uvloop/dns.pyx b/uvloop/dns.pyx index c6be7cbe..67aeb595 100644 --- a/uvloop/dns.pyx +++ b/uvloop/dns.pyx @@ -298,7 +298,7 @@ cdef class AddrInfo: uv.uv_freeaddrinfo(self.data) # returns void self.data = NULL - cdef void set_data(self, system.addrinfo *data): + cdef void set_data(self, system.addrinfo *data) noexcept: self.data = data cdef unpack(self): diff --git a/uvloop/handles/handle.pyx b/uvloop/handles/handle.pyx index 6efe3755..2c96458b 100644 --- a/uvloop/handles/handle.pyx +++ b/uvloop/handles/handle.pyx @@ -363,7 +363,7 @@ cdef void __uv_close_handle_cb(uv.uv_handle_t* handle) noexcept with gil: Py_DECREF(h) # Was INCREFed in UVHandle._close -cdef void __close_all_handles(Loop loop): +cdef void __close_all_handles(Loop loop) noexcept: uv.uv_walk(loop.uvloop, __uv_walk_close_all_handles_cb, loop) # void diff --git a/uvloop/handles/pipe.pyx b/uvloop/handles/pipe.pyx index 195576c7..d30a7366 100644 --- a/uvloop/handles/pipe.pyx +++ b/uvloop/handles/pipe.pyx @@ -25,7 +25,7 @@ cdef __pipe_init_uv_handle(UVStream handle, Loop loop): cdef __pipe_open(UVStream handle, int fd): cdef int err err = uv.uv_pipe_open(handle._handle, - fd) + fd) if err < 0: exc = convert_error(err) raise exc diff --git a/uvloop/handles/poll.pxd b/uvloop/handles/poll.pxd index d07030b5..c2205402 100644 --- a/uvloop/handles/poll.pxd +++ b/uvloop/handles/poll.pxd @@ -10,7 +10,7 @@ cdef class UVPoll(UVHandle): cdef inline _poll_start(self, int flags) cdef inline _poll_stop(self) - cdef int is_active(self) + cdef int is_active(self) noexcept cdef is_reading(self) cdef is_writing(self) diff --git a/uvloop/handles/poll.pyx b/uvloop/handles/poll.pyx index fca5981e..c905e9b0 100644 --- a/uvloop/handles/poll.pyx +++ b/uvloop/handles/poll.pyx @@ -29,7 +29,7 @@ cdef class UVPoll(UVHandle): handle._init(loop, fd) return handle - cdef int is_active(self): + cdef int is_active(self) noexcept: return (self.reading_handle is not None or self.writing_handle is not None) diff --git a/uvloop/handles/stream.pyx b/uvloop/handles/stream.pyx index d4e02e3e..9fbc5a51 100644 --- a/uvloop/handles/stream.pyx +++ b/uvloop/handles/stream.pyx @@ -1,4 +1,8 @@ -DEF __PREALLOCED_BUFS = 4 +cdef extern from *: + ''' + enum {__PREALLOCED_BUFS = 4}; + ''' + const bint __PREALLOCED_BUFS @cython.no_gc_clear diff --git a/uvloop/includes/consts.pxi b/uvloop/includes/consts.pxi index f765053d..82f3c327 100644 --- a/uvloop/includes/consts.pxi +++ b/uvloop/includes/consts.pxi @@ -1,25 +1,33 @@ -DEF UV_STREAM_RECV_BUF_SIZE = 256000 # 250kb +cdef enum: + UV_STREAM_RECV_BUF_SIZE = 256000 # 250kb -DEF FLOW_CONTROL_HIGH_WATER = 64 # KiB -DEF FLOW_CONTROL_HIGH_WATER_SSL_READ = 256 # KiB -DEF FLOW_CONTROL_HIGH_WATER_SSL_WRITE = 512 # KiB + FLOW_CONTROL_HIGH_WATER = 64 # KiB + FLOW_CONTROL_HIGH_WATER_SSL_READ = 256 # KiB + FLOW_CONTROL_HIGH_WATER_SSL_WRITE = 512 # KiB -DEF DEFAULT_FREELIST_SIZE = 250 -DEF DNS_PYADDR_TO_SOCKADDR_CACHE_SIZE = 2048 + DEFAULT_FREELIST_SIZE = 250 + DNS_PYADDR_TO_SOCKADDR_CACHE_SIZE = 2048 -DEF DEBUG_STACK_DEPTH = 10 + DEBUG_STACK_DEPTH = 10 -DEF __PROCESS_DEBUG_SLEEP_AFTER_FORK = 1 + __PROCESS_DEBUG_SLEEP_AFTER_FORK = 1 -DEF LOG_THRESHOLD_FOR_CONNLOST_WRITES = 5 + LOG_THRESHOLD_FOR_CONNLOST_WRITES = 5 + SSL_READ_MAX_SIZE = 256 * 1024 -# Number of seconds to wait for SSL handshake to complete -# The default timeout matches that of Nginx. -DEF SSL_HANDSHAKE_TIMEOUT = 60.0 -# Number of seconds to wait for SSL shutdown to complete -# The default timeout mimics lingering_time -DEF SSL_SHUTDOWN_TIMEOUT = 30.0 -DEF SSL_READ_MAX_SIZE = 256 * 1024 +cdef extern from *: + ''' + // Number of seconds to wait for SSL handshake to complete + // The default timeout matches that of Nginx. + #define SSL_HANDSHAKE_TIMEOUT 60.0 + + // Number of seconds to wait for SSL shutdown to complete + // The default timeout mimics lingering_time + #define SSL_SHUTDOWN_TIMEOUT 30.0 + ''' + + const float SSL_HANDSHAKE_TIMEOUT + const float SSL_SHUTDOWN_TIMEOUT diff --git a/uvloop/includes/fork_handler.h b/uvloop/includes/fork_handler.h index 47bbe036..9d3573ae 100644 --- a/uvloop/includes/fork_handler.h +++ b/uvloop/includes/fork_handler.h @@ -1,7 +1,10 @@ +#ifndef UVLOOP_FORK_HANDLER_H_ +#define UVLOOP_FORK_HANDLER_H_ + volatile uint64_t MAIN_THREAD_ID = 0; volatile int8_t MAIN_THREAD_ID_SET = 0; -typedef void (*OnForkHandler)(); +typedef void (*OnForkHandler)(void); OnForkHandler __forkHandler = NULL; @@ -36,3 +39,4 @@ void setMainThreadID(uint64_t id) { MAIN_THREAD_ID = id; MAIN_THREAD_ID_SET = 1; } +#endif diff --git a/uvloop/includes/uv.pxd b/uvloop/includes/uv.pxd index 2756a306..510b1498 100644 --- a/uvloop/includes/uv.pxd +++ b/uvloop/includes/uv.pxd @@ -220,7 +220,7 @@ cdef extern from "uv.h" nogil: UV_LEAVE_GROUP = 0, UV_JOIN_GROUP - cpdef enum uv_fs_event: + cdef enum uv_fs_event: UV_RENAME = 1, UV_CHANGE = 2 @@ -282,7 +282,7 @@ cdef extern from "uv.h" nogil: int uv_loop_close(uv_loop_t* loop) int uv_loop_alive(uv_loop_t* loop) int uv_loop_fork(uv_loop_t* loop) - int uv_backend_fd(uv_loop_t* loop) + uv_os_fd_t uv_backend_fd(uv_loop_t* loop) void uv_update_time(uv_loop_t* loop) uint64_t uv_now(const uv_loop_t*) @@ -378,7 +378,7 @@ cdef extern from "uv.h" nogil: # Pipes int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) - int uv_pipe_open(uv_pipe_t* handle, uv_file file) + int uv_pipe_open(uv_pipe_t* handle, uv_os_fd_t file) int uv_pipe_bind(uv_pipe_t* handle, const char* name) void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, diff --git a/uvloop/loop.pyx b/uvloop/loop.pyx index de88b575..24df3e8a 100644 --- a/uvloop/loop.pyx +++ b/uvloop/loop.pyx @@ -43,7 +43,6 @@ from cpython.pycapsule cimport PyCapsule_New, PyCapsule_GetPointer from . import _noop -include "includes/consts.pxi" include "includes/stdlib.pxi" include "errors.pyx" @@ -1118,7 +1117,7 @@ cdef class Loop: cdef _sock_set_reuseport(self, int fd): cdef: - int err + int err = 0 int reuseport_flag = 1 err = system.setsockopt( @@ -1396,8 +1395,7 @@ cdef class Loop: def set_debug(self, enabled): self._debug = bool(enabled) if self.is_running(): - self.call_soon_threadsafe( - self._set_coroutine_debug, self, self._debug) + self.call_soon_threadsafe(self._set_coroutine_debug, self._debug) def is_running(self): """Return whether the event loop is currently running.""" @@ -2749,8 +2747,7 @@ cdef class Loop: start_new_session=False, executable=None, pass_fds=(), - # For tests only! Do not use in your code. Ever. - __uvloop_sleep_after_fork=False): + **kwargs): # TODO: Implement close_fds (might not be very important in # Python 3.5, since all FDs aren't inheritable by default.) @@ -2770,8 +2767,12 @@ cdef class Loop: if executable is not None: args[0] = executable - if __uvloop_sleep_after_fork: + # For tests only! Do not use in your code. Ever. + if kwargs.pop("__uvloop_sleep_after_fork", False): debug_flags |= __PROCESS_DEBUG_SLEEP_AFTER_FORK + if kwargs: + raise ValueError( + 'unexpected kwargs: {}'.format(', '.join(kwargs.keys()))) waiter = self._new_future() protocol = protocol_factory()