rsloop 0.1.45__tar.gz → 0.1.46__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.
Files changed (239) hide show
  1. {rsloop-0.1.45 → rsloop-0.1.46}/Cargo.lock +12 -38
  2. {rsloop-0.1.45 → rsloop-0.1.46}/Cargo.toml +3 -4
  3. {rsloop-0.1.45 → rsloop-0.1.46}/PKG-INFO +1 -1
  4. {rsloop-0.1.45 → rsloop-0.1.46}/pyproject.toml +1 -1
  5. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/connections.rs +4 -4
  6. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/methods.rs +2 -2
  7. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/servers.rs +1 -1
  8. {rsloop-0.1.45 → rsloop-0.1.46}/src/engine/callbacks.rs +2 -2
  9. {rsloop-0.1.45 → rsloop-0.1.46}/src/engine/dispatcher.rs +22 -22
  10. {rsloop-0.1.45 → rsloop-0.1.46}/src/engine/loop_core.rs +55 -17
  11. {rsloop-0.1.45 → rsloop-0.1.46}/src/lib.rs +1 -0
  12. {rsloop-0.1.45 → rsloop-0.1.46}/src/profiler.rs +22 -0
  13. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/process/core_events.rs +6 -6
  14. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/process/worker.rs +2 -2
  15. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/accept.rs +4 -4
  16. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/core_events.rs +7 -7
  17. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/core_protocol.rs +5 -5
  18. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/core_write.rs +5 -3
  19. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/py_transport.rs +1 -1
  20. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/reader.rs +3 -3
  21. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/reader_task.rs +3 -3
  22. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/server.rs +1 -1
  23. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/socket_transport.rs +3 -3
  24. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/tls_session.rs +1 -1
  25. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/tls_transport.rs +2 -2
  26. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/writer.rs +3 -3
  27. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/tls/material.rs +2 -2
  28. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/tls/mod.rs +2 -2
  29. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/builder.rs +4 -19
  30. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/driver/mod.rs +8 -1
  31. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/lib.rs +1 -1
  32. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/net/udp.rs +3 -1
  33. {rsloop-0.1.45 → rsloop-0.1.46}/uv.lock +1 -1
  34. {rsloop-0.1.45 → rsloop-0.1.46}/.cargo/config.toml +0 -0
  35. {rsloop-0.1.45 → rsloop-0.1.46}/.github/workflows/anyio.yml +0 -0
  36. {rsloop-0.1.45 → rsloop-0.1.46}/.github/workflows/kani.yml +0 -0
  37. {rsloop-0.1.45 → rsloop-0.1.46}/.github/workflows/mkdocs.yml +0 -0
  38. {rsloop-0.1.45 → rsloop-0.1.46}/.github/workflows/tests.yml +0 -0
  39. {rsloop-0.1.45 → rsloop-0.1.46}/.github/workflows/update-version.yml +0 -0
  40. {rsloop-0.1.45 → rsloop-0.1.46}/.github/workflows/wheels.yml +0 -0
  41. {rsloop-0.1.45 → rsloop-0.1.46}/.gitignore +0 -0
  42. {rsloop-0.1.45 → rsloop-0.1.46}/.vscode/settings.json +0 -0
  43. {rsloop-0.1.45 → rsloop-0.1.46}/LICENSE +0 -0
  44. {rsloop-0.1.45 → rsloop-0.1.46}/README.md +0 -0
  45. {rsloop-0.1.45 → rsloop-0.1.46}/benches/README.md +0 -0
  46. {rsloop-0.1.45 → rsloop-0.1.46}/benches/check_regression.py +0 -0
  47. {rsloop-0.1.45 → rsloop-0.1.46}/benches/compare_event_loops.py +0 -0
  48. {rsloop-0.1.45 → rsloop-0.1.46}/benches/workload_matrix.py +0 -0
  49. {rsloop-0.1.45 → rsloop-0.1.46}/build.rs +0 -0
  50. {rsloop-0.1.45 → rsloop-0.1.46}/docs/development.md +0 -0
  51. {rsloop-0.1.45 → rsloop-0.1.46}/docs/examples.md +0 -0
  52. {rsloop-0.1.45 → rsloop-0.1.46}/docs/getting-started.md +0 -0
  53. {rsloop-0.1.45 → rsloop-0.1.46}/docs/how-it-works.md +0 -0
  54. {rsloop-0.1.45 → rsloop-0.1.46}/docs/index.md +0 -0
  55. {rsloop-0.1.45 → rsloop-0.1.46}/docs/project-structure.md +0 -0
  56. {rsloop-0.1.45 → rsloop-0.1.46}/docs/rsloop.png +0 -0
  57. {rsloop-0.1.45 → rsloop-0.1.46}/docs/rust-extensions.md +0 -0
  58. {rsloop-0.1.45 → rsloop-0.1.46}/docs/verification.md +0 -0
  59. {rsloop-0.1.45 → rsloop-0.1.46}/examples/01_basics.py +0 -0
  60. {rsloop-0.1.45 → rsloop-0.1.46}/examples/02_fd_and_sockets.py +0 -0
  61. {rsloop-0.1.45 → rsloop-0.1.46}/examples/03_streams.py +0 -0
  62. {rsloop-0.1.45 → rsloop-0.1.46}/examples/04_unix_and_accepted_socket.py +0 -0
  63. {rsloop-0.1.45 → rsloop-0.1.46}/examples/05_pipes_signals_subprocesses.py +0 -0
  64. {rsloop-0.1.45 → rsloop-0.1.46}/examples/README.md +0 -0
  65. {rsloop-0.1.45 → rsloop-0.1.46}/examples/fastapi_service.py +0 -0
  66. {rsloop-0.1.45 → rsloop-0.1.46}/examples/picows_server.py +0 -0
  67. {rsloop-0.1.45 → rsloop-0.1.46}/examples/picows_test.py +0 -0
  68. {rsloop-0.1.45 → rsloop-0.1.46}/examples/wsbench_websockets.py +0 -0
  69. {rsloop-0.1.45 → rsloop-0.1.46}/justfile +0 -0
  70. {rsloop-0.1.45 → rsloop-0.1.46}/mkdocs.yml +0 -0
  71. {rsloop-0.1.45 → rsloop-0.1.46}/pyrightconfig.json +0 -0
  72. {rsloop-0.1.45 → rsloop-0.1.46}/python/rsloop/__init__.py +0 -0
  73. {rsloop-0.1.45 → rsloop-0.1.46}/python/rsloop/__init__.pyi +0 -0
  74. {rsloop-0.1.45 → rsloop-0.1.46}/python/rsloop/_bootstrap.py +0 -0
  75. {rsloop-0.1.45 → rsloop-0.1.46}/python/rsloop/_loop.pyi +0 -0
  76. {rsloop-0.1.45 → rsloop-0.1.46}/python/rsloop/_loop_compat.py +0 -0
  77. {rsloop-0.1.45 → rsloop-0.1.46}/python/rsloop/_profile.py +0 -0
  78. {rsloop-0.1.45 → rsloop-0.1.46}/python/rsloop/_run.py +0 -0
  79. {rsloop-0.1.45 → rsloop-0.1.46}/python/rsloop/py.typed +0 -0
  80. {rsloop-0.1.45 → rsloop-0.1.46}/qualirs.toml +0 -0
  81. {rsloop-0.1.45 → rsloop-0.1.46}/scripts/build-pgo-wheels.sh +0 -0
  82. {rsloop-0.1.45 → rsloop-0.1.46}/scripts/build-wheels.sh +0 -0
  83. {rsloop-0.1.45 → rsloop-0.1.46}/scripts/generate_test_tls_certs.py +0 -0
  84. {rsloop-0.1.45 → rsloop-0.1.46}/scripts/prepare_anyio_rsloop_tests.py +0 -0
  85. {rsloop-0.1.45 → rsloop-0.1.46}/scripts/python-versions.sh +0 -0
  86. {rsloop-0.1.45 → rsloop-0.1.46}/scripts/run_python_tests.py +0 -0
  87. {rsloop-0.1.45 → rsloop-0.1.46}/scripts/run_rust_tests.py +0 -0
  88. {rsloop-0.1.45 → rsloop-0.1.46}/scripts/test-supported-pythons.sh +0 -0
  89. {rsloop-0.1.45 → rsloop-0.1.46}/src/async_event.rs +0 -0
  90. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/asyncgens.rs +0 -0
  91. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/asyncio_cache.rs +0 -0
  92. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/executor.rs +0 -0
  93. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/ffi_helpers.rs +0 -0
  94. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/lifecycle.rs +0 -0
  95. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/pipes.rs +0 -0
  96. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/pre_exec.rs +0 -0
  97. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/process_handles.rs +0 -0
  98. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/process_spawn.rs +0 -0
  99. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/process_stdio.rs +0 -0
  100. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/signals.rs +0 -0
  101. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/sock_ops.rs +0 -0
  102. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/socket_connect.rs +0 -0
  103. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/sockets.rs +0 -0
  104. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/spawn_env.rs +0 -0
  105. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/tasks.rs +0 -0
  106. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/tls_params.rs +0 -0
  107. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api/watchers.rs +0 -0
  108. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/loop_api.rs +0 -0
  109. {rsloop-0.1.45 → rsloop-0.1.46}/src/bindings/mod.rs +0 -0
  110. {rsloop-0.1.45 → rsloop-0.1.46}/src/blocking.rs +0 -0
  111. {rsloop-0.1.45 → rsloop-0.1.46}/src/build_metadata.rs +0 -0
  112. {rsloop-0.1.45 → rsloop-0.1.46}/src/context.rs +0 -0
  113. {rsloop-0.1.45 → rsloop-0.1.46}/src/engine/commands.rs +0 -0
  114. {rsloop-0.1.45 → rsloop-0.1.46}/src/engine/dispatcher/timer_entry.rs +0 -0
  115. {rsloop-0.1.45 → rsloop-0.1.46}/src/engine/mod.rs +0 -0
  116. {rsloop-0.1.45 → rsloop-0.1.46}/src/errors.rs +0 -0
  117. {rsloop-0.1.45 → rsloop-0.1.46}/src/module_init.rs +0 -0
  118. {rsloop-0.1.45 → rsloop-0.1.46}/src/platform/fd/mod.rs +0 -0
  119. {rsloop-0.1.45 → rsloop-0.1.46}/src/platform/fd/windows.rs +0 -0
  120. {rsloop-0.1.45 → rsloop-0.1.46}/src/platform/mod.rs +0 -0
  121. {rsloop-0.1.45 → rsloop-0.1.46}/src/platform/windows_vibeio.rs +0 -0
  122. {rsloop-0.1.45 → rsloop-0.1.46}/src/python_names.rs +0 -0
  123. {rsloop-0.1.45 → rsloop-0.1.46}/src/rust_async.rs +0 -0
  124. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/mod.rs +0 -0
  125. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/process/core_protocol.rs +0 -0
  126. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/process/core_state.rs +0 -0
  127. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/process/mod.rs +0 -0
  128. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/process/params.rs +0 -0
  129. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/process/py_pipes.rs +0 -0
  130. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/process/py_transport.rs +0 -0
  131. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/process/spawn.rs +0 -0
  132. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/buffers.rs +0 -0
  133. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/builder.rs +0 -0
  134. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/connect.rs +0 -0
  135. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/core_state.rs +0 -0
  136. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/fast.rs +0 -0
  137. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/io_targets.rs +0 -0
  138. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/mod.rs +0 -0
  139. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/pipe_transport.rs +0 -0
  140. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/platform.rs +0 -0
  141. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/poll.rs +0 -0
  142. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/protocol.rs +0 -0
  143. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/py_server.rs +0 -0
  144. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/server_core.rs +0 -0
  145. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/server_types.rs +0 -0
  146. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/stats.rs +0 -0
  147. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/tuning.rs +0 -0
  148. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/worker.rs +0 -0
  149. {rsloop-0.1.45 → rsloop-0.1.46}/src/transport/stream/write_queue.rs +0 -0
  150. {rsloop-0.1.45 → rsloop-0.1.46}/src/verification.rs +0 -0
  151. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/UPSTREAM.md +0 -0
  152. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/blocking/default.rs +0 -0
  153. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/blocking/mod.rs +0 -0
  154. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/driver/iocp.rs +0 -0
  155. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/driver/kqueue.rs +0 -0
  156. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/driver/mio.rs +0 -0
  157. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/driver/mock.rs +0 -0
  158. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/driver/uring.rs +0 -0
  159. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/executor.rs +0 -0
  160. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/fd_inner.rs +0 -0
  161. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/fs/file.rs +0 -0
  162. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/fs/metadata.rs +0 -0
  163. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/fs/mod.rs +0 -0
  164. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/fs/open_options.rs +0 -0
  165. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/io/buf.rs +0 -0
  166. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/io/mod.rs +0 -0
  167. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/io/pipe.rs +0 -0
  168. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/io/splice.rs +0 -0
  169. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/io/stdio.rs +0 -0
  170. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/io/util.rs +0 -0
  171. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/net/mod.rs +0 -0
  172. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/net/tcp/listener.rs +0 -0
  173. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/net/tcp/mod.rs +0 -0
  174. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/net/tcp/stream.rs +0 -0
  175. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/net/unix/listener.rs +0 -0
  176. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/net/unix/mod.rs +0 -0
  177. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/net/unix/stream.rs +0 -0
  178. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/accept.rs +0 -0
  179. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/accept_unix.rs +0 -0
  180. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/connect.rs +0 -0
  181. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/fsync.rs +0 -0
  182. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/hard_link.rs +0 -0
  183. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/io_util.rs +0 -0
  184. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/mkdir.rs +0 -0
  185. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/mod.rs +0 -0
  186. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/open.rs +0 -0
  187. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/read.rs +0 -0
  188. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/readat.rs +0 -0
  189. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/readiness.rs +0 -0
  190. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/readv.rs +0 -0
  191. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/recv.rs +0 -0
  192. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/recvfrom.rs +0 -0
  193. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/rename.rs +0 -0
  194. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/send.rs +0 -0
  195. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/sendto.rs +0 -0
  196. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/splice.rs +0 -0
  197. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/statx.rs +0 -0
  198. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/symlink.rs +0 -0
  199. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/unlink.rs +0 -0
  200. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/waitpid.rs +0 -0
  201. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/write.rs +0 -0
  202. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/writeat.rs +0 -0
  203. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/op/writev.rs +0 -0
  204. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/process/mod.rs +0 -0
  205. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/process/reaper.rs +0 -0
  206. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/signal/mod.rs +0 -0
  207. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/signal/unix.rs +0 -0
  208. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/signal/windows.rs +0 -0
  209. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/task.rs +0 -0
  210. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/time/interval.rs +0 -0
  211. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/time/mod.rs +0 -0
  212. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/time/sleep.rs +0 -0
  213. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/time/timeout.rs +0 -0
  214. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/timer.rs +0 -0
  215. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/util/async_wrap.rs +0 -0
  216. {rsloop-0.1.45 → rsloop-0.1.46}/src/vibeio/util/mod.rs +0 -0
  217. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/_smoke.py +0 -0
  218. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/aiohttp_test.py +0 -0
  219. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/anyio_test.py +0 -0
  220. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/daphne_test.py +0 -0
  221. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/django_asgi_test.py +0 -0
  222. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/falcon_test.py +0 -0
  223. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/fastapi_test.py +0 -0
  224. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/faststream_test.py +0 -0
  225. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/hypercorn_test.py +0 -0
  226. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/litestar_granian_test.py +0 -0
  227. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/litestar_test.py +0 -0
  228. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/mangum_test.py +0 -0
  229. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/quart_test.py +0 -0
  230. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/sanic_test.py +0 -0
  231. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/starlette_test.py +0 -0
  232. {rsloop-0.1.45 → rsloop-0.1.46}/tests/packages/uvicorn_test.py +0 -0
  233. {rsloop-0.1.45 → rsloop-0.1.46}/tests/proptest-regressions/transport/stream/fast.txt +0 -0
  234. {rsloop-0.1.45 → rsloop-0.1.46}/tests/test_compat.py +0 -0
  235. {rsloop-0.1.45 → rsloop-0.1.46}/tests/test_free_threading.py +0 -0
  236. {rsloop-0.1.45 → rsloop-0.1.46}/tests/test_public_api.py +0 -0
  237. {rsloop-0.1.45 → rsloop-0.1.46}/tests/test_run.py +0 -0
  238. {rsloop-0.1.45 → rsloop-0.1.46}/tests/test_stream_reader.py +0 -0
  239. {rsloop-0.1.45 → rsloop-0.1.46}/tests/test_tls.py +0 -0
