rloop 0.1.4__tar.gz → 0.1.6__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.4 → rloop-0.1.6}/Cargo.lock +11 -11
- {rloop-0.1.4 → rloop-0.1.6}/Cargo.toml +1 -1
- {rloop-0.1.4 → rloop-0.1.6}/PKG-INFO +2 -2
- {rloop-0.1.4 → rloop-0.1.6}/pyproject.toml +1 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/loop.py +14 -13
- {rloop-0.1.4 → rloop-0.1.6}/src/event_loop.rs +57 -125
- {rloop-0.1.4 → rloop-0.1.6}/src/tcp.rs +4 -4
- {rloop-0.1.4 → rloop-0.1.6}/tests/test_handles.py +39 -0
- {rloop-0.1.4 → rloop-0.1.6}/LICENSE +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/README.md +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/__init__.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/_compat.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/_rloop.pyi +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/exc.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/futures.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/server.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/subprocess.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/transports.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/rloop/utils.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/src/handles.rs +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/src/io.rs +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/src/lib.rs +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/src/log.rs +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/src/py.rs +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/src/server.rs +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/src/sock.rs +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/src/time.rs +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/src/utils.rs +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/tests/conftest.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/tests/tcp/__init__.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/tests/tcp/test_tcp_conn.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/tests/tcp/test_tcp_server.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/tests/test_sockets.py +0 -0
- {rloop-0.1.4 → rloop-0.1.6}/tests/udp/test_udp.py +0 -0
|
@@ -4,9 +4,9 @@ version = 4
|
|
|
4
4
|
|
|
5
5
|
[[package]]
|
|
6
6
|
name = "anyhow"
|
|
7
|
-
version = "1.0.
|
|
7
|
+
version = "1.0.99"
|
|
8
8
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
9
|
-
checksum = "
|
|
9
|
+
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
|
10
10
|
|
|
11
11
|
[[package]]
|
|
12
12
|
name = "autocfg"
|
|
@@ -16,9 +16,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
|
|
16
16
|
|
|
17
17
|
[[package]]
|
|
18
18
|
name = "cc"
|
|
19
|
-
version = "1.2.
|
|
19
|
+
version = "1.2.33"
|
|
20
20
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
21
|
-
checksum = "
|
|
21
|
+
checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f"
|
|
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.175"
|
|
47
47
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
48
|
-
checksum = "
|
|
48
|
+
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
|
49
49
|
|
|
50
50
|
[[package]]
|
|
51
51
|
name = "log"
|
|
@@ -98,9 +98,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
|
|
|
98
98
|
|
|
99
99
|
[[package]]
|
|
100
100
|
name = "proc-macro2"
|
|
101
|
-
version = "1.0.
|
|
101
|
+
version = "1.0.101"
|
|
102
102
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
103
|
-
checksum = "
|
|
103
|
+
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
|
104
104
|
dependencies = [
|
|
105
105
|
"unicode-ident",
|
|
106
106
|
]
|
|
@@ -189,7 +189,7 @@ dependencies = [
|
|
|
189
189
|
|
|
190
190
|
[[package]]
|
|
191
191
|
name = "rloop"
|
|
192
|
-
version = "0.1.
|
|
192
|
+
version = "0.1.6"
|
|
193
193
|
dependencies = [
|
|
194
194
|
"anyhow",
|
|
195
195
|
"libc",
|
|
@@ -228,9 +228,9 @@ dependencies = [
|
|
|
228
228
|
|
|
229
229
|
[[package]]
|
|
230
230
|
name = "syn"
|
|
231
|
-
version = "2.0.
|
|
231
|
+
version = "2.0.106"
|
|
232
232
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
233
|
-
checksum = "
|
|
233
|
+
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
|
234
234
|
dependencies = [
|
|
235
235
|
"proc-macro2",
|
|
236
236
|
"quote",
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rloop
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.6
|
|
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
|
|
@@ -20,7 +21,6 @@ License-File: LICENSE
|
|
|
20
21
|
Summary: An asyncio event loop implemented in Rust
|
|
21
22
|
Keywords: asyncio
|
|
22
23
|
Home-Page: https://github.com/gi0baro/rloop
|
|
23
|
-
Author: Giovanni Barillari <g@baro.dev>
|
|
24
24
|
Author-email: Giovanni Barillari <g@baro.dev>
|
|
25
25
|
License: BSD-3-Clause
|
|
26
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',
|
|
@@ -816,22 +816,22 @@ class RLoop(__BaseLoop, __asyncio.AbstractEventLoop):
|
|
|
816
816
|
try:
|
|
817
817
|
n = sock.send(data)
|
|
818
818
|
except (BlockingIOError, InterruptedError):
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
data = memoryview(data)
|
|
824
|
-
data = data[n:]
|
|
819
|
+
n = 0
|
|
820
|
+
|
|
821
|
+
if n == len(data):
|
|
822
|
+
return
|
|
825
823
|
|
|
826
824
|
fd = sock.fileno()
|
|
827
825
|
self._ensure_fd_no_transport(fd)
|
|
828
826
|
future = _SyncSockWriterFuture(sock, self)
|
|
829
|
-
self.add_writer(fd, self._sock_sendall, future, sock, data)
|
|
827
|
+
self.add_writer(fd, self._sock_sendall, future, sock, memoryview(data), [n])
|
|
830
828
|
return await future
|
|
831
829
|
|
|
832
|
-
def _sock_sendall(self, fut, sock, data):
|
|
830
|
+
def _sock_sendall(self, fut, sock, data, pos):
|
|
831
|
+
start = pos[0]
|
|
832
|
+
|
|
833
833
|
try:
|
|
834
|
-
n = sock.send(data)
|
|
834
|
+
n = sock.send(data[start:])
|
|
835
835
|
except (BlockingIOError, InterruptedError):
|
|
836
836
|
return
|
|
837
837
|
except (SystemExit, KeyboardInterrupt):
|
|
@@ -841,12 +841,13 @@ class RLoop(__BaseLoop, __asyncio.AbstractEventLoop):
|
|
|
841
841
|
self.remove_writer(sock.fileno())
|
|
842
842
|
return
|
|
843
843
|
|
|
844
|
-
|
|
845
|
-
|
|
844
|
+
start += n
|
|
845
|
+
|
|
846
|
+
if start == len(data):
|
|
846
847
|
fut.set_result(None)
|
|
848
|
+
self.remove_writer(sock.fileno())
|
|
847
849
|
else:
|
|
848
|
-
|
|
849
|
-
self.add_writer(sock.fileno(), self._sock_sendall, fut, sock, data)
|
|
850
|
+
pos[0] = start
|
|
850
851
|
|
|
851
852
|
# async def sock_sendto(self, sock, data, address):
|
|
852
853
|
# raise NotImplementedError
|
|
@@ -3,12 +3,12 @@ use std::{
|
|
|
3
3
|
io::Read,
|
|
4
4
|
mem,
|
|
5
5
|
os::fd::{AsRawFd, FromRawFd},
|
|
6
|
-
sync::{Mutex, RwLock, atomic},
|
|
6
|
+
sync::{Arc, Mutex, RwLock, atomic},
|
|
7
7
|
time::{Duration, Instant},
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
use anyhow::Result;
|
|
11
|
-
use mio::{Interest, Poll, Token, event, net::TcpListener};
|
|
11
|
+
use mio::{Interest, Poll, Token, Waker, event, net::TcpListener};
|
|
12
12
|
use pyo3::prelude::*;
|
|
13
13
|
|
|
14
14
|
use crate::{
|
|
@@ -19,13 +19,9 @@ use crate::{
|
|
|
19
19
|
server::Server,
|
|
20
20
|
tcp::{TCPReadHandle, TCPServer, TCPServerRef, TCPTransport, TCPWriteHandle},
|
|
21
21
|
time::Timer,
|
|
22
|
-
utils::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),
|
|
@@ -47,7 +43,6 @@ 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 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);
|
|
123
|
+
}
|
|
124
|
+
if let Err(ref err) = res
|
|
125
|
+
&& err.kind() == std::io::ErrorKind::Interrupted
|
|
126
|
+
{
|
|
127
|
+
// if we got an interrupt, we retry ready events (as we might need to process signals)
|
|
128
|
+
let _ = io.poll(&mut state.events, Some(Duration::from_millis(0)));
|
|
166
129
|
}
|
|
167
|
-
let res = py.allow_threads(|| {
|
|
168
|
-
let mut io = self.io.lock().unwrap();
|
|
169
|
-
let res = io.poll(&mut state.events, sched_time.map(Duration::from_micros));
|
|
170
|
-
if idle_swap {
|
|
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
|
-
}
|
|
178
|
-
}
|
|
179
|
-
res
|
|
180
|
-
});
|
|
181
|
-
state.tick_last = Instant::now().duration_since(self.epoch).as_micros();
|
|
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,
|
|
@@ -258,15 +202,15 @@ impl EventLoop {
|
|
|
258
202
|
handle: &PyHandleData,
|
|
259
203
|
handles: &mut VecDeque<BoxedHandle>,
|
|
260
204
|
) {
|
|
261
|
-
if let Some(cbr) = &handle.cbr
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
205
|
+
if let Some(cbr) = &handle.cbr
|
|
206
|
+
&& event.is_readable()
|
|
207
|
+
{
|
|
208
|
+
handles.push_back(Box::new(cbr.clone_ref(py)));
|
|
265
209
|
}
|
|
266
|
-
if let Some(cbw) = &handle.cbw
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
210
|
+
if let Some(cbw) = &handle.cbw
|
|
211
|
+
&& event.is_writable()
|
|
212
|
+
{
|
|
213
|
+
handles.push_back(Box::new(cbw.clone_ref(py)));
|
|
270
214
|
}
|
|
271
215
|
}
|
|
272
216
|
|
|
@@ -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) {
|
|
@@ -437,11 +382,10 @@ impl EventLoop {
|
|
|
437
382
|
|
|
438
383
|
#[inline(always)]
|
|
439
384
|
pub(crate) fn tcp_stream_close(&self, py: Python, fd: usize) {
|
|
440
|
-
if let Some(transport) = self.tcp_transports.pin().remove(&fd)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
// transport.drop_ref(py);
|
|
385
|
+
if let Some(transport) = self.tcp_transports.pin().remove(&fd)
|
|
386
|
+
&& let Some(lfd) = transport.borrow(py).lfd
|
|
387
|
+
{
|
|
388
|
+
self.tcp_lstreams.pin().get(&lfd).map(|v| v.pin().remove(&fd));
|
|
445
389
|
}
|
|
446
390
|
}
|
|
447
391
|
|
|
@@ -486,9 +430,7 @@ impl EventLoop {
|
|
|
486
430
|
guard.push_back(Box::new(handle));
|
|
487
431
|
}
|
|
488
432
|
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
489
|
-
|
|
490
|
-
self.wake();
|
|
491
|
-
}
|
|
433
|
+
self.wake();
|
|
492
434
|
|
|
493
435
|
Ok(())
|
|
494
436
|
}
|
|
@@ -509,9 +451,7 @@ impl EventLoop {
|
|
|
509
451
|
guard.push_back(Box::new(handle));
|
|
510
452
|
}
|
|
511
453
|
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
512
|
-
|
|
513
|
-
self.wake();
|
|
514
|
-
}
|
|
454
|
+
self.wake();
|
|
515
455
|
|
|
516
456
|
Ok(())
|
|
517
457
|
}
|
|
@@ -532,9 +472,7 @@ impl EventLoop {
|
|
|
532
472
|
guard.push_back(Box::new(handle));
|
|
533
473
|
}
|
|
534
474
|
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
535
|
-
|
|
536
|
-
self.wake();
|
|
537
|
-
}
|
|
475
|
+
self.wake();
|
|
538
476
|
|
|
539
477
|
Ok(())
|
|
540
478
|
}
|
|
@@ -559,9 +497,7 @@ impl EventLoop {
|
|
|
559
497
|
.map_err(|_| anyhow::anyhow!("lock acquisition failed"))?;
|
|
560
498
|
guard.push(timer);
|
|
561
499
|
}
|
|
562
|
-
|
|
563
|
-
self.wake();
|
|
564
|
-
}
|
|
500
|
+
self.wake();
|
|
565
501
|
|
|
566
502
|
Ok(())
|
|
567
503
|
}
|
|
@@ -592,9 +528,7 @@ impl EventLoop {
|
|
|
592
528
|
.map_err(|_| anyhow::anyhow!("lock acquisition failed"))?;
|
|
593
529
|
guard.push(timer);
|
|
594
530
|
}
|
|
595
|
-
|
|
596
|
-
self.wake();
|
|
597
|
-
}
|
|
531
|
+
self.wake();
|
|
598
532
|
|
|
599
533
|
Ok(())
|
|
600
534
|
}
|
|
@@ -625,9 +559,7 @@ impl EventLoop {
|
|
|
625
559
|
.map_err(|_| anyhow::anyhow!("lock acquisition failed"))?;
|
|
626
560
|
guard.push(timer);
|
|
627
561
|
}
|
|
628
|
-
|
|
629
|
-
self.wake();
|
|
630
|
-
}
|
|
562
|
+
self.wake();
|
|
631
563
|
|
|
632
564
|
Ok(())
|
|
633
565
|
}
|
|
@@ -660,9 +592,7 @@ impl EventLoop {
|
|
|
660
592
|
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
661
593
|
}
|
|
662
594
|
}
|
|
663
|
-
|
|
664
|
-
self.wake();
|
|
665
|
-
}
|
|
595
|
+
self.wake();
|
|
666
596
|
|
|
667
597
|
Ok(())
|
|
668
598
|
}
|
|
@@ -672,17 +602,19 @@ impl EventLoop {
|
|
|
672
602
|
impl EventLoop {
|
|
673
603
|
#[new]
|
|
674
604
|
fn new(py: Python) -> PyResult<Self> {
|
|
605
|
+
let poll = Poll::new()?;
|
|
606
|
+
let waker = Waker::new(poll.registry(), Token(0))?;
|
|
607
|
+
|
|
675
608
|
Ok(Self {
|
|
676
609
|
idle: atomic::AtomicBool::new(false),
|
|
677
|
-
io: Mutex::new(
|
|
610
|
+
io: Mutex::new(poll),
|
|
611
|
+
waker: Arc::new(waker),
|
|
678
612
|
handles_io: papaya::HashMap::with_capacity(128),
|
|
679
613
|
handles_ready: Mutex::new(VecDeque::with_capacity(128)),
|
|
680
614
|
handles_sched: Mutex::new(BinaryHeap::with_capacity(32)),
|
|
681
615
|
epoch: Instant::now(),
|
|
682
616
|
counter_ready: atomic::AtomicUsize::new(0),
|
|
683
617
|
ssock: RwLock::new(None),
|
|
684
|
-
wsock: Mutex::new(None),
|
|
685
|
-
wsock_fd: atomic::AtomicI32::new(-1),
|
|
686
618
|
closed: atomic::AtomicBool::new(false),
|
|
687
619
|
exc_handler: RwLock::new(py.None()),
|
|
688
620
|
exception_handler: RwLock::new(py.None()),
|
|
@@ -935,10 +867,7 @@ impl EventLoop {
|
|
|
935
867
|
guard.push_back(bhandle);
|
|
936
868
|
}
|
|
937
869
|
self.counter_ready.fetch_add(1, atomic::Ordering::Release);
|
|
938
|
-
|
|
939
|
-
if self.idle.load(atomic::Ordering::Acquire) {
|
|
940
|
-
self.wake();
|
|
941
|
-
}
|
|
870
|
+
self.wake();
|
|
942
871
|
|
|
943
872
|
handle
|
|
944
873
|
}
|
|
@@ -1195,7 +1124,12 @@ impl EventLoop {
|
|
|
1195
1124
|
}
|
|
1196
1125
|
|
|
1197
1126
|
fn _run(&self, py: Python) -> PyResult<()> {
|
|
1198
|
-
let mut state =
|
|
1127
|
+
let mut state = EventLoopRunState {
|
|
1128
|
+
buf: vec![0; 4096].into_boxed_slice(),
|
|
1129
|
+
events: event::Events::with_capacity(128),
|
|
1130
|
+
read_buf: vec![0; 262_144].into_boxed_slice(),
|
|
1131
|
+
tick_last: 0,
|
|
1132
|
+
};
|
|
1199
1133
|
|
|
1200
1134
|
loop {
|
|
1201
1135
|
if self.stopping.load(atomic::Ordering::Acquire) {
|
|
@@ -1208,12 +1142,10 @@ impl EventLoop {
|
|
|
1208
1142
|
}
|
|
1209
1143
|
break;
|
|
1210
1144
|
}
|
|
1211
|
-
self.run_post(&mut state);
|
|
1212
1145
|
return Err(err.into());
|
|
1213
1146
|
}
|
|
1214
1147
|
}
|
|
1215
1148
|
|
|
1216
|
-
self.run_post(&mut state);
|
|
1217
1149
|
Ok(())
|
|
1218
1150
|
}
|
|
1219
1151
|
}
|
|
@@ -605,10 +605,10 @@ impl TCPReadHandle {
|
|
|
605
605
|
#[inline]
|
|
606
606
|
fn recv_eof(&self, py: Python, event_loop: &EventLoop, transport: &TCPTransport) -> bool {
|
|
607
607
|
event_loop.tcp_stream_rem(self.fd, Interest::READABLE);
|
|
608
|
-
if let Ok(pyr) = transport.proto.call_method0(py, pyo3::intern!(py, "eof_received"))
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
608
|
+
if let Ok(pyr) = transport.proto.call_method0(py, pyo3::intern!(py, "eof_received"))
|
|
609
|
+
&& let Ok(true) = pyr.is_truthy(py)
|
|
610
|
+
{
|
|
611
|
+
return false;
|
|
612
612
|
}
|
|
613
613
|
transport.close_from_read_handle(py, event_loop)
|
|
614
614
|
}
|
|
@@ -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]
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|