rloop 0.1.0a2__tar.gz → 0.1.0a3__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.
@@ -1,12 +1,12 @@
1
1
  # This file is automatically @generated by Cargo.
2
2
  # It is not intended for manual editing.
3
- version = 3
3
+ version = 4
4
4
 
5
5
  [[package]]
6
6
  name = "anyhow"
7
- version = "1.0.93"
7
+ version = "1.0.94"
8
8
  source = "registry+https://github.com/rust-lang/crates.io-index"
9
- checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
9
+ checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
10
10
 
11
11
  [[package]]
12
12
  name = "autocfg"
@@ -22,9 +22,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
22
22
 
23
23
  [[package]]
24
24
  name = "cc"
25
- version = "1.1.37"
25
+ version = "1.2.5"
26
26
  source = "registry+https://github.com/rust-lang/crates.io-index"
27
- checksum = "40545c26d092346d8a8dab71ee48e7685a7a9cba76e634790c215b41a4a7b4cf"
27
+ checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
28
28
  dependencies = [
29
29
  "shlex",
30
30
  ]
@@ -37,9 +37,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
37
37
 
38
38
  [[package]]
39
39
  name = "crossbeam-utils"
40
- version = "0.8.20"
40
+ version = "0.8.21"
41
41
  source = "registry+https://github.com/rust-lang/crates.io-index"
42
- checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
42
+ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
43
43
 
44
44
  [[package]]
45
45
  name = "dashmap"
@@ -67,12 +67,6 @@ version = "0.5.0"
67
67
  source = "registry+https://github.com/rust-lang/crates.io-index"
68
68
  checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
69
69
 
70
- [[package]]
71
- name = "hermit-abi"
72
- version = "0.3.9"
73
- source = "registry+https://github.com/rust-lang/crates.io-index"
74
- checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
75
-
76
70
  [[package]]
77
71
  name = "indoc"
78
72
  version = "2.0.5"
@@ -81,19 +75,9 @@ checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
81
75
 
82
76
  [[package]]
83
77
  name = "libc"
84
- version = "0.2.162"
78
+ version = "0.2.169"
85
79
  source = "registry+https://github.com/rust-lang/crates.io-index"
86
- checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
87
-
88
- [[package]]
89
- name = "libmimalloc-sys"
90
- version = "0.1.39"
91
- source = "registry+https://github.com/rust-lang/crates.io-index"
92
- checksum = "23aa6811d3bd4deb8a84dde645f943476d13b248d818edcf8ce0b2f37f036b44"
93
- dependencies = [
94
- "cc",
95
- "libc",
96
- ]
80
+ checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
97
81
 
98
82
  [[package]]
99
83
  name = "lock_api"
@@ -120,22 +104,12 @@ dependencies = [
120
104
  "autocfg",
121
105
  ]
122
106
 
123
- [[package]]
124
- name = "mimalloc"
125
- version = "0.1.43"
126
- source = "registry+https://github.com/rust-lang/crates.io-index"
127
- checksum = "68914350ae34959d83f732418d51e2427a794055d0b9529f48259ac07af65633"
128
- dependencies = [
129
- "libmimalloc-sys",
130
- ]
131
-
132
107
  [[package]]
133
108
  name = "mio"
134
- version = "1.0.2"
109
+ version = "1.0.3"
135
110
  source = "registry+https://github.com/rust-lang/crates.io-index"