@@ -197,15 +197,9 @@ dependencies = [
197
197
 
198
198
  [[package]]
199
199
  name = "bitflags"
200
- version = "1.3.2"
200
+ version = "2.13.1"
201
201
  source = "registry+https://github.com/rust-lang/crates.io-index"
202
- checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
203
-
204
- [[package]]
205
- name = "bitflags"
206
- version = "2.13.0"
207
- source = "registry+https://github.com/rust-lang/crates.io-index"
208
- checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
202
+ checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
209
203
 
210
204
  [[package]]
211
205
  name = "blocking"
@@ -522,11 +516,12 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
522
516
 
523
517
  [[package]]
524
518
  name = "io-uring"
525
- version = "0.6.4"
519
+ version = "0.7.14"
526
520
  source = "registry+https://github.com/rust-lang/crates.io-index"
527
- checksum = "595a0399f411a508feb2ec1e970a4a30c249351e30208960d58298de8660b0e5"
521
+ checksum = "d64d8ca234d152948ceaede1f419b6a83983a5ecccaac05fb337a809c96d3aa6"
528
522
  dependencies = [
529
- "bitflags 1.3.2",
523
+ "bitflags",
524
+ "cfg-if",
530
525
  "libc",
531
526
  ]
532
527
 
@@ -568,9 +563,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
568
563
 
569
564
  [[package]]
570
565
  name = "libc"
571
- version = "0.2.186"
566
+ version = "0.2.189"
572
567
  source = "registry+https://github.com/rust-lang/crates.io-index"
573
- checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
568
+ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
574
569
 
575
570
  [[package]]
576
571
  name = "linux-raw-sys"
@@ -730,33 +725,13 @@ dependencies = [
730
725
  "unicode-ident",
731
726
  ]
732
727
 
733
- [[package]]
734
- name = "profiling"
735
- version = "1.0.18"
736
- source = "registry+https://github.com/rust-lang/crates.io-index"
737
- checksum = "3d595e54a326bc53c1c197b32d295e14b169e3cfeaa8dc82b529f947fba6bcf5"
738
- dependencies = [
739
- "profiling-procmacros",
740
- "tracy-client",
741
- ]
742
-
743
- [[package]]
744
- name = "profiling-procmacros"
745
- version = "1.0.18"
746
- source = "registry+https://github.com/rust-lang/crates.io-index"
747
- checksum = "4488a4a36b9a4ba6b9334a32a39971f77c1436ec82c38707bce707699cc3bbcb"
748
- dependencies = [
749
- "quote",
750
- "syn",
751
- ]
752
-
753
728
  [[package]]
754
729
  name = "proptest"
755
730
  version = "1.11.0"
756
731
  source = "registry+https://github.com/rust-lang/crates.io-index"
757
732
  checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
758
733
  dependencies = [
759
- "bitflags 2.13.0",
734
+ "bitflags",
760
735
  "num-traits",
761
736
  "rand",
762
737
  "rand_chacha",
@@ -922,7 +897,7 @@ dependencies = [
922
897
 
923
898
  [[package]]
924
899
  name = "rsloop"
925
- version = "0.1.45"
900
+ version = "0.1.46"
926
901
  dependencies = [
927
902
  "async-io",
928
903
  "async-std",
@@ -935,7 +910,6 @@ dependencies = [
935
910
  "memchr",
936
911
  "mio",
937
912
  "oneshot",
938
- "profiling",
939
913
  "proptest",
940
914
  "pyo3",
941
915
  "pyo3-async-runtimes",
@@ -957,7 +931,7 @@ version = "1.1.4"
957
931
  source = "registry+https://github.com/rust-lang/crates.io-index"
958
932
  checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
959
933
  dependencies = [
960
- "bitflags 2.13.0",
934
+ "bitflags",
961
935
  "errno",
962
936
  "libc",
963
937
  "linux-raw-sys",
@@ -1048,7 +1022,7 @@ version = "3.7.0"
1048
1022
  source = "registry+https://github.com/rust-lang/crates.io-index"
1049
1023
  checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
1050
1024
  dependencies = [
1051
- "bitflags 2.13.0",
1025
+ "bitflags",
1052
1026
  "core-foundation",
1053
1027
  "core-foundation-sys",
1054
1028
  "libc",
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "rsloop"
3
- version = "0.1.45"
3
+ version = "0.1.46"
4
4
  edition = "2024"
5
5
  description = "An event loop for asyncio written in Rust"
6
6
  license = "Apache-2.0"
@@ -15,7 +15,7 @@ crate-type = ["cdylib", "rlib"]
15
15
 
16
16
  [features]
17
17
  default = []
18
- profiler = ["dep:tracy-client", "profiling/profile-with-tracy"]
18
+ profiler = ["dep:tracy-client"]
19
19
 
20
20
  [dependencies]
21
21
  async-io = "2"
@@ -28,7 +28,6 @@ libc = "0.2"
28
28
  memchr = "2"
29
29
  mio = "1"
30
30
  oneshot = { version = "0.2", features = ["async", "std"] }
31
- profiling = "1"
32
31
  pyo3 = { version = "0.29.2" }
33
32
  pyo3-async-runtimes = { version = "0.29", features = ["async-std-runtime"] }
34
33
  rustls = "0.23"
@@ -40,7 +39,7 @@ socket2 = "0.6"
40
39
  tokio = { version = "1", default-features = false, features = ["io-util"] }
41
40
  tracy-client = { version = "0.18", default-features = false, features = ["enable", "only-localhost", "sampling"], optional = true }
42
41
  [target.'cfg(target_os = "linux")'.dependencies]
43
- io-uring = "0.6"
42
+ io-uring = "0.7"
44
43
 
45
44
  [target.'cfg(unix)'.dependencies]
46
45
  mio = { version = "1", features = ["os-poll", "os-ext"] }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rsloop
3
- Version: 0.1.45
3
+ Version: 0.1.46
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: Apache Software License
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "rsloop"
7
- version = "0.1.45"
7
+ version = "0.1.46"
8
8
  description = "An event loop for asyncio written in Rust"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -37,7 +37,7 @@ pub(super) fn create_connection<'py>(
37
37
  py: Python<'py>,
38
38
  params: CreateConnectionParams,
39
39
  ) -> PyResult<Bound<'py, PyAny>> {
40
- profiling::scope!("PyLoop::create_connection");
40
+ crate::profile_scope!("PyLoop::create_connection");
41
41
  let CreateConnectionParams {
42
42
  protocol_factory,
43
43
  host,
@@ -146,7 +146,7 @@ pub(super) fn create_connection_transport(
146
146
  sock: Py<PyAny>,
147
147
  tls: TlsParams,
148
148
  ) -> PyResult<Py<PyAny>> {
149
- profiling::scope!("PyLoop::_create_connection_transport");
149
+ crate::profile_scope!("PyLoop::_create_connection_transport");
150
150
  tls.validate()?;
151
151
 
152
152
  let env = LoopSpawnEnv::capture(py, &slf)?;
@@ -214,7 +214,7 @@ pub(super) fn connect_accepted_socket<'py>(
214
214
  sock: Py<PyAny>,
215
215
  tls: TlsParams,
216
216
  ) -> PyResult<Bound<'py, PyAny>> {
217
- profiling::scope!("PyLoop::connect_accepted_socket");
217
+ crate::profile_scope!("PyLoop::connect_accepted_socket");
218
218
  tls.validate()?;
219
219
 
220
220
  let locals = PyLoop::task_locals(py, &slf)?;
@@ -250,7 +250,7 @@ pub(super) fn start_tls<'py>(
250
250
  tls: TlsParams,
251
251
  server_side: bool,
252
252
  ) -> PyResult<Bound<'py, PyAny>> {
253
- profiling::scope!("PyLoop::start_tls");
253
+ crate::profile_scope!("PyLoop::start_tls");
254
254
  let locals = PyLoop::task_locals(py, &slf)?;
255
255
  let locals_for_barrier = locals.clone();
256
256
  let transport: Py<PyStreamTransport> = transport.extract(py)?;
@@ -137,13 +137,13 @@ impl PyLoop {
137
137
  self.core.set_debug(enabled);
138
138
  }
139
139
 
140
- #[profiling::function]
141
140
  fn run_forever(slf: Py<Self>, py: Python<'_>) -> PyResult<()> {
141
+ crate::profile_function!();
142
142
  lifecycle::run_forever(slf, py)
143
143
  }
144
144
 
145
- #[profiling::function]
146
145
  fn run_until_complete(slf: Py<Self>, py: Python<'_>, future: Py<PyAny>) -> PyResult<Py<PyAny>> {
146
+ crate::profile_function!();
147
147
  lifecycle::run_until_complete(slf, py, future)
148
148
  }
149
149
 
@@ -42,7 +42,7 @@ pub(super) fn create_server<'py>(
42
42
  py: Python<'py>,
43
43
  params: CreateServerParams,
44
44
  ) -> PyResult<Bound<'py, PyAny>> {
45
- profiling::scope!("PyLoop::create_server");
45
+ crate::profile_scope!("PyLoop::create_server");
46
46
  let CreateServerParams {
47
47
  protocol_factory,
48
48
  host,
@@ -129,7 +129,7 @@ impl ReadyCallback {
129
129
  /// A nested-context error falls back to direct invocation because that means
130
130
  /// the desired context is already active on this thread.
131
131
  pub fn invoke(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
132
- profiling::scope!("ReadyCallback::invoke");
132
+ crate::profile_scope!("ReadyCallback::invoke");
133
133
  if !self.context_needs_run {
134
134
  return self.invoke_direct(py);
135
135
  }
@@ -152,7 +152,7 @@ impl ReadyCallback {
152
152
  }
153
153
 
154
154
  fn invoke_direct(&self, py: Python<'_>) -> PyResult<Py<PyAny>> {
155
- profiling::scope!("ReadyCallback::invoke_direct");
155
+ crate::profile_scope!("ReadyCallback::invoke_direct");
156
156
  match &self.args {
157
157
  CallbackArgs::None => call_callback_noargs(py, &self.callback),
158
158
  CallbackArgs::One(arg) => call_callback_onearg(py, &self.callback, arg),
@@ -113,7 +113,7 @@ fn cancel_watch_task(task: WatchTask) {
113
113
  }
114
114
 
115
115
  pub fn run_runtime_thread(core: Arc<LoopCore>, command_rx: Receiver<LoopCommand>) {
116
- profiling::scope!("runtime.run_thread");
116
+ crate::profile_scope!("runtime.run_thread");
117
117
  #[cfg(feature = "profiler")]
118
118
  if tracy_client::Client::is_running() {
119
119
  tracy_client::set_thread_name!("rsloop-runtime");
@@ -148,7 +148,7 @@ impl Future for RuntimeDispatcher {
148
148
  type Output = ();
149
149
 
150
150
  fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
151
- profiling::scope!("runtime.dispatcher.poll");
151
+ crate::profile_scope!("runtime.dispatcher.poll");
152
152
  // Register before inspecting the command channel so a concurrent send
153
153
  // either wakes this poll or remains visible when the channel is
154
154
  // drained. The retained waker is intentional: consuming it while the
@@ -222,7 +222,7 @@ impl RuntimeDispatcher {
222
222
  }
223
223
 
224
224
  fn collect_expired_timers(&mut self) {
225
- profiling::scope!("runtime.collect_expired_timers");
225
+ crate::profile_scope!("runtime.collect_expired_timers");
226
226
  if self.active_run.is_none() {
227
227
  return;
228
228
  }
@@ -239,49 +239,49 @@ impl RuntimeDispatcher {
239
239
  }
240
240
 
241
241
  fn handle_command(&mut self, command: LoopCommand) -> bool {
242
- profiling::scope!("runtime.handle_command");
242
+ crate::profile_scope!("runtime.handle_command");
243
243
  match command {
244
244
  LoopCommand::ScheduleReady(callback) => {
245
- profiling::scope!("runtime.cmd.schedule_ready");
245
+ crate::profile_scope!("runtime.cmd.schedule_ready");
246
246
  self.ready_batch.push_back(ReadyItem::Callback(callback));
247
247
  }
248
248
  LoopCommand::ScheduleReadyHandle(handle) => {
249
- profiling::scope!("runtime.cmd.schedule_ready_handle");
249
+ crate::profile_scope!("runtime.cmd.schedule_ready_handle");
250
250
  self.ready_batch
251
251
  .push_back(ReadyItem::HandleCallback(handle));
252
252
  }
253
253
  LoopCommand::Future(LoopFutureCommand::SetResult { future, value }) => {
254
- profiling::scope!("runtime.cmd.future_set_result");
254
+ crate::profile_scope!("runtime.cmd.future_set_result");
255
255
  self.ready_batch
256
256
  .push_back(ReadyItem::FutureSetResult { future, value });
257
257
  }
258
258
  LoopCommand::Future(LoopFutureCommand::SetException { future, value }) => {
259
- profiling::scope!("runtime.cmd.future_set_exception");
259
+ crate::profile_scope!("runtime.cmd.future_set_exception");
260
260
  self.ready_batch
261
261
  .push_back(ReadyItem::FutureSetException { future, value });
262
262
  }
263
263
  LoopCommand::Transport(LoopTransportCommand::StreamRead(core)) => {
264
- profiling::scope!("runtime.cmd.stream_transport_read");
264
+ crate::profile_scope!("runtime.cmd.stream_transport_read");
265
265
  self.ready_batch
266
266
  .push_back(ReadyItem::StreamTransportRead(core));
267
267
  }
268
268
  LoopCommand::Transport(LoopTransportCommand::StreamWrite(core)) => {
269
- profiling::scope!("runtime.cmd.stream_transport_write");
269
+ crate::profile_scope!("runtime.cmd.stream_transport_write");
270
270
  self.ready_batch
271
271
  .push_back(ReadyItem::StreamTransportWrite(core));
272
272
  }
273
273
  LoopCommand::Transport(LoopTransportCommand::Process(core)) => {
274
- profiling::scope!("runtime.cmd.process_transport");
274
+ crate::profile_scope!("runtime.cmd.process_transport");
275
275
  self.ready_batch
276
276
  .push_back(ReadyItem::ProcessTransport(core));
277
277
  }
278
278
  LoopCommand::Transport(LoopTransportCommand::ServerAccepted { server, stream }) => {
279
- profiling::scope!("runtime.cmd.server_accepted");
279
+ crate::profile_scope!("runtime.cmd.server_accepted");
280
280
  self.ready_batch
281
281
  .push_back(ReadyItem::ServerAccepted { server, stream });
282
282
  }
283
283
  LoopCommand::ScheduleTimer { callback, when } => {
284
- profiling::scope!("runtime.cmd.schedule_timer");
284
+ crate::profile_scope!("runtime.cmd.schedule_timer");
285
285
  let seq = self.next_timer_id;
286
286
  self.next_timer_id += 1;
287
287
  self.timers.push(TimerEntry {
@@ -291,12 +291,12 @@ impl RuntimeDispatcher {
291
291
  });
292
292
  }
293
293
  LoopCommand::Run(LoopRunCommand::EnterRun { pending_ready }) => {
294
- profiling::scope!("runtime.cmd.enter_run");
294
+ crate::profile_scope!("runtime.cmd.enter_run");
295
295
  self.active_run = Some(ActiveRun { pending_ready });
296
296
  self.dispatch_ready_batch();
297
297
  }
298
298
  LoopCommand::Run(LoopRunCommand::FinishRun { done_tx }) => {
299
- profiling::scope!("runtime.cmd.finish_run");
299
+ crate::profile_scope!("runtime.cmd.finish_run");
300
300
  self.finish_run();
301
301
  let _ = done_tx.send(());
302
302
  }
@@ -495,7 +495,7 @@ impl RuntimeDispatcher {
495
495
  }
496
496
  #[cfg(unix)]
497
497
  LoopCommand::Io(LoopIoCommand::WatchConnect { fd, future }) => {
498
- profiling::scope!("runtime.cmd.watch_connect");
498
+ crate::profile_scope!("runtime.cmd.watch_connect");
499
499
  // Detached: the task self-reports via ConnectCompleted, and a
500
500
  // vibeio JoinHandle has no Drop, so dropping it detaches (does
501
501
  // not cancel) the running task.
@@ -510,7 +510,7 @@ impl RuntimeDispatcher {
510
510
  fd,
511
511
  wait_errno,
512
512
  } => {
513
- profiling::scope!("runtime.cmd.connect_completed");
513
+ crate::profile_scope!("runtime.cmd.connect_completed");
514
514
  self.ready_batch.push_back(ReadyItem::ConnectCompleted {
515
515
  future,
516
516
  fd,
@@ -518,11 +518,11 @@ impl RuntimeDispatcher {
518
518
  });
519
519
  }
520
520
  LoopCommand::RequestStop => {
521
- profiling::scope!("runtime.cmd.request_stop");
521
+ crate::profile_scope!("runtime.cmd.request_stop");
522
522
  self.ready_batch.push_back(ReadyItem::Stop);
523
523
  }
524
524
  LoopCommand::Close => {
525
- profiling::scope!("runtime.cmd.close");
525
+ crate::profile_scope!("runtime.cmd.close");
526
526
  self.finish_run();
527
527
  self.cleanup_watchers();
528
528
  self.shutting_down = true;
@@ -534,7 +534,7 @@ impl RuntimeDispatcher {
534
534
  }
535
535
 
536
536
  fn dispatch_ready_batch(&mut self) {
537
- profiling::scope!("runtime.dispatch_ready_batch");
537
+ crate::profile_scope!("runtime.dispatch_ready_batch");
538
538
  let Some(active_run) = self.active_run.as_ref() else {
539
539
  return;
540
540
  };
@@ -555,7 +555,7 @@ impl RuntimeDispatcher {
555
555
  }
556
556
 
557
557
  fn finish_run(&mut self) {
558
- profiling::scope!("runtime.finish_run");
558
+ crate::profile_scope!("runtime.finish_run");
559
559
  let Some(active_run) = self.active_run.take() else {
560
560
  return;
561
561
  };
@@ -572,7 +572,7 @@ impl RuntimeDispatcher {
572
572
  }
573
573
 
574
574
  fn cleanup_watchers(&mut self) {
575
- profiling::scope!("runtime.cleanup_watchers");
575
+ crate::profile_scope!("runtime.cleanup_watchers");
576
576
  #[cfg(unix)]
577
577
  for (_, watcher) in self.signal_tasks.drain() {
578
578
  watcher.handle.close();
@@ -315,7 +315,7 @@ impl LoopCore {
315
315
  /// avoid a channel round trip. `LoopCoreError::ChannelClosed` means the
316
316
  /// dispatcher has already terminated.
317
317
  pub fn send_command(&self, command: LoopCommand) -> Result<(), LoopCoreError> {
318
- profiling::scope!("LoopCore::send_command");
318
+ crate::profile_scope!("LoopCore::send_command");
319
319
  let command = match self.try_handle_local_command(command) {
320
320
  Ok(()) => return Ok(()),
321
321
  Err(command) => command,
@@ -395,7 +395,7 @@ impl LoopCore {
395
395
  args: Py<PyTuple>,
396
396
  context: Option<Py<PyAny>>,
397
397
  ) -> PyResult<Py<super::callbacks::PyHandle>> {
398
- profiling::scope!("LoopCore::schedule_callback");
398
+ crate::profile_scope!("LoopCore::schedule_callback");
399
399
  let (captured, context_needs_run) = capture_context(py, context)?;
400
400
  let ready = ReadyCallback::new(
401
401
  py,
@@ -427,7 +427,7 @@ impl LoopCore {
427
427
  args: Py<PyTuple>,
428
428
  context: Option<Py<PyAny>>,
429
429
  ) -> PyResult<(Arc<ReadyCallback>, f64)> {
430
- profiling::scope!("LoopCore::schedule_timer");
430
+ crate::profile_scope!("LoopCore::schedule_timer");
431
431
  let (captured, context_needs_run) = capture_context(py, context)?;
432
432
  let ready = Arc::new(ReadyCallback::new(
433
433
  py,
@@ -456,8 +456,8 @@ impl LoopCore {
456
456
  /// to Python again before invoking user code.
457
457
  ///
458
458
  /// Returns an error if the loop is closed or already running.
459
- #[profiling::function]
460
459
  pub fn run_forever(self: &Arc<Self>, py: Python<'_>, loop_obj: Py<PyAny>) -> PyResult<()> {
460
+ crate::profile_function!();
461
461
  {
462
462
  let mut state = self.state.lock().expect("poisoned loop state");
463
463
  if state.closed {
@@ -579,11 +579,11 @@ impl LoopCore {
579
579
  .expect("ready batch was checked as non-empty");
580
580
  match item {
581
581
  ReadyItem::Stop => {
582
- profiling::scope!("ready.stop");
582
+ crate::profile_scope!("ready.stop");
583
583
  self.state.lock().expect("poisoned loop state").stopping = true;
584
584
  }
585
585
  ReadyItem::Callback(callback) => {
586
- profiling::scope!("ready.callback");
586
+ crate::profile_scope!("ready.callback");
587
587
  let should_rearm = matches!(
588
588
  callback.kind(),
589
589
  CallbackKind::Reader(_) | CallbackKind::Writer(_)
@@ -599,7 +599,7 @@ impl LoopCore {
599
599
  }
600
600
  }
601
601
  ReadyItem::HandleCallback(handle) => {
602
- profiling::scope!("ready.handle_callback");
602
+ crate::profile_scope!("ready.handle_callback");
603
603
  if let Some(err) =
604
604
  self.execute_ready(py, Some(&loop_obj), handle.get().ready())?
605
605
  {
@@ -608,7 +608,7 @@ impl LoopCore {
608
608
  }
609
609
  }
610
610
  ReadyItem::FutureSetResult { future, value } => {
611
- profiling::scope!("ready.future_set_result");
611
+ crate::profile_scope!("ready.future_set_result");
612
612
  let future = future.bind(py);
613
613
  if !crate::python_names::call_method0(
614
614
  py,
@@ -627,7 +627,7 @@ impl LoopCore {
627
627
  }
628
628
  }
629
629
  ReadyItem::FutureSetException { future, value } => {
630
- profiling::scope!("ready.future_set_exception");
630
+ crate::profile_scope!("ready.future_set_exception");
631
631
  let future = future.bind(py);
632
632
  if !crate::python_names::call_method0(
633
633
  py,
@@ -646,19 +646,19 @@ impl LoopCore {
646
646
  }
647
647
  }
648
648
  ReadyItem::StreamTransportRead(core) => {
649
- profiling::scope!("ready.stream_transport_read");
649
+ crate::profile_scope!("ready.stream_transport_read");
650
650
  core.drain_pending_read_events_with_py(py)?;
651
651
  }
652
652
  ReadyItem::StreamTransportWrite(core) => {
653
- profiling::scope!("ready.stream_transport_write");
653
+ crate::profile_scope!("ready.stream_transport_write");
654
654
  core.flush_pending_direct_write();
655
655
  }
656
656
  ReadyItem::ProcessTransport(core) => {
657
- profiling::scope!("ready.process_transport");
657
+ crate::profile_scope!("ready.process_transport");
658
658
  core.drain_pending_events_with_py(py)?;
659
659
  }
660
660
  ReadyItem::ServerAccepted { server, stream } => {
661
- profiling::scope!("ready.server_accepted");
661
+ crate::profile_scope!("ready.server_accepted");
662
662
  if let Err(err) = crate::transport::stream::spawn_accepted_transport_with_py(
663
663
  py, &server, stream,
664
664
  ) {
@@ -671,7 +671,7 @@ impl LoopCore {
671
671
  fd,
672
672
  wait_errno,
673
673
  } => {
674
- profiling::scope!("ready.connect_completed");
674
+ crate::profile_scope!("ready.connect_completed");
675
675
  self.resolve_connect_completed(py, future, fd, wait_errno)?;
676
676
  }
677
677
  }
@@ -825,7 +825,7 @@ impl LoopCore {
825
825
  /// Already-ready callbacks are still processed according to asyncio's
826
826
  /// stop semantics before `run_forever` returns.
827
827
  pub fn schedule_stop(&self) -> Result<(), LoopCoreError> {
828
- profiling::scope!("LoopCore::schedule_stop");
828
+ crate::profile_scope!("LoopCore::schedule_stop");
829
829
  self.send_command(LoopCommand::RequestStop)
830
830
  }
831
831
 
@@ -835,7 +835,7 @@ impl LoopCore {
835
835
  /// `LoopCoreError::Running`. Tracked I/O tasks are cancelled before the
836
836
  /// on-thread runtime is dropped.
837
837
  pub fn close(&self) -> Result<(), LoopCoreError> {
838
- profiling::scope!("LoopCore::close");
838
+ crate::profile_scope!("LoopCore::close");
839
839
  {
840
840
  let mut state = self.state.lock().expect("poisoned loop state");
841
841
  if state.running {
@@ -946,7 +946,7 @@ impl LoopCore {
946
946
  loop_obj: Option<&Py<PyAny>>,
947
947
  ready: &ReadyCallback,
948
948
  ) -> PyResult<Option<PyErr>> {
949
- profiling::scope!("LoopCore::execute_ready");
949
+ crate::profile_scope!("LoopCore::execute_ready");
950
950
  if ready.cancelled() {
951
951
  return Ok(None);
952
952
  }
@@ -1440,4 +1440,42 @@ mod wake_tests {
1440
1440
  assert!(!wake.ready_pending.load(Ordering::Acquire));
1441
1441
  assert!(started.elapsed() >= Duration::from_millis(1));
1442
1442
  }
1443
+
1444
+ #[test]
1445
+ fn command_channel_accepts_concurrent_producers_and_disconnects_cleanly() {
1446
+ const PRODUCERS: usize = 8;
1447
+ const COMMANDS_PER_PRODUCER: usize = 128;
1448
+
1449
+ let core = LoopCore::new();
1450
+ let producers = (0..PRODUCERS)
1451
+ .map(|_| {
1452
+ let core = Arc::clone(&core);
1453
+ std::thread::spawn(move || {
1454
+ for _ in 0..COMMANDS_PER_PRODUCER {
1455
+ core.send_command(LoopCommand::RequestStop)
1456
+ .expect("dispatcher should accept concurrent commands");
1457
+ }
1458
+ })
1459
+ })
1460
+ .collect::<Vec<_>>();
1461
+
1462
+ for producer in producers {
1463
+ producer.join().expect("command producer");
1464
+ }
1465
+
1466
+ core.send_command(LoopCommand::Close)
1467
+ .expect("dispatcher close command");
1468
+ core.runtime_thread
1469
+ .lock()
1470
+ .expect("runtime thread mutex")
1471
+ .take()
1472
+ .expect("runtime thread")
1473
+ .join()
1474
+ .expect("runtime thread join");
1475
+
1476
+ assert!(matches!(
1477
+ core.send_command(LoopCommand::RequestStop),
1478
+ Err(LoopCoreError::ChannelClosed)
1479
+ ));
1480
+ }
1443
1481
  }
@@ -34,6 +34,7 @@ pub(crate) mod vibeio;
34
34
  pub(crate) use platform::fd as fd_ops;
35
35
  #[cfg(windows)]
36
36
  pub(crate) use platform::windows_vibeio;
37
+ pub(crate) use profiler::{profile_function, profile_scope};
37
38
 
38
39
  // Compatibility re-exports for the crate's existing Rust API. Internal module
39
40
  // registration imports from the owning modules directly, so these can be
@@ -1,5 +1,27 @@
1
1
  //! Optional Tracy profiler lifecycle exposed to Python.
2
2
 
3
+ /// Opens a named profiling scope when Tracy support is compiled in.
4
+ ///
5
+ /// Default builds intentionally expand this macro to nothing, matching the
6
+ /// previous `profiling` facade without retaining it as a dependency.
7
+ macro_rules! profile_scope {
8
+ ($name:literal) => {
9
+ #[cfg(feature = "profiler")]
10
+ let _rsloop_tracy_span = tracy_client::span!($name, 0);
11
+ };
12
+ }
13
+
14
+ /// Opens a scope named after the enclosing function in profiler builds.
15
+ macro_rules! profile_function {
16
+ () => {
17
+ #[cfg(feature = "profiler")]
18
+ let _rsloop_tracy_span = tracy_client::span!();
19
+ };
20
+ }
21
+
22
+ pub(crate) use profile_function;
23
+ pub(crate) use profile_scope;
24
+
3
25
  use pyo3::prelude::*;
4
26
 
5
27
  #[cfg(feature = "profiler")]