rloop 0.1.3__tar.gz → 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rloop-0.1.3 → rloop-0.1.5}/Cargo.lock +28 -28
- {rloop-0.1.3 → rloop-0.1.5}/Cargo.toml +4 -4
- {rloop-0.1.3 → rloop-0.1.5}/PKG-INFO +2 -9
- {rloop-0.1.3 → rloop-0.1.5}/pyproject.toml +15 -6
- {rloop-0.1.3 → rloop-0.1.5}/rloop/__init__.py +1 -2
- rloop-0.1.5/rloop/_compat.py +11 -0
- {rloop-0.1.3 → rloop-0.1.5}/rloop/loop.py +1 -1
- {rloop-0.1.3 → rloop-0.1.5}/src/event_loop.rs +82 -113
- {rloop-0.1.3 → rloop-0.1.5}/src/handles.rs +2 -2
- {rloop-0.1.3 → rloop-0.1.5}/src/io.rs +1 -1
- {rloop-0.1.3 → rloop-0.1.5}/src/lib.rs +1 -1
- {rloop-0.1.3 → rloop-0.1.5}/src/tcp.rs +2 -2
- rloop-0.1.5/src/utils.rs +12 -0
- {rloop-0.1.3 → rloop-0.1.5}/tests/test_handles.py +39 -0
- rloop-0.1.3/rloop/_compat.py +0 -5
- rloop-0.1.3/src/utils.rs +0 -27
- {rloop-0.1.3 → rloop-0.1.5}/LICENSE +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/README.md +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/rloop/_rloop.pyi +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/rloop/exc.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/rloop/futures.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/rloop/server.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/rloop/subprocess.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/rloop/transports.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/rloop/utils.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/src/log.rs +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/src/py.rs +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/src/server.rs +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/src/sock.rs +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/src/time.rs +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/tests/conftest.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/tests/tcp/__init__.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/tests/tcp/test_tcp_conn.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/tests/tcp/test_tcp_server.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/tests/test_sockets.py +0 -0
- {rloop-0.1.3 → rloop-0.1.5}/tests/udp/test_udp.py +0 -0
|
@@ -10,15 +10,15 @@ checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
|
|
10
10
|
|
|
11
11
|
[[package]]
|
|
12
12
|
name = "autocfg"
|
|
13
|
-
version = "1.
|
|
13
|
+
version = "1.5.0"
|
|
14
14
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
15
|
-
checksum = "
|
|
15
|
+
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
16
16
|
|
|
17
17
|
[[package]]
|
|
18
18
|
name = "cc"
|
|
19
|
-
version = "1.2.
|
|
19
|
+
version = "1.2.32"
|
|
20
20
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
-
checksum = "
|
|
21
|
+
checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e"
|
|
22
22
|
dependencies = [
|
|
23
23
|
"shlex",
|
|
24
24
|
]
|
|
@@ -43,9 +43,9 @@ checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
|
|
43
43
|
|
|
44
44
|
[[package]]
|
|
45
45
|
name = "libc"
|
|
46
|
-
version = "0.2.
|
|
46
|
+
version = "0.2.174"
|
|
47
47
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
48
|
-
checksum = "
|
|
48
|
+
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
|
49
49
|
|
|
50
50
|
[[package]]
|
|
51
51
|
name = "log"
|
|
@@ -82,9 +82,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
|
|
82
82
|
|
|
83
83
|
[[package]]
|
|
84
84
|
name = "papaya"
|
|
85
|
-
version = "0.2.
|
|
85
|
+
version = "0.2.3"
|
|
86
86
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
87
|
-
checksum = "
|
|
87
|
+
checksum = "f92dd0b07c53a0a0c764db2ace8c541dc47320dad97c2200c2a637ab9dd2328f"
|
|
88
88
|
dependencies = [
|
|
89
89
|
"equivalent",
|
|
90
90
|
"seize",
|
|
@@ -92,9 +92,9 @@ dependencies = [
|
|
|
92
92
|
|
|
93
93
|
[[package]]
|
|
94
94
|
name = "portable-atomic"
|
|
95
|
-
version = "1.11.
|
|
95
|
+
version = "1.11.1"
|
|
96
96
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
97
|
-
checksum = "
|
|
97
|
+
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
|
98
98
|
|
|
99
99
|
[[package]]
|
|
100
100
|
name = "proc-macro2"
|
|
@@ -107,9 +107,9 @@ dependencies = [
|
|
|
107
107
|
|
|
108
108
|
[[package]]
|
|
109
109
|
name = "pyo3"
|
|
110
|
-
version = "0.25.
|
|
110
|
+
version = "0.25.1"
|
|
111
111
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
112
|
-
checksum = "
|
|
112
|
+
checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a"
|
|
113
113
|
dependencies = [
|
|
114
114
|
"anyhow",
|
|
115
115
|
"indoc",
|
|
@@ -125,9 +125,9 @@ dependencies = [
|
|
|
125
125
|
|
|
126
126
|
[[package]]
|
|
127
127
|
name = "pyo3-build-config"
|
|
128
|
-
version = "0.25.
|
|
128
|
+
version = "0.25.1"
|
|
129
129
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
130
|
-
checksum = "
|
|
130
|
+
checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598"
|
|
131
131
|
dependencies = [
|
|
132
132
|
"once_cell",
|
|
133
133
|
"python3-dll-a",
|
|
@@ -136,9 +136,9 @@ dependencies = [
|
|
|
136
136
|
|
|
137
137
|
[[package]]
|
|
138
138
|
name = "pyo3-ffi"
|
|
139
|
-
version = "0.25.
|
|
139
|
+
version = "0.25.1"
|
|
140
140
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
141
|
-
checksum = "
|
|
141
|
+
checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c"
|
|
142
142
|
dependencies = [
|
|
143
143
|
"libc",
|
|
144
144
|
"pyo3-build-config",
|
|
@@ -146,9 +146,9 @@ dependencies = [
|
|
|
146
146
|
|
|
147
147
|
[[package]]
|
|
148
148
|
name = "pyo3-macros"
|
|
149
|
-
version = "0.25.
|
|
149
|
+
version = "0.25.1"
|
|
150
150
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
151
|
-
checksum = "
|
|
151
|
+
checksum = "a8725c0a622b374d6cb051d11a0983786448f7785336139c3c94f5aa6bef7e50"
|
|
152
152
|
dependencies = [
|
|
153
153
|
"proc-macro2",
|
|
154
154
|
"pyo3-macros-backend",
|
|
@@ -158,9 +158,9 @@ dependencies = [
|
|
|
158
158
|
|
|
159
159
|
[[package]]
|
|
160
160
|
name = "pyo3-macros-backend"
|
|
161
|
-
version = "0.25.
|
|
161
|
+
version = "0.25.1"
|
|
162
162
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
163
|
-
checksum = "
|
|
163
|
+
checksum = "4109984c22491085343c05b0dbc54ddc405c3cf7b4374fc533f5c3313a572ccc"
|
|
164
164
|
dependencies = [
|
|
165
165
|
"heck",
|
|
166
166
|
"proc-macro2",
|
|
@@ -189,7 +189,7 @@ dependencies = [
|
|
|
189
189
|
|
|
190
190
|
[[package]]
|
|
191
191
|
name = "rloop"
|
|
192
|
-
version = "0.1.
|
|
192
|
+
version = "0.1.5"
|
|
193
193
|
dependencies = [
|
|
194
194
|
"anyhow",
|
|
195
195
|
"libc",
|
|
@@ -218,19 +218,19 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
|
|
218
218
|
|
|
219
219
|
[[package]]
|
|
220
220
|
name = "socket2"
|
|
221
|
-
version = "0.
|
|
221
|
+
version = "0.6.0"
|
|
222
222
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
223
|
-
checksum = "
|
|
223
|
+
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
|
224
224
|
dependencies = [
|
|
225
225
|
"libc",
|
|
226
|
-
"windows-sys 0.
|
|
226
|
+
"windows-sys 0.59.0",
|
|
227
227
|
]
|
|
228
228
|
|
|
229
229
|
[[package]]
|
|
230
230
|
name = "syn"
|
|
231
|
-
version = "2.0.
|
|
231
|
+
version = "2.0.104"
|
|
232
232
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
233
|
-
checksum = "
|
|
233
|
+
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
|
234
234
|
dependencies = [
|
|
235
235
|
"proc-macro2",
|
|
236
236
|
"quote",
|
|
@@ -257,9 +257,9 @@ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
|
|
|
257
257
|
|
|
258
258
|
[[package]]
|
|
259
259
|
name = "wasi"
|
|
260
|
-
version = "0.11.
|
|
260
|
+
version = "0.11.1+wasi-snapshot-preview1"
|
|
261
261
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
262
|
-
checksum = "
|
|
262
|
+
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
|
263
263
|
|
|
264
264
|
[[package]]
|
|
265
265
|
name = "windows-sys"
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "rloop"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.5"
|
|
4
4
|
description = "An asyncio event loop implemented in Rust"
|
|
5
5
|
authors = ["Giovanni Barillari <g@baro.dev>"]
|
|
6
6
|
license = "BSD-3-Clause"
|
|
7
|
-
edition = "
|
|
7
|
+
edition = "2024"
|
|
8
8
|
|
|
9
9
|
keywords = ["asyncio"]
|
|
10
10
|
|
|
@@ -27,14 +27,14 @@ include = [
|
|
|
27
27
|
|
|
28
28
|
[lib]
|
|
29
29
|
name = "_rloop"
|
|
30
|
-
crate-type = ["cdylib"]
|
|
30
|
+
crate-type = ["cdylib", "rlib"]
|
|
31
31
|
|
|
32
32
|
[dependencies]
|
|
33
33
|
anyhow = "=1.0"
|
|
34
34
|
mio = { version = "=1.0", features = ["net", "os-ext", "os-poll"] }
|
|
35
35
|
papaya = "=0.2"
|
|
36
36
|
pyo3 = { version = "=0.25", features = ["anyhow", "extension-module", "generate-import-lib"] }
|
|
37
|
-
socket2 = { version = "=0.
|
|
37
|
+
socket2 = { version = "=0.6", features = ["all"] }
|
|
38
38
|
|
|
39
39
|
[target.'cfg(unix)'.dependencies]
|
|
40
40
|
libc = "0.2.159"
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rloop
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: License :: OSI Approved :: BSD License
|
|
7
7
|
Classifier: Operating System :: MacOS
|
|
8
8
|
Classifier: Operating System :: POSIX :: Linux
|
|
9
|
+
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
9
10
|
Classifier: Programming Language :: Python :: 3
|
|
10
11
|
Classifier: Programming Language :: Python :: 3.9
|
|
11
12
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -16,18 +17,10 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
|
16
17
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
17
18
|
Classifier: Programming Language :: Python
|
|
18
19
|
Classifier: Programming Language :: Rust
|
|
19
|
-
Requires-Dist: ruff~=0.5.0 ; extra == 'lint'
|
|
20
|
-
Requires-Dist: pytest~=7.4.2 ; extra == 'test'
|
|
21
|
-
Requires-Dist: pytest-asyncio~=0.21.1 ; extra == 'test'
|
|
22
|
-
Requires-Dist: rloop[lint,test] ; extra == 'dev'
|
|
23
|
-
Provides-Extra: lint
|
|
24
|
-
Provides-Extra: test
|
|
25
|
-
Provides-Extra: dev
|
|
26
20
|
License-File: LICENSE
|
|
27
21
|
Summary: An asyncio event loop implemented in Rust
|
|
28
22
|
Keywords: asyncio
|
|
29
23
|
Home-Page: https://github.com/gi0baro/rloop
|
|
30
|
-
Author: Giovanni Barillari <g@baro.dev>
|
|
31
24
|
Author-email: Giovanni Barillari <g@baro.dev>
|
|
32
25
|
License: BSD-3-Clause
|
|
33
26
|
Requires-Python: >=3.9
|
|
@@ -9,6 +9,7 @@ classifiers = [
|
|
|
9
9
|
'License :: OSI Approved :: BSD License',
|
|
10
10
|
'Operating System :: MacOS',
|
|
11
11
|
'Operating System :: POSIX :: Linux',
|
|
12
|
+
'Programming Language :: Python :: Free Threading :: 2 - Beta',
|
|
12
13
|
'Programming Language :: Python :: 3',
|
|
13
14
|
'Programming Language :: Python :: 3.9',
|
|
14
15
|
'Programming Language :: Python :: 3.10',
|
|
@@ -32,15 +33,23 @@ dynamic = [
|
|
|
32
33
|
requires-python = '>=3.9'
|
|
33
34
|
dependencies = []
|
|
34
35
|
|
|
35
|
-
[
|
|
36
|
+
[dependency-groups]
|
|
37
|
+
build = [
|
|
38
|
+
'maturin~=1.8',
|
|
39
|
+
]
|
|
36
40
|
lint = [
|
|
37
|
-
'ruff~=0.
|
|
41
|
+
'ruff~=0.11',
|
|
38
42
|
]
|
|
39
43
|
test = [
|
|
40
|
-
'pytest~=
|
|
41
|
-
'pytest-asyncio~=0.
|
|
44
|
+
'pytest~=8.3',
|
|
45
|
+
'pytest-asyncio~=0.26',
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
all = [
|
|
49
|
+
{ include-group = 'build' },
|
|
50
|
+
{ include-group = 'lint' },
|
|
51
|
+
{ include-group = 'test' },
|
|
42
52
|
]
|
|
43
|
-
dev = ['rloop[lint,test]']
|
|
44
53
|
|
|
45
54
|
[project.urls]
|
|
46
55
|
Homepage = 'https://github.com/gi0baro/rloop'
|
|
@@ -48,7 +57,7 @@ Funding = 'https://github.com/sponsors/gi0baro'
|
|
|
48
57
|
Source = 'https://github.com/gi0baro/rloop'
|
|
49
58
|
|
|
50
59
|
[build-system]
|
|
51
|
-
requires = ['maturin>=1.
|
|
60
|
+
requires = ['maturin>=1.8.0,<2']
|
|
52
61
|
build-backend = 'maturin'
|
|
53
62
|
|
|
54
63
|
[tool.maturin]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
_PYV = int(sys.version_info.major * 100 + sys.version_info.minor)
|
|
5
|
+
_PY_311 = 311
|
|
6
|
+
_PY_314 = 314
|
|
7
|
+
|
|
8
|
+
if _PYV < 314:
|
|
9
|
+
from asyncio.events import BaseDefaultEventLoopPolicy as _BaseEventLoopPolicy
|
|
10
|
+
else:
|
|
11
|
+
from asyncio.events import _BaseDefaultEventLoopPolicy as _BaseEventLoopPolicy # noqa
|
|
@@ -391,7 +391,7 @@ class RLoop(__BaseLoop, __asyncio.AbstractEventLoop):
|
|
|
391
391
|
exceptions = [exc for sub in exceptions for exc in sub]
|
|
392
392
|
try:
|
|
393
393
|
if all_errors:
|
|
394
|
-
raise ExceptionGroup('create_connection failed', exceptions)
|
|
394
|
+
raise ExceptionGroup('create_connection failed', exceptions) # noqa: F821
|
|
395
395
|
if len(exceptions) == 1:
|
|
396
396
|
raise exceptions[0]
|
|
397
397
|
else:
|
|
@@ -3,29 +3,25 @@ use std::{
|
|
|
3
3
|
io::Read,
|
|
4
4
|
mem,
|
|
5
5
|
os::fd::{AsRawFd, FromRawFd},
|
|
6
|
-
sync::{
|
|
6
|
+
sync::{Arc, Mutex, RwLock, atomic},
|
|
7
7
|
time::{Duration, Instant},
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
use anyhow::Result;
|
|
11
|
-
use mio::{
|
|
11
|
+
use mio::{Interest, Poll, Token, Waker, event, net::TcpListener};
|
|
12
12
|
use pyo3::prelude::*;
|
|
13
13
|
|
|
14
14
|
use crate::{
|
|
15
15
|
handles::{BoxedHandle, CBHandle, Handle, TimerHandle},
|
|
16
16
|
io::Source,
|
|
17
|
-
log::{
|
|
17
|
+
log::{LogExc, log_exc_to_py_ctx},
|
|
18
18
|
py::{copy_context, weakset},
|
|
19
19
|
server::Server,
|
|
20
20
|
tcp::{TCPReadHandle, TCPServer, TCPServerRef, TCPTransport, TCPWriteHandle},
|
|
21
21
|
time::Timer,
|
|
22
|
-
utils::{py_allow_threads, syscall},
|
|
23
22
|
};
|
|
24
23
|
|
|
25
|
-
const WAKEB: &[u8; 1] = b"\0";
|
|
26
|
-
|
|
27
24
|
enum IOHandle {
|
|
28
|
-
Internal,
|
|
29
25
|
Py(PyHandleData),
|
|
30
26
|
Signals,
|
|
31
27
|
TCPListener(TCPListenerHandleData),
|
|
@@ -43,11 +39,10 @@ struct TCPListenerHandleData {
|
|
|
43
39
|
server: TCPServerRef,
|
|
44
40
|
}
|
|
45
41
|
|
|
46
|
-
pub
|
|
42
|
+
pub struct EventLoopRunState {
|
|
47
43
|
buf: Box<[u8]>,
|
|
48
44
|
events: event::Events,
|
|
49
45
|
pub read_buf: Box<[u8]>,
|
|
50
|
-
sock: socket2::Socket,
|
|
51
46
|
tick_last: u128,
|
|
52
47
|
}
|
|
53
48
|
|
|
@@ -55,14 +50,13 @@ pub(crate) struct EventLoopRunState {
|
|
|
55
50
|
pub struct EventLoop {
|
|
56
51
|
idle: atomic::AtomicBool,
|
|
57
52
|
io: Mutex<Poll>,
|
|
53
|
+
waker: Arc<Waker>,
|
|
58
54
|
handles_io: papaya::HashMap<Token, IOHandle>,
|
|
59
55
|
handles_ready: Mutex<VecDeque<BoxedHandle>>,
|
|
60
56
|
handles_sched: Mutex<BinaryHeap<Timer>>,
|
|
61
57
|
epoch: Instant,
|
|
62
58
|
counter_ready: atomic::AtomicUsize,
|
|
63
59
|
ssock: RwLock<Option<(socket2::Socket, socket2::Socket)>>,
|
|
64
|
-
wsock: Mutex<Option<socket2::Socket>>,
|
|
65
|
-
wsock_fd: atomic::AtomicI32,
|
|
66
60
|
closed: atomic::AtomicBool,
|
|
67
61
|
exc_handler: RwLock<PyObject>,
|
|
68
62
|
exception_handler: RwLock<PyObject>,
|
|
@@ -88,46 +82,6 @@ pub struct EventLoop {
|
|
|
88
82
|
}
|
|
89
83
|
|
|
90
84
|
impl EventLoop {
|
|
91
|
-
fn run_pre(&self) -> Result<EventLoopRunState> {
|
|
92
|
-
// wake sockets
|
|
93
|
-
let (sock_r, sock_w) = socket2::Socket::pair(socket2::Domain::UNIX, socket2::Type::STREAM, None)?;
|
|
94
|
-
sock_r.set_nonblocking(true)?;
|
|
95
|
-
sock_w.set_nonblocking(true)?;
|
|
96
|
-
let token = Token(sock_r.as_raw_fd() as usize);
|
|
97
|
-
let mut source = Source::FD(sock_r.as_raw_fd());
|
|
98
|
-
{
|
|
99
|
-
let guard = self.io.lock().unwrap();
|
|
100
|
-
guard.registry().register(&mut source, token, Interest::READABLE)?;
|
|
101
|
-
}
|
|
102
|
-
self.handles_io.pin().insert(token, IOHandle::Internal);
|
|
103
|
-
{
|
|
104
|
-
let mut guard = self.wsock.lock().unwrap();
|
|
105
|
-
self.wsock_fd.store(sock_w.as_raw_fd(), atomic::Ordering::Relaxed);
|
|
106
|
-
*guard = Some(sock_w);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
Ok(EventLoopRunState {
|
|
110
|
-
buf: vec![0; 4096].into_boxed_slice(),
|
|
111
|
-
events: event::Events::with_capacity(128),
|
|
112
|
-
read_buf: vec![0; 262_144].into_boxed_slice(),
|
|
113
|
-
tick_last: 0,
|
|
114
|
-
sock: sock_r,
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
fn run_post(&self, state: &mut EventLoopRunState) {
|
|
119
|
-
// cleanup wake sockets
|
|
120
|
-
self.wsock.lock().unwrap().take();
|
|
121
|
-
self.wsock_fd.store(-1, atomic::Ordering::Relaxed);
|
|
122
|
-
let token = Token(state.sock.as_raw_fd() as usize);
|
|
123
|
-
let mut source = Source::FD(state.sock.as_raw_fd());
|
|
124
|
-
{
|
|
125
|
-
let guard = self.io.lock().unwrap();
|
|
126
|
-
_ = guard.registry().deregister(&mut source);
|
|
127
|
-
}
|
|
128
|
-
self.handles_io.pin().remove(&token);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
85
|
#[inline]
|
|
132
86
|
fn step(&self, py: Python, state: &mut EventLoopRunState) -> std::result::Result<(), std::io::Error> {
|
|
133
87
|
let mut sched_time: Option<u64> = None;
|
|
@@ -154,33 +108,29 @@ impl EventLoop {
|
|
|
154
108
|
}
|
|
155
109
|
|
|
156
110
|
// I/O
|
|
157
|
-
let poll_result =
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
111
|
+
let poll_result = if skip_poll {
|
|
112
|
+
Ok(())
|
|
113
|
+
} else {
|
|
114
|
+
let idle_swap = !matches!(sched_time, Some(0));
|
|
115
|
+
if idle_swap {
|
|
116
|
+
self.idle.store(true, atomic::Ordering::Release);
|
|
161
117
|
}
|
|
162
|
-
|
|
163
|
-
let
|
|
118
|
+
let res = py.allow_threads(|| {
|
|
119
|
+
let mut io = self.io.lock().unwrap();
|
|
120
|
+
let res = io.poll(&mut state.events, sched_time.map(Duration::from_micros));
|
|
164
121
|
if idle_swap {
|
|
165
|
-
self.idle.store(
|
|
122
|
+
self.idle.store(false, atomic::Ordering::Release);
|
|
166
123
|
}
|
|
167
|
-
let
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
self.idle.store(false, atomic::Ordering::Release);
|
|
172
|
-
}
|
|
173
|
-
if let Err(ref err) = res {
|
|
174
|
-
if err.kind() == std::io::ErrorKind::Interrupted {
|
|
175
|
-
// if we got an interrupt, we retry ready events (as we might need to process signals)
|
|
176
|
-
let _ = io.poll(&mut state.events, Some(Duration::from_millis(0)));
|
|
177
|
-
}
|
|
124
|
+
if let Err(ref err) = res {
|
|
125
|
+
if err.kind() == std::io::ErrorKind::Interrupted {
|
|
126
|
+
// if we got an interrupt, we retry ready events (as we might need to process signals)
|
|
127
|
+
let _ = io.poll(&mut state.events, Some(Duration::from_millis(0)));
|
|
178
128
|
}
|
|
179
|
-
|
|
180
|
-
});
|
|
181
|
-
state.tick_last = Instant::now().duration_since(self.epoch).as_micros();
|
|
129
|
+
}
|
|
182
130
|
res
|
|
183
|
-
}
|
|
131
|
+
});
|
|
132
|
+
state.tick_last = Instant::now().duration_since(self.epoch).as_micros();
|
|
133
|
+
res
|
|
184
134
|
};
|
|
185
135
|
|
|
186
136
|
let mut cb_handles = {
|
|
@@ -190,7 +140,7 @@ impl EventLoop {
|
|
|
190
140
|
self.counter_ready
|
|
191
141
|
.fetch_sub(cb_handles.len(), atomic::Ordering::Release);
|
|
192
142
|
|
|
193
|
-
{
|
|
143
|
+
if !skip_poll {
|
|
194
144
|
let io_handles = self.handles_io.pin();
|
|
195
145
|
for event in &state.events {
|
|
196
146
|
// NOTE: cancellation is not necessary as we have custom futures
|
|
@@ -199,7 +149,6 @@ impl EventLoop {
|
|
|
199
149
|
IOHandle::Py(handle) => self.handle_io_py(py, event, handle, &mut cb_handles),
|
|
200
150
|
IOHandle::TCPListener(handle) => self.handle_io_tcpl(py, handle, &io_handles, &mut cb_handles),
|
|
201
151
|
IOHandle::TCPStream(_) => self.handle_io_tcps(event, &mut cb_handles),
|
|
202
|
-
IOHandle::Internal => self.handle_io_internal(&mut state.sock, &mut state.buf),
|
|
203
152
|
IOHandle::Signals => self.handle_io_signals(py, &mut state.buf, &mut cb_handles),
|
|
204
153
|
}
|
|
205
154
|
}
|
|
@@ -245,11 +194,6 @@ impl EventLoop {
|
|
|
245
194
|
len
|
|
246
195
|
}
|
|
247
196
|
|
|
248
|
-
#[inline]
|
|
249
|
-
fn handle_io_internal(&self, socket: &mut socket2::Socket, buf: &mut [u8]) {
|
|
250
|
-
self.read_from_sock(socket, buf);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
197
|
#[inline]
|
|
254
198
|
fn handle_io_py(
|
|
255
199
|
&self,
|
|
@@ -338,8 +282,9 @@ impl EventLoop {
|
|
|
338
282
|
|
|
339
283
|
#[inline(always)]
|
|
340
284
|
fn wake(&self) {
|
|
341
|
-
|
|
342
|
-
|
|
285
|
+
if self.idle.load(atomic::Ordering::Acquire) {
|
|
286
|
+
_ = self.waker.wake();
|
|
287
|
+
}
|
|
343
288
|
}
|
|
344
289
|
|
|
345
290
|
pub(crate) fn tcp_listener_add(&self, listener: TcpListener, server: TCPServerRef) {
|
|
@@ -486,9 +431,7 @@ impl EventLoop {
|
|
|
486
431
|
guard.push_back(Box::new(handle));
|
|
487
432
|
}
|
|
488
433
|
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
489
|
-
|
|
490
|
-
self.wake();
|
|
491
|
-
}
|
|
434
|
+
self.wake();
|
|
492
435
|
|
|
493
436
|
Ok(())
|
|
494
437
|
}
|
|
@@ -509,9 +452,7 @@ impl EventLoop {
|
|
|
509
452
|
guard.push_back(Box::new(handle));
|
|
510
453
|
}
|
|
511
454
|
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
512
|
-
|
|
513
|
-
self.wake();
|
|
514
|
-
}
|
|
455
|
+
self.wake();
|
|
515
456
|
|
|
516
457
|
Ok(())
|
|
517
458
|
}
|
|
@@ -532,9 +473,7 @@ impl EventLoop {
|
|
|
532
473
|
guard.push_back(Box::new(handle));
|
|
533
474
|
}
|
|
534
475
|
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
535
|
-
|
|
536
|
-
self.wake();
|
|
537
|
-
}
|
|
476
|
+
self.wake();
|
|
538
477
|
|
|
539
478
|
Ok(())
|
|
540
479
|
}
|
|
@@ -559,9 +498,7 @@ impl EventLoop {
|
|
|
559
498
|
.map_err(|_| anyhow::anyhow!("lock acquisition failed"))?;
|
|
560
499
|
guard.push(timer);
|
|
561
500
|
}
|
|
562
|
-
|
|
563
|
-
self.wake();
|
|
564
|
-
}
|
|
501
|
+
self.wake();
|
|
565
502
|
|
|
566
503
|
Ok(())
|
|
567
504
|
}
|
|
@@ -592,9 +529,7 @@ impl EventLoop {
|
|
|
592
529
|
.map_err(|_| anyhow::anyhow!("lock acquisition failed"))?;
|
|
593
530
|
guard.push(timer);
|
|
594
531
|
}
|
|
595
|
-
|
|
596
|
-
self.wake();
|
|
597
|
-
}
|
|
532
|
+
self.wake();
|
|
598
533
|
|
|
599
534
|
Ok(())
|
|
600
535
|
}
|
|
@@ -625,9 +560,40 @@ impl EventLoop {
|
|
|
625
560
|
.map_err(|_| anyhow::anyhow!("lock acquisition failed"))?;
|
|
626
561
|
guard.push(timer);
|
|
627
562
|
}
|
|
628
|
-
|
|
629
|
-
|
|
563
|
+
self.wake();
|
|
564
|
+
|
|
565
|
+
Ok(())
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
#[allow(clippy::missing_errors_doc)]
|
|
569
|
+
pub fn schedule_handle(&self, handle: impl Handle + Send + 'static, delay: Option<Duration>) -> Result<()> {
|
|
570
|
+
match delay {
|
|
571
|
+
Some(delay) => {
|
|
572
|
+
let when = (Instant::now().duration_since(self.epoch) + delay).as_micros();
|
|
573
|
+
let timer = Timer {
|
|
574
|
+
handle: Box::new(handle),
|
|
575
|
+
when,
|
|
576
|
+
};
|
|
577
|
+
{
|
|
578
|
+
let mut guard = self
|
|
579
|
+
.handles_sched
|
|
580
|
+
.lock()
|
|
581
|
+
.map_err(|_| anyhow::anyhow!("lock acquisition failed"))?;
|
|
582
|
+
guard.push(timer);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
None => {
|
|
586
|
+
{
|
|
587
|
+
let mut guard = self
|
|
588
|
+
.handles_ready
|
|
589
|
+
.lock()
|
|
590
|
+
.map_err(|_| anyhow::anyhow!("lock acquisition failed"))?;
|
|
591
|
+
guard.push_back(Box::new(handle));
|
|
592
|
+
}
|
|
593
|
+
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
594
|
+
}
|
|
630
595
|
}
|
|
596
|
+
self.wake();
|
|
631
597
|
|
|
632
598
|
Ok(())
|
|
633
599
|
}
|
|
@@ -637,17 +603,19 @@ impl EventLoop {
|
|
|
637
603
|
impl EventLoop {
|
|
638
604
|
#[new]
|
|
639
605
|
fn new(py: Python) -> PyResult<Self> {
|
|
606
|
+
let poll = Poll::new()?;
|
|
607
|
+
let waker = Waker::new(poll.registry(), Token(0))?;
|
|
608
|
+
|
|
640
609
|
Ok(Self {
|
|
641
610
|
idle: atomic::AtomicBool::new(false),
|
|
642
|
-
io: Mutex::new(
|
|
611
|
+
io: Mutex::new(poll),
|
|
612
|
+
waker: Arc::new(waker),
|
|
643
613
|
handles_io: papaya::HashMap::with_capacity(128),
|
|
644
614
|
handles_ready: Mutex::new(VecDeque::with_capacity(128)),
|
|
645
615
|
handles_sched: Mutex::new(BinaryHeap::with_capacity(32)),
|
|
646
616
|
epoch: Instant::now(),
|
|
647
617
|
counter_ready: atomic::AtomicUsize::new(0),
|
|
648
618
|
ssock: RwLock::new(None),
|
|
649
|
-
wsock: Mutex::new(None),
|
|
650
|
-
wsock_fd: atomic::AtomicI32::new(-1),
|
|
651
619
|
closed: atomic::AtomicBool::new(false),
|
|
652
620
|
exc_handler: RwLock::new(py.None()),
|
|
653
621
|
exception_handler: RwLock::new(py.None()),
|
|
@@ -900,10 +868,7 @@ impl EventLoop {
|
|
|
900
868
|
guard.push_back(bhandle);
|
|
901
869
|
}
|
|
902
870
|
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
903
|
-
|
|
904
|
-
if self.idle.load(atomic::Ordering::Acquire) {
|
|
905
|
-
self.wake();
|
|
906
|
-
}
|
|
871
|
+
self.wake();
|
|
907
872
|
|
|
908
873
|
handle
|
|
909
874
|
}
|
|
@@ -1160,24 +1125,28 @@ impl EventLoop {
|
|
|
1160
1125
|
}
|
|
1161
1126
|
|
|
1162
1127
|
fn _run(&self, py: Python) -> PyResult<()> {
|
|
1163
|
-
let mut state =
|
|
1128
|
+
let mut state = EventLoopRunState {
|
|
1129
|
+
buf: vec![0; 4096].into_boxed_slice(),
|
|
1130
|
+
events: event::Events::with_capacity(128),
|
|
1131
|
+
read_buf: vec![0; 262_144].into_boxed_slice(),
|
|
1132
|
+
tick_last: 0,
|
|
1133
|
+
};
|
|
1164
1134
|
|
|
1165
1135
|
loop {
|
|
1166
1136
|
if self.stopping.load(atomic::Ordering::Acquire) {
|
|
1167
1137
|
break;
|
|
1168
1138
|
}
|
|
1169
1139
|
if let Err(err) = self.step(py, &mut state) {
|
|
1170
|
-
if err.kind() == std::io::ErrorKind::Interrupted
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1140
|
+
if err.kind() == std::io::ErrorKind::Interrupted {
|
|
1141
|
+
if self.sig_loop_handled.swap(false, atomic::Ordering::Relaxed) {
|
|
1142
|
+
continue;
|
|
1143
|
+
}
|
|
1144
|
+
break;
|
|
1174
1145
|
}
|
|
1175
|
-
self.run_post(&mut state);
|
|
1176
1146
|
return Err(err.into());
|
|
1177
1147
|
}
|
|
1178
1148
|
}
|
|
1179
1149
|
|
|
1180
|
-
self.run_post(&mut state);
|
|
1181
1150
|
Ok(())
|
|
1182
1151
|
}
|
|
1183
1152
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
use pyo3::{prelude
|
|
1
|
+
use pyo3::{IntoPyObjectExt, prelude::*};
|
|
2
2
|
use std::sync::atomic;
|
|
3
3
|
|
|
4
4
|
use crate::{
|
|
@@ -10,7 +10,7 @@ use crate::{
|
|
|
10
10
|
#[cfg(not(PyPy))]
|
|
11
11
|
use crate::py::run_in_ctx1;
|
|
12
12
|
|
|
13
|
-
pub
|
|
13
|
+
pub trait Handle {
|
|
14
14
|
fn run(&self, py: Python, event_loop: &EventLoop, state: &mut EventLoopRunState);
|
|
15
15
|
fn cancelled(&self) -> bool {
|
|
16
16
|
false
|
|
@@ -5,7 +5,7 @@ use std::os::fd::RawFd;
|
|
|
5
5
|
#[cfg(windows)]
|
|
6
6
|
use std::os::windows::io::RawSocket;
|
|
7
7
|
|
|
8
|
-
use mio::{event::Source as MioSource, net::TcpListener
|
|
8
|
+
use mio::{Interest, Registry, Token, event::Source as MioSource, net::TcpListener};
|
|
9
9
|
|
|
10
10
|
pub(crate) enum Source {
|
|
11
11
|
TCPListener(TcpListener),
|
|
@@ -3,10 +3,10 @@ use std::os::fd::{AsRawFd, FromRawFd};
|
|
|
3
3
|
|
|
4
4
|
use anyhow::Result;
|
|
5
5
|
use mio::{
|
|
6
|
-
net::{TcpListener, TcpStream},
|
|
7
6
|
Interest,
|
|
7
|
+
net::{TcpListener, TcpStream},
|
|
8
8
|
};
|
|
9
|
-
use pyo3::{buffer::PyBuffer, prelude::*, types::PyBytes
|
|
9
|
+
use pyo3::{IntoPyObjectExt, buffer::PyBuffer, prelude::*, types::PyBytes};
|
|
10
10
|
use std::{
|
|
11
11
|
borrow::Cow,
|
|
12
12
|
cell::RefCell,
|
rloop-0.1.5/src/utils.rs
ADDED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import threading
|
|
2
|
+
|
|
3
|
+
|
|
1
4
|
def run_loop(loop):
|
|
2
5
|
async def run():
|
|
3
6
|
loop.stop()
|
|
@@ -57,3 +60,39 @@ def test_call_at(loop):
|
|
|
57
60
|
dt = loop.time() - t0
|
|
58
61
|
|
|
59
62
|
assert dt >= delay
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_call_soon_threadsafe(loop):
|
|
66
|
+
calls = []
|
|
67
|
+
|
|
68
|
+
def cb(arg):
|
|
69
|
+
calls.append(arg)
|
|
70
|
+
|
|
71
|
+
def wake(cond):
|
|
72
|
+
with cond:
|
|
73
|
+
cond.notify_all()
|
|
74
|
+
|
|
75
|
+
def stop():
|
|
76
|
+
loop.stop()
|
|
77
|
+
|
|
78
|
+
def trun(cond1, cond2, loop, cb):
|
|
79
|
+
with cond1:
|
|
80
|
+
cond1.wait()
|
|
81
|
+
loop.call_soon_threadsafe(cb, 2)
|
|
82
|
+
with cond2:
|
|
83
|
+
cond2.wait()
|
|
84
|
+
loop.call_soon_threadsafe(cb, 4)
|
|
85
|
+
|
|
86
|
+
cond1 = threading.Condition()
|
|
87
|
+
cond2 = threading.Condition()
|
|
88
|
+
t = threading.Thread(target=trun, args=(cond1, cond2, loop, cb))
|
|
89
|
+
t.start()
|
|
90
|
+
|
|
91
|
+
loop.call_soon(cb, 1)
|
|
92
|
+
loop.call_soon(wake, cond1)
|
|
93
|
+
loop.call_later(0.5, cb, 3)
|
|
94
|
+
loop.call_later(0.6, wake, cond2)
|
|
95
|
+
loop.call_later(1.0, stop)
|
|
96
|
+
loop.run_forever()
|
|
97
|
+
|
|
98
|
+
assert calls == [1, 2, 3, 4]
|
rloop-0.1.3/rloop/_compat.py
DELETED
rloop-0.1.3/src/utils.rs
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
#[cfg(not(Py_GIL_DISABLED))]
|
|
2
|
-
macro_rules! py_allow_threads {
|
|
3
|
-
($py:expr, $func:tt) => {
|
|
4
|
-
$py.allow_threads(|| $func)
|
|
5
|
-
};
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
#[cfg(Py_GIL_DISABLED)]
|
|
9
|
-
macro_rules! py_allow_threads {
|
|
10
|
-
($py:expr, $func:tt) => {
|
|
11
|
-
$func
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
macro_rules! syscall {
|
|
16
|
-
($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
|
|
17
|
-
let res = unsafe { libc::$fn($($arg, )*) };
|
|
18
|
-
if res < 0 {
|
|
19
|
-
Err(std::io::Error::last_os_error())
|
|
20
|
-
} else {
|
|
21
|
-
Ok(res)
|
|
22
|
-
}
|
|
23
|
-
}};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
pub(super) use py_allow_threads;
|
|
27
|
-
pub(crate) use syscall;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|