136
- checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
111
+ checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
137
112
  dependencies = [
138
- "hermit-abi",
139
113
  "libc",
140
114
  "log",
141
115
  "wasi",
@@ -163,24 +137,24 @@ dependencies = [
163
137
 
164
138
  [[package]]
165
139
  name = "portable-atomic"
166
- version = "1.9.0"
140
+ version = "1.10.0"
167
141
  source = "registry+https://github.com/rust-lang/crates.io-index"
168
- checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
142
+ checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
169
143
 
170
144
  [[package]]
171
145
  name = "proc-macro2"
172
- version = "1.0.89"
146
+ version = "1.0.92"
173
147
  source = "registry+https://github.com/rust-lang/crates.io-index"
174
- checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
148
+ checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
175
149
  dependencies = [
176
150
  "unicode-ident",
177
151
  ]
178
152
 
179
153
  [[package]]
180
154
  name = "pyo3"
181
- version = "0.23.1"
155
+ version = "0.23.3"
182
156
  source = "registry+https://github.com/rust-lang/crates.io-index"
183
- checksum = "7ebb0c0cc0de9678e53be9ccf8a2ab53045e6e3a8be03393ceccc5e7396ccb40"
157
+ checksum = "e484fd2c8b4cb67ab05a318f1fd6fa8f199fcc30819f08f07d200809dba26c15"
184
158
  dependencies = [
185
159
  "anyhow",
186
160
  "cfg-if",
@@ -197,9 +171,9 @@ dependencies = [
197
171
 
198
172
  [[package]]
199
173
  name = "pyo3-build-config"
200
- version = "0.23.1"
174
+ version = "0.23.3"
201
175
  source = "registry+https://github.com/rust-lang/crates.io-index"
202
- checksum = "80e3ce69c4ec34476534b490e412b871ba03a82e35604c3dfb95fcb6bfb60c09"
176
+ checksum = "dc0e0469a84f208e20044b98965e1561028180219e35352a2afaf2b942beff3b"
203
177
  dependencies = [
204
178
  "once_cell",
205
179
  "python3-dll-a",
@@ -208,9 +182,9 @@ dependencies = [
208
182
 
209
183
  [[package]]
210
184
  name = "pyo3-ffi"
211
- version = "0.23.1"
185
+ version = "0.23.3"
212
186
  source = "registry+https://github.com/rust-lang/crates.io-index"
213
- checksum = "3b09f311c76b36dfd6dd6f7fa6f9f18e7e46a1c937110d283e80b12ba2468a75"
187
+ checksum = "eb1547a7f9966f6f1a0f0227564a9945fe36b90da5a93b3933fc3dc03fae372d"
214
188
  dependencies = [
215
189
  "libc",
216
190
  "pyo3-build-config",
@@ -218,9 +192,9 @@ dependencies = [
218
192
 
219
193
  [[package]]
220
194
  name = "pyo3-macros"
221
- version = "0.23.1"
195
+ version = "0.23.3"
222
196
  source = "registry+https://github.com/rust-lang/crates.io-index"
223
- checksum = "fd4f74086536d1e1deaff99ec0387481fb3325c82e4e48be0e75ab3d3fcb487a"
197
+ checksum = "fdb6da8ec6fa5cedd1626c886fc8749bdcbb09424a86461eb8cdf096b7c33257"
224
198
  dependencies = [
225
199
  "proc-macro2",
226
200
  "pyo3-macros-backend",
@@ -230,9 +204,9 @@ dependencies = [
230
204
 
231
205
  [[package]]
232
206
  name = "pyo3-macros-backend"
233
- version = "0.23.1"
207
+ version = "0.23.3"
234
208
  source = "registry+https://github.com/rust-lang/crates.io-index"
235
- checksum = "9e77dfeb76b32bbf069144a5ea0a36176ab59c8db9ce28732d0f06f096bbfbc8"
209
+ checksum = "38a385202ff5a92791168b1136afae5059d3ac118457bb7bc304c197c2d33e7d"
236
210
  dependencies = [
237
211
  "heck",
238
212
  "proc-macro2",
@@ -243,9 +217,9 @@ dependencies = [
243
217
 
244
218
  [[package]]
245
219
  name = "python3-dll-a"
246
- version = "0.2.10"
220
+ version = "0.2.12"
247
221
  source = "registry+https://github.com/rust-lang/crates.io-index"
248
- checksum = "bd0b78171a90d808b319acfad166c4790d9e9759bbc14ac8273fe133673dd41b"
222
+ checksum = "9b66f9171950e674e64bad3456e11bb3cca108e5c34844383cfe277f45c8a7a8"
249
223
  dependencies = [
250
224
  "cc",
251
225
  ]
@@ -261,24 +235,22 @@ dependencies = [
261
235
 
262
236
  [[package]]
263
237
  name = "redox_syscall"
264
- version = "0.5.7"
238
+ version = "0.5.8"
265
239
  source = "registry+https://github.com/rust-lang/crates.io-index"
266
- checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
240
+ checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
267
241
  dependencies = [
268
242
  "bitflags",
269
243
  ]
270
244
 
271
245
  [[package]]
272
246
  name = "rloop"
273
- version = "0.1.0-alpha2"
247
+ version = "0.1.0-alpha3"
274
248
  dependencies = [
275
249
  "anyhow",
276
250
  "dashmap",
277
- "mimalloc",
278
251
  "mio",
279
252
  "pyo3",
280
253
  "socket2",
281
- "tikv-jemallocator",
282
254
  ]
283
255
 
284
256
  [[package]]
@@ -301,9 +273,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
301
273
 
302
274
  [[package]]
303
275
  name = "socket2"
304
- version = "0.5.7"
276
+ version = "0.5.8"
305
277
  source = "registry+https://github.com/rust-lang/crates.io-index"
306
- checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
278
+ checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
307
279
  dependencies = [
308
280
  "libc",
309
281
  "windows-sys",
@@ -311,9 +283,9 @@ dependencies = [
311
283
 
312
284
  [[package]]
313
285
  name = "syn"
314
- version = "2.0.87"
286
+ version = "2.0.90"
315
287
  source = "registry+https://github.com/rust-lang/crates.io-index"
316
- checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
288
+ checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
317
289
  dependencies = [
318
290
  "proc-macro2",
319
291
  "quote",
@@ -326,31 +298,11 @@ version = "0.12.16"
326
298
  source = "registry+https://github.com/rust-lang/crates.io-index"
327
299
  checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
328
300
 
329
- [[package]]
330
- name = "tikv-jemalloc-sys"
331
- version = "0.6.0+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7"
332
- source = "registry+https://github.com/rust-lang/crates.io-index"
333
- checksum = "cd3c60906412afa9c2b5b5a48ca6a5abe5736aec9eb48ad05037a677e52e4e2d"
334
- dependencies = [
335
- "cc",
336
- "libc",
337
- ]
338
-
339
- [[package]]
340
- name = "tikv-jemallocator"
341
- version = "0.6.0"
342
- source = "registry+https://github.com/rust-lang/crates.io-index"
343
- checksum = "4cec5ff18518d81584f477e9bfdf957f5bb0979b0bac3af4ca30b5b3ae2d2865"
344
- dependencies = [
345
- "libc",
346
- "tikv-jemalloc-sys",
347
- ]
348
-
349
301
  [[package]]
350
302
  name = "unicode-ident"
351
- version = "1.0.13"
303
+ version = "1.0.14"
352
304
  source = "registry+https://github.com/rust-lang/crates.io-index"
353
- checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
305
+ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
354
306
 
355
307
  [[package]]
356
308
  name = "unindent"
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rloop"
3
- version = "0.1.0-alpha2"
3
+ version = "0.1.0-alpha3"
4
4
  description = "An asyncio event loop implemented in Rust"
5
5
  authors = ["Giovanni Barillari <g@baro.dev>"]
6
6
  license = "BSD-3-Clause"
@@ -36,12 +36,6 @@ mio = { version = "=1.0", features = ["net", "os-ext", "os-poll"] }
36
36
  pyo3 = { version = "=0.23", features = ["anyhow", "extension-module", "generate-import-lib"] }
37
37
  socket2 = "=0.5"
38
38
 
39
- [target.'cfg(any(target_os = "freebsd", target_os = "windows"))'.dependencies]
40
- mimalloc = { version = "0.1.43", default-features = false, features = ["local_dynamic_tls"] }
41
-
42
- [target.'cfg(not(any(target_os = "freebsd", target_os = "windows")))'.dependencies]
43
- tikv-jemallocator = { version = "0.6.0", default-features = false, features = ["disable_initial_exec_tls"] }
44
-
45
39
  [profile.release]
46
40
  codegen-units = 1
47
41
  debug = false
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: rloop
3
- Version: 0.1.0a2
3
+ Version: 0.1.0a3
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: BSD License
@@ -95,3 +95,6 @@ known-first-party = ['rloop', 'tests']
95
95
 
96
96
  [tool.pytest.ini_options]
97
97
  asyncio_mode = 'auto'
98
+
99
+ [tool.uv]
100
+ package = false
@@ -35,8 +35,6 @@ class EventLoop:
35
35
  _watcher_child: Any
36
36
 
37
37
  def _run(self): ...
38
- def _wake(self): ...
39
- def _call_soon(self, callback, args, context) -> CBHandle: ...
40
38
  def _call_later(self, delay, callback, args, context) -> TimerHandle: ...
41
39
  def _reader_add(self, fd, callback, args, context) -> CBHandle: ...
42
40
  def _reader_rem(self, fd) -> bool: ...
@@ -45,7 +43,7 @@ class EventLoop:
45
43
  def _sig_add(self, sig, callback, context): ...
46
44
  def _sig_rem(self, sig) -> bool: ...
47
45
  def _sig_clear(self): ...
48
- def _sig_handle(self, sig) -> bool: ...
49
- def _sig_ceval(self, noop: Any): ...
50
46
  def _ssock_set(self, fd): ...
51
47
  def _ssock_del(self, fd): ...
48
+ def call_soon(self, callback, *args, context=None) -> CBHandle: ...
49
+ def call_soon_threadsafe(self, callback, *args, context=None) -> CBHandle: ...
@@ -210,19 +210,16 @@ class RLoop(__BaseLoop, __asyncio.AbstractEventLoop):
210
210
  # def _timer_handle_cancelled(self, handle):
211
211
  # raise NotImplementedError
212
212
 
213
- def call_soon(self, callback, *args, context=None) -> CBHandle:
214
- return self._call_soon(callback, args, context or _copy_context())
215
-
216
213
  def call_later(self, delay, callback, *args, context=None) -> Union[CBHandle, TimerHandle]:
217
214
  if delay <= 0:
218
- return self._call_soon(callback, args, context or _copy_context())
215
+ return self.call_soon(callback, *args, context=context or _copy_context())
219
216
  delay = round(delay * 1_000_000)
220
217
  return self._call_later(delay, callback, args, context or _copy_context())
221
218
 
222
219
  def call_at(self, when, callback, *args, context=None) -> Union[CBHandle, TimerHandle]:
223
220
  delay = round((when - self.time()) * 1_000_000)
224
221
  if delay <= 0:
225
- return self._call_soon(callback, args, context or _copy_context())
222
+ return self.call_soon(callback, *args, context=context or _copy_context())
226
223
  return self._call_later(delay, callback, args, context or _copy_context())
227
224
 
228
225
  def time(self) -> float:
@@ -269,11 +266,6 @@ class RLoop(__BaseLoop, __asyncio.AbstractEventLoop):
269
266
  return task
270
267
 
271
268
  #: threads methods
272
- def call_soon_threadsafe(self, callback, *args, context=None) -> CBHandle:
273
- rv = self._call_soon(callback, args, context or self._base_ctx)
274
- self._wake()
275
- return rv
276
-
277
269
  def run_in_executor(self, executor, fn, *args):
278
270
  if _iscoroutine(fn) or _iscoroutinefunction(fn):
279
271
  raise TypeError('Coroutines cannot be used with executors')
@@ -675,41 +667,21 @@ class RLoop(__BaseLoop, __asyncio.AbstractEventLoop):
675
667
  try:
676
668
  self._ssock_r.setblocking(False)
677
669
  self._ssock_w.setblocking(False)
678
- self._ssock_set(self._ssock_w.fileno())
670
+ self._ssock_set(self._ssock_r.fileno(), self._ssock_w.fileno())
679
671
  except Exception:
680
- self._ssock_del()
681
- self._ssock_r.close()
672
+ self._ssock_del(self._ssock_r.fileno())
682
673
  self._ssock_w = None
683
674
  self._ssock_r = None
684
675
  raise
685
676
 
686
- self._reader_add(self._ssock_r.fileno(), self._ssock_reader, (), _copy_context())
687
-
688
677
  def _ssock_stop(self):
689
678
  if not self._ssock_w:
690
679
  raise RuntimeError('self-socket has not been setup')
691
680
 
692
- self._reader_rem(self._ssock_r.fileno())
693
- self._ssock_del()
694
- self._ssock_r.close()
681
+ self._ssock_del(self._ssock_r.fileno())
695
682
  self._ssock_w = None
696
683
  self._ssock_r = None
697
684
 
698
- def _ssock_reader(self):
699
- sigdata = b''
700
- while True:
701
- try:
702
- data = self._ssock_r.recv(65536)
703
- if not data:
704
- break
705
- sigdata += data
706
- except InterruptedError:
707
- continue
708
- except BlockingIOError:
709
- break
710
- if sigdata and self._sig_listening:
711
- self._signals_invoke(sigdata)
712
-
713
685
  def add_signal_handler(self, sig, callback, *args):
714
686
  if not self.__is_main_thread():
715
687
  raise ValueError('Signals can only be handled from the main thread')
@@ -718,10 +690,11 @@ class RLoop(__BaseLoop, __asyncio.AbstractEventLoop):
718
690
  raise TypeError('Coroutines cannot be used as signals handlers')
719
691
 
720
692
  self._check_closed()
721
- self._sig_add(sig, callback, _copy_context())
693
+ self._check_signal(sig)
694
+ self._sig_add(sig, callback, args, _copy_context())
722
695
  try:
723
696
  # register a dummy signal handler so Python will write the signal no in the wakeup fd
724
- signal.signal(sig, self.__sighandler)
697
+ signal.signal(sig, _noop)
725
698
  # set SA_RESTART to limit EINTR occurrences
726
699
  signal.siginterrupt(sig, False)
727
700
  except OSError as exc:
@@ -734,13 +707,32 @@ class RLoop(__BaseLoop, __asyncio.AbstractEventLoop):
734
707
  if not self._is_main_thread():
735
708
  raise ValueError('Signals can only be handled from the main thread')
736
709
 
737
- return self._sig_rem(sig)
710
+ if not self._sig_rem(sig):
711
+ return False
712
+
713
+ if sig == signal.SIGINT:
714
+ handler = signal.default_int_handler
715
+ else:
716
+ handler = signal.SIG_DFL
717
+
718
+ try:
719
+ signal.signal(sig, handler)
720
+ except OSError as exc:
721
+ if exc.errno == errno.EINVAL:
722
+ raise RuntimeError(f'signum {sig} cannot be caught')
723
+ raise
724
+
725
+ return True
738
726
 
739
727
  def __is_main_thread(self):
740
728
  return threading.main_thread().ident == threading.current_thread().ident
741
729
 
742
- def __sighandler(self, signum, frame):
743
- self._signals.add(signum)
730
+ def _check_signal(self, sig):
731
+ if not isinstance(sig, int):
732
+ raise TypeError(f'sig must be an int, not {sig!r}')
733
+
734
+ if sig not in signal.valid_signals():
735
+ raise ValueError(f'invalid signal number {sig}')
744
736
 
745
737
  def __set_sig_wfd(self, fd):
746
738
  if fd >= 0:
@@ -786,25 +778,6 @@ class RLoop(__BaseLoop, __asyncio.AbstractEventLoop):
786
778
 
787
779
  self._sig_clear()
788
780
 
789
- def _signals_invoke(self, data):
790
- self._sig_ceval(_noop)
791
- self._sig_loop_handled = True
792
-
793
- sigs = self._signals.copy()
794
- self._signals.clear()
795
- for signum in data:
796
- if not signum:
797
- continue
798
- sigs.discard(signum)
799
- self._signal_handle(signum)
800
-
801
- for signum in sigs:
802
- self._signal_handle(signum)
803
-
804
- def _signal_handle(self, signum):
805
- if not self._sig_handle(signum):
806
- self._sig_ceval(_noop)
807
-
808
781
  #: task factory
809
782
  def set_task_factory(self, factory):
810
783
  self._task_factory = factory
@@ -75,5 +75,5 @@ def _ipaddr_info(host, port, family, type, proto, flowinfo=0, scopeid=0):
75
75
  return None
76
76
 
77
77
 
78
- def _noop():
78
+ def _noop(*args, **kwargs):
79
79
  return
@@ -1,7 +1,7 @@
1
1
  use std::{
2
2
  cmp::Ordering,
3
3
  collections::{BinaryHeap, VecDeque},
4
- io::Write,
4
+ io::{Read, Write},
5
5
  mem,
6
6
  os::fd::FromRawFd,
7
7
  sync::{atomic, Arc, Mutex, RwLock},
@@ -11,13 +11,10 @@ use std::{
11
11
  use anyhow::Result;
12
12
  use dashmap::DashMap;
13
13
  use mio::{Events, Interest, Poll, Token};
14
- use pyo3::{
15
- prelude::*,
16
- types::{PyDict, PySet, PyTuple},
17
- };
14
+ use pyo3::{prelude::*, types::PyDict};
18
15
 
19
16
  use crate::handles::{CBHandle, TimerHandle};
20
- use crate::io::Source;
17
+ use crate::io::{InternalIO, Source};
21
18
  use crate::py::{copy_context, weakset};
22
19
 
23
20
  struct Timer {
@@ -51,7 +48,19 @@ impl Ord for Timer {
51
48
  }
52
49
  }
53
50
 
51
+ enum IOHandle {
52
+ Internal(IOHandleData),
53
+ Py(PyIOHandleData),
54
+ }
55
+
54
56
  struct IOHandleData {
57
+ source: Source,
58
+ #[allow(dead_code)]
59
+ interest: Interest,
60
+ handle: InternalIO,
61
+ }
62
+
63
+ struct PyIOHandleData {
55
64
  source: Source,
56
65
  interest: Interest,
57
66
  cbr: Option<Py<CBHandle>>,
@@ -60,20 +69,21 @@ struct IOHandleData {
60
69
 
61
70
  #[pyclass(frozen, subclass)]
62
71
  struct EventLoop {
72
+ idle: atomic::AtomicBool,
63
73
  io: Arc<Mutex<Poll>>,
64
- handles_io: Arc<DashMap<Token, IOHandleData>>,
74
+ handles_io: Arc<DashMap<Token, IOHandle>>,
65
75
  handles_ready: Arc<Mutex<VecDeque<Py<CBHandle>>>>,
66
76
  handles_sched: Arc<Mutex<BinaryHeap<Timer>>>,
67
77
  epoch: Instant,
68
78
  counter_ready: atomic::AtomicUsize,
69
79
  counter_io: atomic::AtomicU16,
70
- ssock: Arc<RwLock<Option<socket2::Socket>>>,
80
+ ssock: Arc<RwLock<Option<(socket2::Socket, socket2::Socket)>>>,
71
81
  tick_last_poll: atomic::AtomicU64,
72
82
  closed: atomic::AtomicBool,
73
83
  exc_handler: Arc<RwLock<PyObject>>,
74
84
  exception_handler: Arc<RwLock<PyObject>>,
75
85
  executor: Arc<RwLock<PyObject>>,
76
- sig_handlers: Arc<DashMap<u16, Py<CBHandle>>>,
86
+ sig_handlers: Arc<DashMap<u8, Py<CBHandle>>>,
77
87
  sig_listening: atomic::AtomicBool,
78
88
  sig_loop_handled: atomic::AtomicBool,
79
89
  sig_wfd: Arc<RwLock<PyObject>>,
@@ -89,8 +99,6 @@ struct EventLoop {
89
99
  _asyncgens: PyObject,
90
100
  #[pyo3(get)]
91
101
  _base_ctx: PyObject,
92
- #[pyo3(get)]
93
- _signals: Py<PySet>,
94
102
  }
95
103
 
96
104
  impl EventLoop {
@@ -104,16 +112,9 @@ impl EventLoop {
104
112
  if self.counter_ready.load(atomic::Ordering::Relaxed) > 0 {
105
113
  sched_time = Some(0);
106
114
  // we want to skip polling when unnecessary:
107
- // if we have I/O handles, we need to check the time since last poll
108
- // otherwise we don't need to poll at all
109
- // NOTE: >1 as we always have signal socket reader
110
- if self.counter_io.load(atomic::Ordering::Relaxed) > 1 {
111
- // we max out at 250μs poll intervals
112
- let tick = Instant::now().duration_since(self.epoch).as_micros() as u64;
113
- if (tick - self.tick_last_poll.load(atomic::Ordering::Relaxed)) < 250 {
114
- skip_poll = true;
115
- }
116
- } else {
115
+ // if work is ready we check the time since last poll and skip for max 250μs
116
+ let tick = Instant::now().duration_since(self.epoch).as_micros() as u64;
117
+ if (tick - self.tick_last_poll.load(atomic::Ordering::Relaxed)) < 250 {
117
118
  skip_poll = true;
118
119
  }
119
120
  } else {
@@ -133,6 +134,9 @@ impl EventLoop {
133
134
  true => Ok(()),
134
135
  false => py.allow_threads(|| {
135
136
  let mut io = self.io.lock().unwrap();
137
+ if sched_time.is_none() {
138
+ self.idle.store(true, atomic::Ordering::Relaxed);
139
+ }
136
140
  let res = io.poll(&mut io_events, sched_time.map(Duration::from_millis));
137
141
  if let Err(ref err) = res {
138
142
  if err.kind() == std::io::ErrorKind::Interrupted {
@@ -140,6 +144,7 @@ impl EventLoop {
140
144
  let _ = io.poll(&mut io_events, Some(Duration::from_millis(0)));
141
145
  }
142
146
  }
147
+ self.idle.store(false, atomic::Ordering::Relaxed);
143
148
  self.tick_last_poll.store(
144
149
  Instant::now().duration_since(self.epoch).as_micros() as u64,
145
150
  atomic::Ordering::Relaxed,
@@ -148,20 +153,28 @@ impl EventLoop {
148
153
  }),
149
154
  };
150
155
  let mut guard_cb = self.handles_ready.lock().unwrap();
151
- self.counter_ready.fetch_sub(guard_cb.len(), atomic::Ordering::Relaxed);
156
+ let mut cb_handles = mem::replace(&mut *guard_cb, VecDeque::with_capacity(128));
157
+ self.counter_ready
158
+ .fetch_sub(cb_handles.len(), atomic::Ordering::Relaxed);
159
+ drop(guard_cb);
152
160
 
153
161
  for event in &io_events {
154
162
  // NOTE: cancellation is not necessary as we have custom futures
155
- if let Some(handle) = self.handles_io.get(&event.token()) {
156
- if let Some(cbr) = &handle.cbr {
157
- if event.is_readable() {
158
- guard_cb.push_back(cbr.clone_ref(py));
159
- }
160
- }
161
- if let Some(cbw) = &handle.cbw {
162
- if event.is_writable() {
163
- guard_cb.push_back(cbw.clone_ref(py));
163
+ if let Some(io_handle) = self.handles_io.get(&event.token()) {
164
+ match io_handle.value() {
165
+ IOHandle::Py(handle) => {
166
+ if let Some(cbr) = &handle.cbr {
167
+ if event.is_readable() {
168
+ cb_handles.push_back(cbr.clone_ref(py));
169
+ }
170
+ }
171
+ if let Some(cbw) = &handle.cbw {
172
+ if event.is_writable() {
173
+ cb_handles.push_back(cbw.clone_ref(py));
174
+ }
175
+ }
164
176
  }
177
+ IOHandle::Internal(handle) => self.handle_internal_io(handle, py, &mut cb_handles),
165
178
  }
166
179
  }
167
180
  }
@@ -175,15 +188,13 @@ impl EventLoop {
175
188
  if timer.when > tick {
176
189
  break;
177
190
  }
178
- guard_cb.push_back(guard_sched.pop().unwrap().handle);
191
+ cb_handles.push_back(guard_sched.pop().unwrap().handle);
179
192
  }
180
193
  }
181
194
  }
182
195
  drop(guard_sched);
183
196
 
184
197
  // callbacks
185
- let mut cb_handles = mem::replace(&mut *guard_cb, VecDeque::with_capacity(128));
186
- drop(guard_cb);
187
198
  while let Some(cb_handle) = cb_handles.pop_front() {
188
199
  // let handle = match cb_handle {
189
200
  // Handle::Callback(ref v) => v.get(),
@@ -207,9 +218,71 @@ impl EventLoop {
207
218
  poll_result
208
219
  }
209
220
 
221
+ #[inline]
222
+ fn handle_internal_io(&self, handle_data: &IOHandleData, py: Python, handles_ready: &mut VecDeque<Py<CBHandle>>) {
223
+ match handle_data.handle {
224
+ InternalIO::Signals => {
225
+ let sigs = py.allow_threads(|| self.read_from_self());
226
+ for sig in sigs {
227
+ self.sig_handle(py, sig, handles_ready);
228
+ }
229
+ }
230
+ }
231
+ }
232
+
233
+ #[inline]
234
+ fn sig_handle(&self, py: Python, sig: u8, handles_ready: &mut VecDeque<Py<CBHandle>>) {
235
+ if let Some(pyhandle) = self.sig_handlers.get(&sig) {
236
+ self.sig_loop_handled.store(true, atomic::Ordering::Relaxed);
237
+
238
+ if pyhandle.get().cancelled.load(atomic::Ordering::Relaxed) {
239
+ self._sig_rem(sig);
240
+ } else {
241
+ handles_ready.push_back(pyhandle.clone_ref(py));
242
+ }
243
+ }
244
+ }
245
+
246
+ #[inline(always)]
247
+ fn wake(&self) {
248
+ let mut guard = self.ssock.write().unwrap();
249
+ if let Some((_, sockw)) = guard.as_mut() {
250
+ let _ = sockw.write(b"\0");
251
+ }
252
+ }
253
+
254
+ fn read_from_self(&self) -> Vec<u8> {
255
+ let mut guard = self.ssock.write().unwrap();
256
+ if let Some((sockr, _)) = guard.as_mut() {
257
+ let mut buf = [0; 4096];
258
+ let mut len = 0;
259
+ loop {
260
+ match sockr.read(&mut buf[len..]) {
261
+ Ok(0) => break,
262
+ Ok(readn) => {
263
+ len += readn;
264
+ }
265
+ Err(err) if err.kind() == std::io::ErrorKind::Interrupted => continue,
266
+ Err(_) => break,
267
+ }
268
+ }
269
+ if self.sig_listening.load(atomic::Ordering::Relaxed) {
270
+ let mut sigs = Vec::with_capacity(len);
271
+ for sig in &buf[..len] {
272
+ if *sig == 0 {
273
+ continue;
274
+ }
275
+ sigs.push(*sig);
276
+ }
277
+ return sigs;
278
+ }
279
+ }
280
+ Vec::new()
281
+ }
282
+
210
283
  #[inline]
211
284
  fn reader_rem(&self, token: Token) -> Result<bool> {
212
- if let Some((_, mut item)) = self.handles_io.remove(&token) {
285
+ if let Some((_, IOHandle::Py(mut item))) = self.handles_io.remove(&token) {
213
286
  let guard_poll = self.io.lock().unwrap();
214
287
  match item.interest {
215
288
  Interest::READABLE => {
@@ -221,12 +294,12 @@ impl EventLoop {
221
294
  guard_poll.registry().reregister(&mut item.source, token, interest)?;
222
295
  self.handles_io.insert(
223
296
  token,
224
- IOHandleData {
297
+ IOHandle::Py(PyIOHandleData {
225
298
  source: item.source,
226
299
  interest,
227
300
  cbr: None,
228
301
  cbw: item.cbw,
229
- },
302
+ }),
230
303
  );
231
304
  }
232
305
  }
@@ -237,7 +310,7 @@ impl EventLoop {
237
310
 
238
311
  #[inline]
239
312
  fn writer_rem(&self, token: Token) -> Result<bool> {
240
- if let Some((_, mut item)) = self.handles_io.remove(&token) {
313
+ if let Some((_, IOHandle::Py(mut item))) = self.handles_io.remove(&token) {
241
314
  let guard_poll = self.io.lock().unwrap();
242
315
  match item.interest {
243
316
  Interest::WRITABLE => {
@@ -249,12 +322,12 @@ impl EventLoop {
249
322
  guard_poll.registry().reregister(&mut item.source, token, interest)?;
250
323
  self.handles_io.insert(
251
324
  token,
252
- IOHandleData {
325
+ IOHandle::Py(PyIOHandleData {
253
326
  source: item.source,
254
327
  interest,
255
328
  cbr: item.cbr,
256
329
  cbw: None,
257
- },
330
+ }),
258
331
  );
259
332
  }
260
333
  }
@@ -263,14 +336,6 @@ impl EventLoop {
263
336
  Ok(false)
264
337
  }
265
338
 
266
- #[inline]
267
- fn wake(&self) {
268
- let mut guard = self.ssock.write().unwrap();
269
- if let Some(sock) = guard.as_mut() {
270
- let _ = sock.write(b"\0");
271
- }
272
- }
273
-
274
339
  fn log_exception(&self, py: Python, ctx: Bound<PyDict>) -> PyResult<PyObject> {
275
340
  let handler = self.exc_handler.read().unwrap();
276
341
  handler.call1(py, (ctx, self.exception_handler.read().unwrap().clone_ref(py)))
@@ -282,6 +347,7 @@ impl EventLoop {
282
347
  #[new]
283
348
  fn new(py: Python) -> PyResult<Self> {
284
349
  Ok(Self {
350
+ idle: atomic::AtomicBool::new(false),
285
351
  io: Arc::new(Mutex::new(Poll::new()?)),
286
352
  handles_io: Arc::new(DashMap::with_capacity(128)),
287
353
  handles_ready: Arc::new(Mutex::new(VecDeque::with_capacity(128))),
@@ -309,7 +375,6 @@ impl EventLoop {
309
375
  watcher_child: Arc::new(RwLock::new(py.None())),
310
376
  _asyncgens: weakset(py)?.unbind(),
311
377
  _base_ctx: copy_context(py)?.unbind(),
312
- _signals: PySet::empty(py)?.into_pyobject(py)?.unbind(),
313
378
  })
314
379
  }
315
380
 
@@ -411,16 +476,6 @@ impl EventLoop {
411
476
  self.sig_listening.store(val, atomic::Ordering::Relaxed);
412
477
  }
413
478
 
414
- #[getter(_sig_loop_handled)]
415
- fn _get_sig_loop_handled(&self) -> bool {
416
- self.sig_loop_handled.load(atomic::Ordering::Relaxed)
417
- }
418
-
419
- #[setter(_sig_loop_handled)]
420
- fn _set_sig_loop_handled(&self, val: bool) {
421
- self.sig_loop_handled.store(val, atomic::Ordering::Relaxed);
422
- }
423
-
424
479
  #[getter(_sig_wfd)]
425
480
  fn _get_sig_wfd(&self, py: Python) -> PyObject {
426
481
  self.sig_wfd.read().unwrap().clone_ref(py)
@@ -476,21 +531,84 @@ impl EventLoop {
476
531
  *guard = factory;
477
532
  }
478
533
 
479
- fn _ssock_set(&self, fd: i32) {
534
+ fn _ssock_set(&self, fd_r: usize, fd_w: usize) -> PyResult<()> {
480
535
  let mut guard = self.ssock.write().unwrap();
481
- *guard = Some(unsafe { socket2::Socket::from_raw_fd(fd) });
536
+ *guard = Some(unsafe {
537
+ (
538
+ #[allow(clippy::cast_possible_wrap)]
539
+ socket2::Socket::from_raw_fd(fd_r as i32),
540
+ #[allow(clippy::cast_possible_wrap)]
541
+ socket2::Socket::from_raw_fd(fd_w as i32),
542
+ )
543
+ });
544
+
545
+ let token = Token(fd_r);
546
+ let mut source = Source::FD(fd_r.try_into()?);
547
+ let interest = Interest::READABLE;
548
+ let guard_poll = self.io.lock().unwrap();
549
+ guard_poll.registry().register(&mut source, token, interest)?;
550
+ drop(guard_poll);
551
+ self.handles_io.insert(
552
+ token,
553
+ IOHandle::Internal(IOHandleData {
554
+ source,
555
+ interest,
556
+ handle: InternalIO::Signals,
557
+ }),
558
+ );
559
+
560
+ Ok(())
482
561
  }
483
562
 
484
- fn _ssock_del(&self) {
563
+ fn _ssock_del(&self, fd_r: usize) -> PyResult<()> {
564
+ let token = Token(fd_r);
565
+ if let Some((_, IOHandle::Internal(mut item))) = self.handles_io.remove(&token) {
566
+ let guard_poll = self.io.lock().unwrap();
567
+ guard_poll.registry().deregister(&mut item.source)?;
568
+ }
485
569
  self.ssock.write().unwrap().take();
570
+ Ok(())
486
571
  }
487
572
 
488
- fn _call_soon(&self, py: Python, callback: PyObject, args: PyObject, context: PyObject) -> PyResult<Py<CBHandle>> {
489
- let handle = Py::new(py, CBHandle::new(callback, args, context))?;
573
+ #[pyo3(signature = (callback, *args, context=None))]
574
+ fn call_soon(
575
+ &self,
576
+ py: Python,
577
+ callback: PyObject,
578
+ args: PyObject,
579
+ context: Option<PyObject>,
580
+ ) -> PyResult<Py<CBHandle>> {
581
+ let handle = Py::new(
582
+ py,
583
+ CBHandle::new(callback, args, context.unwrap_or_else(|| self._base_ctx.clone_ref(py))),
584
+ )?;
585
+ let mut guard = self.handles_ready.lock().unwrap();
586
+ guard.push_back(handle.clone_ref(py));
587
+ self.counter_ready.fetch_add(1, atomic::Ordering::Relaxed);
588
+ drop(guard);
589
+ Ok(handle)
590
+ }
591
+
592
+ #[pyo3(signature = (callback, *args, context=None))]
593
+ fn call_soon_threadsafe(
594
+ &self,
595
+ py: Python,
596
+ callback: PyObject,
597
+ args: PyObject,
598
+ context: Option<PyObject>,
599
+ ) -> PyResult<Py<CBHandle>> {
600
+ let handle = Py::new(
601
+ py,
602
+ CBHandle::new(callback, args, context.unwrap_or_else(|| self._base_ctx.clone_ref(py))),
603
+ )?;
490
604
  let mut guard = self.handles_ready.lock().unwrap();
491
605
  guard.push_back(handle.clone_ref(py));
492
606
  self.counter_ready.fetch_add(1, atomic::Ordering::Relaxed);
493
607
  drop(guard);
608
+ // wake when necessary
609
+ if self.idle.load(atomic::Ordering::Relaxed) {
610
+ py.allow_threads(|| self.wake());
611
+ }
494
612
  Ok(handle)
495
613
  }
496
614
 
@@ -521,33 +639,34 @@ impl EventLoop {
521
639
  ) -> PyResult<Py<CBHandle>> {
522
640
  let token = Token(fd);
523
641
  let handle = Py::new(py, CBHandle::new(callback, args, context))?;
524
- match self.handles_io.get_mut(&token) {
525
- Some(mut item) => {
526
- let interest = item.interest | Interest::READABLE;
642
+ if let Some(mut item) = self.handles_io.get_mut(&token) {
643
+ if let IOHandle::Py(data) = item.value_mut() {
644
+ let interest = data.interest | Interest::READABLE;
527
645
  let guard_poll = self.io.lock().unwrap();
528
- guard_poll.registry().reregister(&mut item.source, token, interest)?;
646
+ guard_poll.registry().reregister(&mut data.source, token, interest)?;
529
647
  drop(guard_poll);
530
- item.interest = interest;
531
- item.cbr = Some(handle.clone_ref(py));
532
- }
533
- _ => {
534
- let mut source = Source::FD(fd.try_into()?);
535
- let interest = Interest::READABLE;
536
- let guard_poll = self.io.lock().unwrap();
537
- guard_poll.registry().register(&mut source, token, interest)?;
538
- drop(guard_poll);
539
- self.handles_io.insert(
540
- token,
541
- IOHandleData {
542
- source,
543
- interest,
544
- cbr: Some(handle.clone_ref(py)),
545
- cbw: None,
546
- },
547
- );
548
- self.counter_io.fetch_add(1, atomic::Ordering::Relaxed);
648
+ data.interest = interest;
649
+ data.cbr = Some(handle.clone_ref(py));
650
+ return Ok(handle);
549
651
  }
550
652
  }
653
+
654
+ let mut source = Source::FD(fd.try_into()?);
655
+ let interest = Interest::READABLE;
656
+ let guard_poll = self.io.lock().unwrap();
657
+ guard_poll.registry().register(&mut source, token, interest)?;
658
+ drop(guard_poll);
659
+ self.handles_io.insert(
660
+ token,
661
+ IOHandle::Py(PyIOHandleData {
662
+ source,
663
+ interest,
664
+ cbr: Some(handle.clone_ref(py)),
665
+ cbw: None,
666
+ }),
667
+ );
668
+ self.counter_io.fetch_add(1, atomic::Ordering::Relaxed);
669
+
551
670
  Ok(handle)
552
671
  }
553
672
 
@@ -566,33 +685,35 @@ impl EventLoop {
566
685
  ) -> PyResult<Py<CBHandle>> {
567
686
  let token = Token(fd);
568
687
  let handle = Py::new(py, CBHandle::new(callback, args, context))?;
569
- match self.handles_io.get_mut(&token) {
570
- Some(mut item) => {
571
- let interest = item.interest | Interest::WRITABLE;
572
- let guard_poll = self.io.lock().unwrap();
573
- guard_poll.registry().reregister(&mut item.source, token, interest)?;
574
- drop(guard_poll);
575
- item.interest = interest;
576
- item.cbw = Some(handle.clone_ref(py));
577
- }
578
- _ => {
579
- let mut source = Source::FD(fd.try_into()?);
580
- let interest = Interest::WRITABLE;
688
+
689
+ if let Some(mut item) = self.handles_io.get_mut(&token) {
690
+ if let IOHandle::Py(data) = item.value_mut() {
691
+ let interest = data.interest | Interest::WRITABLE;
581
692
  let guard_poll = self.io.lock().unwrap();
582
- guard_poll.registry().register(&mut source, token, interest)?;
693
+ guard_poll.registry().reregister(&mut data.source, token, interest)?;
583
694
  drop(guard_poll);
584
- self.handles_io.insert(
585
- token,
586
- IOHandleData {
587
- source,
588
- interest,
589
- cbr: None,
590
- cbw: Some(handle.clone_ref(py)),
591
- },
592
- );
593
- self.counter_io.fetch_add(1, atomic::Ordering::Relaxed);
695
+ data.interest = interest;
696
+ data.cbw = Some(handle.clone_ref(py));
697
+ return Ok(handle);
594
698
  }
595
699
  }
700
+
701
+ let mut source = Source::FD(fd.try_into()?);
702
+ let interest = Interest::WRITABLE;
703
+ let guard_poll = self.io.lock().unwrap();
704
+ guard_poll.registry().register(&mut source, token, interest)?;
705
+ drop(guard_poll);
706
+ self.handles_io.insert(
707
+ token,
708
+ IOHandle::Py(PyIOHandleData {
709
+ source,
710
+ interest,
711
+ cbr: None,
712
+ cbw: Some(handle.clone_ref(py)),
713
+ }),
714
+ );
715
+ self.counter_io.fetch_add(1, atomic::Ordering::Relaxed);
716
+
596
717
  Ok(handle)
597
718
  }
598
719
 
@@ -601,14 +722,13 @@ impl EventLoop {
601
722
  self.writer_rem(token)
602
723
  }
603
724
 
604
- fn _sig_add(&self, py: Python, sig: u16, callback: PyObject, context: PyObject) -> Result<()> {
605
- let args = PyTuple::empty(py).into_pyobject(py)?.into_any().unbind();
725
+ fn _sig_add(&self, py: Python, sig: u8, callback: PyObject, args: PyObject, context: PyObject) -> Result<()> {
606
726
  let handle = Py::new(py, CBHandle::new(callback, args, context))?;
607
727
  self.sig_handlers.insert(sig, handle);
608
728
  Ok(())
609
729
  }
610
730
 
611
- fn _sig_rem(&self, sig: u16) -> bool {
731
+ fn _sig_rem(&self, sig: u8) -> bool {
612
732
  self.sig_handlers.remove(&sig).is_some()
613
733
  }
614
734
 
@@ -616,26 +736,6 @@ impl EventLoop {
616
736
  self.sig_handlers.clear();
617
737
  }
618
738
 
619
- fn _sig_handle(&self, py: Python, sig: u16) -> bool {
620
- if let Some(handle) = self.sig_handlers.get(&sig) {
621
- handle.get().run(py);
622
- return true;
623
- }
624
- false
625
- }
626
-
627
- fn _sig_ceval(&self, noop: PyObject) {
628
- let noop_ptr = noop.as_ptr();
629
- unsafe {
630
- pyo3::ffi::PyErr_CheckSignals();
631
- pyo3::ffi::compat::PyObject_CallNoArgs(noop_ptr);
632
- }
633
- }
634
-
635
- fn _wake(&self) {
636
- self.wake();
637
- }
638
-
639
739
  fn _run(&self, py: Python) -> PyResult<()> {
640
740
  loop {
641
741
  if self.stopping.load(atomic::Ordering::Relaxed) {
@@ -3,8 +3,9 @@ use std::sync::atomic;
3
3
 
4
4
  // pub(crate) enum Handle {
5
5
  // Callback(Py<CBHandle>),
6
+ // Signal,
6
7
  // // Timer(Py<TimerHandle>),
7
- // IO(Arc<CBHandle>),
8
+ // // IO(Arc<CBHandle>),
8
9
  // }
9
10
 
10
11
  #[pyclass(frozen)]
@@ -21,6 +21,10 @@ pub(crate) enum Source {
21
21
  FD(RawSocket),
22
22
  }
23
23
 
24
+ pub(crate) enum InternalIO {
25
+ Signals,
26
+ }
27
+
24
28
  #[cfg(windows)]
25
29
  #[derive(Debug)]
26
30
  pub struct SourceRawSocket<'a>(pub &'a RawSocket);
@@ -1,11 +1,3 @@
1
- #[cfg(not(any(target_os = "freebsd", target_os = "windows")))]
2
- #[global_allocator]
3
- static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
4
-
5
- #[cfg(any(target_os = "freebsd", target_os = "windows"))]
6
- #[global_allocator]
7
- static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
8
-
9
1
  use pyo3::prelude::*;
10
2
  use std::sync::OnceLock;
11
3
 
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