uringmachine 0.23.1 → 0.25.0

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 (291) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -1
  3. data/.gitignore +1 -0
  4. data/.gitmodules +0 -3
  5. data/CHANGELOG.md +17 -0
  6. data/Gemfile +12 -1
  7. data/README.md +266 -112
  8. data/Rakefile +8 -0
  9. data/TODO.md +40 -17
  10. data/benchmark/bm_io_pipe.rb +43 -1
  11. data/benchmark/bm_io_socketpair.rb +32 -2
  12. data/benchmark/bm_mutex_io.rb +47 -5
  13. data/benchmark/chart_bm_io_pipe_x.png +0 -0
  14. data/benchmark/common.rb +163 -17
  15. data/benchmark/http_parse.rb +9 -9
  16. data/benchmark/http_server_accept_queue.rb +104 -0
  17. data/benchmark/http_server_multi_accept.rb +93 -0
  18. data/benchmark/http_server_multi_ractor.rb +99 -0
  19. data/benchmark/http_server_single_thread.rb +80 -0
  20. data/benchmark/ips_io_pipe.rb +146 -0
  21. data/benchmark/openssl.rb +77 -0
  22. data/benchmark/openssl_socketpair.rb +112 -0
  23. data/benchmark/sqlite.rb +1 -1
  24. data/docs/design/buffer_pool.md +183 -0
  25. data/docs/um_api.md +91 -0
  26. data/examples/fiber_scheduler_file_io.rb +34 -0
  27. data/examples/fiber_scheduler_file_io_async.rb +33 -0
  28. data/ext/um/extconf.rb +15 -0
  29. data/ext/um/um.c +83 -50
  30. data/ext/um/um.h +18 -3
  31. data/ext/um/um_async_op_class.c +31 -0
  32. data/ext/um/um_class.c +759 -30
  33. data/ext/um/um_const.c +31 -0
  34. data/ext/um/um_mutex_class.c +12 -0
  35. data/ext/um/um_queue_class.c +16 -0
  36. data/ext/um/um_sidecar.c +106 -0
  37. data/ext/um/um_ssl.c +109 -0
  38. data/ext/um/um_stream.c +40 -8
  39. data/ext/um/um_stream_class.c +14 -0
  40. data/ext/um/um_utils.c +3 -4
  41. data/grant-2025/interim-report.md +130 -0
  42. data/grant-2025/journal.md +166 -2
  43. data/grant-2025/tasks.md +32 -20
  44. data/lib/uringmachine/dns_resolver.rb +38 -0
  45. data/lib/uringmachine/fiber_scheduler.rb +42 -32
  46. data/lib/uringmachine/version.rb +1 -1
  47. data/lib/uringmachine.rb +105 -7
  48. data/test/helper.rb +23 -3
  49. data/test/test_fiber.rb +16 -0
  50. data/test/test_fiber_scheduler.rb +221 -72
  51. data/test/test_ssl.rb +85 -0
  52. data/test/test_stream.rb +27 -0
  53. data/test/test_um.rb +250 -26
  54. data/uringmachine.gemspec +1 -7
  55. data/vendor/liburing/examples/send-zerocopy.c +43 -31
  56. data/vendor/liburing/examples/zcrx.c +260 -69
  57. data/vendor/liburing/liburing.spec +1 -1
  58. data/vendor/liburing/src/include/liburing/io_uring.h +12 -0
  59. data/vendor/liburing/src/include/liburing.h +3 -2
  60. data/vendor/liburing/src/liburing-ffi.map +4 -0
  61. data/vendor/liburing/src/liburing.map +4 -0
  62. data/vendor/liburing/src/queue.c +12 -0
  63. data/vendor/liburing/src/register.c +1 -0
  64. data/vendor/liburing/src/setup.c +15 -7
  65. data/vendor/liburing/test/Makefile +8 -4
  66. data/vendor/liburing/test/conn-unreach.c +1 -1
  67. data/vendor/liburing/test/epwait.c +32 -6
  68. data/vendor/liburing/test/io-wq-exit.c +131 -0
  69. data/vendor/liburing/test/iowait.c +1 -1
  70. data/vendor/liburing/test/min-timeout.c +3 -1
  71. data/vendor/liburing/test/open-close.c +39 -0
  72. data/vendor/liburing/test/poll-update-trigger.c +85 -0
  73. data/vendor/liburing/test/recvsend_bundle.c +14 -11
  74. data/vendor/liburing/test/sendzc-bug.c +146 -0
  75. data/vendor/liburing/test/sqe-mixed-nop.c +151 -7
  76. data/vendor/liburing/test/test.h +2 -0
  77. data/vendor/liburing/test/timestamp-bug.c +135 -0
  78. data/vendor/liburing/test/timestamp.c +5 -0
  79. data/vendor/liburing/test/vec-regbuf.c +136 -1
  80. metadata +50 -284
  81. data/vendor/libressl/.github/scripts/changelog.sh +0 -74
  82. data/vendor/libressl/.github/workflows/android.yml +0 -35
  83. data/vendor/libressl/.github/workflows/cifuzz.yml +0 -33
  84. data/vendor/libressl/.github/workflows/cmake-config.yml +0 -98
  85. data/vendor/libressl/.github/workflows/coverity.yml +0 -69
  86. data/vendor/libressl/.github/workflows/emscripten.yml +0 -71
  87. data/vendor/libressl/.github/workflows/fedora-rawhide.yml +0 -39
  88. data/vendor/libressl/.github/workflows/freebsd.yml +0 -71
  89. data/vendor/libressl/.github/workflows/linux.yml +0 -71
  90. data/vendor/libressl/.github/workflows/macos.yml +0 -37
  91. data/vendor/libressl/.github/workflows/release.yml +0 -81
  92. data/vendor/libressl/.github/workflows/rust-openssl.yml +0 -47
  93. data/vendor/libressl/.github/workflows/solaris.yml +0 -37
  94. data/vendor/libressl/.github/workflows/windows.yml +0 -70
  95. data/vendor/libressl/.gitignore +0 -333
  96. data/vendor/libressl/CMakeLists.txt +0 -581
  97. data/vendor/libressl/COPYING +0 -133
  98. data/vendor/libressl/ChangeLog +0 -3280
  99. data/vendor/libressl/FindLibreSSL.cmake +0 -232
  100. data/vendor/libressl/LibreSSLConfig.cmake.in +0 -36
  101. data/vendor/libressl/Makefile.am +0 -60
  102. data/vendor/libressl/Makefile.am.common +0 -20
  103. data/vendor/libressl/OPENBSD_BRANCH +0 -1
  104. data/vendor/libressl/README.md +0 -238
  105. data/vendor/libressl/README.mingw.md +0 -43
  106. data/vendor/libressl/apps/CMakeLists.txt +0 -18
  107. data/vendor/libressl/apps/Makefile.am +0 -5
  108. data/vendor/libressl/apps/nc/CMakeLists.txt +0 -67
  109. data/vendor/libressl/apps/nc/Makefile.am +0 -64
  110. data/vendor/libressl/apps/nc/compat/accept4.c +0 -17
  111. data/vendor/libressl/apps/nc/compat/readpassphrase.c +0 -205
  112. data/vendor/libressl/apps/nc/compat/socket.c +0 -29
  113. data/vendor/libressl/apps/nc/compat/sys/socket.h +0 -30
  114. data/vendor/libressl/apps/ocspcheck/CMakeLists.txt +0 -44
  115. data/vendor/libressl/apps/ocspcheck/Makefile.am +0 -45
  116. data/vendor/libressl/apps/ocspcheck/compat/.gitignore +0 -0
  117. data/vendor/libressl/apps/openssl/CMakeLists.txt +0 -97
  118. data/vendor/libressl/apps/openssl/Makefile.am +0 -108
  119. data/vendor/libressl/apps/openssl/apps_win.c +0 -138
  120. data/vendor/libressl/apps/openssl/certhash_win.c +0 -13
  121. data/vendor/libressl/apps/openssl/compat/clock_gettime_osx.c +0 -26
  122. data/vendor/libressl/apps/openssl/compat/poll_win.c +0 -329
  123. data/vendor/libressl/appveyor.yml +0 -53
  124. data/vendor/libressl/autogen.sh +0 -15
  125. data/vendor/libressl/check-release.sh +0 -86
  126. data/vendor/libressl/cmake_export_symbol.cmake +0 -71
  127. data/vendor/libressl/cmake_uninstall.cmake.in +0 -36
  128. data/vendor/libressl/config +0 -17
  129. data/vendor/libressl/configure.ac +0 -165
  130. data/vendor/libressl/crypto/CMakeLists.txt +0 -863
  131. data/vendor/libressl/crypto/Makefile.am +0 -962
  132. data/vendor/libressl/crypto/Makefile.am.arc4random +0 -46
  133. data/vendor/libressl/crypto/Makefile.am.elf-mips +0 -14
  134. data/vendor/libressl/crypto/Makefile.am.elf-mips64 +0 -14
  135. data/vendor/libressl/crypto/Makefile.am.elf-x86_64 +0 -35
  136. data/vendor/libressl/crypto/Makefile.am.macosx-x86_64 +0 -35
  137. data/vendor/libressl/crypto/Makefile.am.masm-x86_64 +0 -22
  138. data/vendor/libressl/crypto/Makefile.am.mingw64-x86_64 +0 -23
  139. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_darwin.c +0 -60
  140. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_linux.c +0 -62
  141. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_none.c +0 -26
  142. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_windows.c +0 -36
  143. data/vendor/libressl/crypto/arch/loongarch64/crypto_arch.h +0 -21
  144. data/vendor/libressl/crypto/arch/mips/crypto_arch.h +0 -21
  145. data/vendor/libressl/crypto/bn/arch/loongarch64/bn_arch.h +0 -23
  146. data/vendor/libressl/crypto/bn/arch/mips/bn_arch.h +0 -24
  147. data/vendor/libressl/crypto/compat/.gitignore +0 -31
  148. data/vendor/libressl/crypto/compat/arc4random.h +0 -41
  149. data/vendor/libressl/crypto/compat/b_win.c +0 -55
  150. data/vendor/libressl/crypto/compat/bsd-asprintf.c +0 -96
  151. data/vendor/libressl/crypto/compat/crypto_lock_win.c +0 -56
  152. data/vendor/libressl/crypto/compat/explicit_bzero_win.c +0 -13
  153. data/vendor/libressl/crypto/compat/freezero.c +0 -32
  154. data/vendor/libressl/crypto/compat/getdelim.c +0 -78
  155. data/vendor/libressl/crypto/compat/getline.c +0 -40
  156. data/vendor/libressl/crypto/compat/getopt_long.c +0 -528
  157. data/vendor/libressl/crypto/compat/getpagesize.c +0 -18
  158. data/vendor/libressl/crypto/compat/getprogname_linux.c +0 -23
  159. data/vendor/libressl/crypto/compat/getprogname_unimpl.c +0 -7
  160. data/vendor/libressl/crypto/compat/getprogname_windows.c +0 -13
  161. data/vendor/libressl/crypto/compat/posix_win.c +0 -296
  162. data/vendor/libressl/crypto/compat/syslog_r.c +0 -19
  163. data/vendor/libressl/crypto/compat/ui_openssl_win.c +0 -334
  164. data/vendor/libressl/dist.sh +0 -22
  165. data/vendor/libressl/gen-coverage-report.sh +0 -58
  166. data/vendor/libressl/gen-openbsd-tags.sh +0 -20
  167. data/vendor/libressl/include/CMakeLists.txt +0 -61
  168. data/vendor/libressl/include/Makefile.am +0 -79
  169. data/vendor/libressl/include/arch/loongarch64/opensslconf.h +0 -150
  170. data/vendor/libressl/include/arch/mips/opensslconf.h +0 -150
  171. data/vendor/libressl/include/compat/arpa/inet.h +0 -15
  172. data/vendor/libressl/include/compat/arpa/nameser.h +0 -25
  173. data/vendor/libressl/include/compat/cet.h +0 -19
  174. data/vendor/libressl/include/compat/dirent.h +0 -17
  175. data/vendor/libressl/include/compat/dirent_msvc.h +0 -611
  176. data/vendor/libressl/include/compat/endian.h +0 -161
  177. data/vendor/libressl/include/compat/err.h +0 -95
  178. data/vendor/libressl/include/compat/fcntl.h +0 -32
  179. data/vendor/libressl/include/compat/getopt.h +0 -50
  180. data/vendor/libressl/include/compat/limits.h +0 -25
  181. data/vendor/libressl/include/compat/netdb.h +0 -10
  182. data/vendor/libressl/include/compat/netinet/in.h +0 -19
  183. data/vendor/libressl/include/compat/netinet/ip.h +0 -49
  184. data/vendor/libressl/include/compat/netinet/tcp.h +0 -10
  185. data/vendor/libressl/include/compat/poll.h +0 -63
  186. data/vendor/libressl/include/compat/pthread.h +0 -122
  187. data/vendor/libressl/include/compat/readpassphrase.h +0 -44
  188. data/vendor/libressl/include/compat/resolv.h +0 -24
  189. data/vendor/libressl/include/compat/stdint.h +0 -31
  190. data/vendor/libressl/include/compat/stdio.h +0 -65
  191. data/vendor/libressl/include/compat/stdlib.h +0 -57
  192. data/vendor/libressl/include/compat/string.h +0 -98
  193. data/vendor/libressl/include/compat/sys/_null.h +0 -18
  194. data/vendor/libressl/include/compat/sys/ioctl.h +0 -11
  195. data/vendor/libressl/include/compat/sys/mman.h +0 -19
  196. data/vendor/libressl/include/compat/sys/param.h +0 -15
  197. data/vendor/libressl/include/compat/sys/queue.h +0 -536
  198. data/vendor/libressl/include/compat/sys/select.h +0 -10
  199. data/vendor/libressl/include/compat/sys/socket.h +0 -18
  200. data/vendor/libressl/include/compat/sys/stat.h +0 -129
  201. data/vendor/libressl/include/compat/sys/time.h +0 -37
  202. data/vendor/libressl/include/compat/sys/tree.h +0 -1006
  203. data/vendor/libressl/include/compat/sys/types.h +0 -69
  204. data/vendor/libressl/include/compat/sys/uio.h +0 -17
  205. data/vendor/libressl/include/compat/syslog.h +0 -38
  206. data/vendor/libressl/include/compat/time.h +0 -59
  207. data/vendor/libressl/include/compat/unistd.h +0 -83
  208. data/vendor/libressl/include/compat/win32netcompat.h +0 -57
  209. data/vendor/libressl/include/openssl/Makefile.am.tpl +0 -45
  210. data/vendor/libressl/libcrypto.pc.in +0 -28
  211. data/vendor/libressl/libressl.pub +0 -2
  212. data/vendor/libressl/libssl.pc.in +0 -28
  213. data/vendor/libressl/libtls.pc.in +0 -28
  214. data/vendor/libressl/m4/ax_add_fortify_source.m4 +0 -80
  215. data/vendor/libressl/m4/ax_check_compile_flag.m4 +0 -53
  216. data/vendor/libressl/m4/check-hardening-options.m4 +0 -110
  217. data/vendor/libressl/m4/check-libc.m4 +0 -189
  218. data/vendor/libressl/m4/check-os-options.m4 +0 -181
  219. data/vendor/libressl/m4/disable-compiler-warnings.m4 +0 -44
  220. data/vendor/libressl/man/CMakeLists.txt +0 -26
  221. data/vendor/libressl/man/links +0 -2780
  222. data/vendor/libressl/man/update_links.sh +0 -25
  223. data/vendor/libressl/openssl.pc.in +0 -11
  224. data/vendor/libressl/patches/bn_shift.patch +0 -34
  225. data/vendor/libressl/patches/crypto_arch.h.patch +0 -34
  226. data/vendor/libressl/patches/crypto_namespace.h.patch +0 -22
  227. data/vendor/libressl/patches/netcat.c.patch +0 -178
  228. data/vendor/libressl/patches/openssl.c.patch +0 -12
  229. data/vendor/libressl/patches/opensslfeatures.h.patch +0 -49
  230. data/vendor/libressl/patches/patch-amd64-crypto-cpu-caps.c.patch +0 -20
  231. data/vendor/libressl/patches/patch-i386-crypto-cpu-caps.c.patch +0 -20
  232. data/vendor/libressl/patches/speed.c.patch +0 -114
  233. data/vendor/libressl/patches/ssl_namespace.h.patch +0 -21
  234. data/vendor/libressl/patches/tls.h.patch +0 -16
  235. data/vendor/libressl/patches/tls_config.c.patch +0 -15
  236. data/vendor/libressl/patches/win32_amd64_bn_arch.h.patch +0 -28
  237. data/vendor/libressl/patches/windows_headers.patch +0 -80
  238. data/vendor/libressl/scripts/config.guess +0 -1774
  239. data/vendor/libressl/scripts/config.sub +0 -1907
  240. data/vendor/libressl/scripts/i686-w64-mingw32.cmake +0 -9
  241. data/vendor/libressl/scripts/test +0 -210
  242. data/vendor/libressl/scripts/wrap-compiler-for-flag-check +0 -31
  243. data/vendor/libressl/scripts/x86_64-w64-mingw32.cmake +0 -9
  244. data/vendor/libressl/ssl/CMakeLists.txt +0 -183
  245. data/vendor/libressl/ssl/Makefile.am +0 -187
  246. data/vendor/libressl/tests/CMakeLists.txt +0 -970
  247. data/vendor/libressl/tests/Makefile.am +0 -944
  248. data/vendor/libressl/tests/aeadtest.sh +0 -30
  249. data/vendor/libressl/tests/arc4randomforktest.sh +0 -21
  250. data/vendor/libressl/tests/asn1time_small.test +0 -10
  251. data/vendor/libressl/tests/cmake/CMakeLists.txt +0 -52
  252. data/vendor/libressl/tests/cmake/crypto.c +0 -7
  253. data/vendor/libressl/tests/cmake/ssl.c +0 -6
  254. data/vendor/libressl/tests/cmake/tls.c +0 -6
  255. data/vendor/libressl/tests/compat/pipe2.c +0 -186
  256. data/vendor/libressl/tests/dtlstest.sh +0 -28
  257. data/vendor/libressl/tests/evptest.sh +0 -22
  258. data/vendor/libressl/tests/keypairtest.sh +0 -27
  259. data/vendor/libressl/tests/mlkem_tests.sh +0 -39
  260. data/vendor/libressl/tests/ocsptest.bat +0 -25
  261. data/vendor/libressl/tests/ocsptest.sh +0 -23
  262. data/vendor/libressl/tests/openssl.cnf +0 -29
  263. data/vendor/libressl/tests/optionstest.c +0 -381
  264. data/vendor/libressl/tests/pidwraptest.c +0 -85
  265. data/vendor/libressl/tests/pidwraptest.sh +0 -26
  266. data/vendor/libressl/tests/quictest.bat +0 -27
  267. data/vendor/libressl/tests/quictest.sh +0 -30
  268. data/vendor/libressl/tests/renegotiation_test.bat +0 -27
  269. data/vendor/libressl/tests/renegotiation_test.sh +0 -30
  270. data/vendor/libressl/tests/rfc5280time_small.test +0 -10
  271. data/vendor/libressl/tests/servertest.bat +0 -27
  272. data/vendor/libressl/tests/servertest.sh +0 -30
  273. data/vendor/libressl/tests/shutdowntest.bat +0 -27
  274. data/vendor/libressl/tests/shutdowntest.sh +0 -30
  275. data/vendor/libressl/tests/ssltest.bat +0 -32
  276. data/vendor/libressl/tests/ssltest.sh +0 -48
  277. data/vendor/libressl/tests/testdsa.bat +0 -47
  278. data/vendor/libressl/tests/testdsa.sh +0 -57
  279. data/vendor/libressl/tests/testenc.bat +0 -85
  280. data/vendor/libressl/tests/testenc.sh +0 -93
  281. data/vendor/libressl/tests/testrsa.bat +0 -47
  282. data/vendor/libressl/tests/testrsa.sh +0 -57
  283. data/vendor/libressl/tests/testssl.bat +0 -171
  284. data/vendor/libressl/tests/tlstest.bat +0 -27
  285. data/vendor/libressl/tests/tlstest.sh +0 -28
  286. data/vendor/libressl/tls/CMakeLists.txt +0 -125
  287. data/vendor/libressl/tls/Makefile.am +0 -76
  288. data/vendor/libressl/tls/compat/ftruncate.c +0 -17
  289. data/vendor/libressl/tls/compat/pread.c +0 -29
  290. data/vendor/libressl/tls/compat/pwrite.c +0 -29
  291. data/vendor/libressl/update.sh +0 -460
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ require 'uringmachine'
6
+ require 'uringmachine/fiber_scheduler'
7
+ require 'securerandom'
8
+
9
+ $machine = UringMachine.new
10
+ scheduler = UM::FiberScheduler.new($machine)
11
+ Fiber.set_scheduler scheduler
12
+
13
+ fn = "/tmp/file_io_#{SecureRandom.hex}"
14
+
15
+ r, w = IO.pipe
16
+
17
+ f1 = Fiber.schedule do
18
+ File.open(fn, 'w') {
19
+ it.sync = true
20
+ UM.debug "writing..."
21
+ it << 'foobar'
22
+ # w.close
23
+ }
24
+
25
+ File.open(fn, 'r') {
26
+ UM.debug "reading..."
27
+ buf = it.read
28
+ UM.debug "read: #{buf}"
29
+ }
30
+ rescue => e
31
+ p e
32
+ p e.backtrace
33
+ end
34
+ scheduler.join
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'io-event'
8
+ gem 'async'
9
+ end
10
+
11
+
12
+ require 'async'
13
+ require 'securerandom'
14
+
15
+ selector ||= IO::Event::Selector::URing.new(Fiber.current)
16
+ scheduler = Async::Scheduler.new(selector:)
17
+ Fiber.set_scheduler scheduler
18
+
19
+ fn = "/tmp/file_io_#{SecureRandom.hex}"
20
+
21
+ scheduler.run do
22
+ Fiber.schedule do
23
+ File.open(fn, 'w') {
24
+ it << 'foo'
25
+ p pre_flush: IO.read(fn)
26
+ it.flush
27
+ it << 'bar'
28
+ p post_flush: IO.read(fn)
29
+
30
+ }
31
+ p post_close: IO.read(fn)
32
+ end
33
+ end
data/ext/um/extconf.rb CHANGED
@@ -54,6 +54,21 @@ if !find_library('uring', nil, File.join(liburing_path, 'src'))
54
54
  raise "Couldn't find liburing.a"
55
55
  end
56
56
 
57
+ if !have_header("openssl/ssl.h")
58
+ raise "Couldn't find OpenSSL headers"
59
+ end
60
+
61
+ if !have_library("ssl", "SSL_new")
62
+ raise "Couldn't find OpenSSL library"
63
+ end
64
+
65
+ version_ok = checking_for("OpenSSL version >= 1.1.1") {
66
+ try_static_assert("OPENSSL_VERSION_NUMBER >= 0x10101000L", "openssl/opensslv.h")
67
+ }
68
+ unless version_ok
69
+ raise "OpenSSL >= 1.1.1 or LibreSSL >= 3.9.0 is required"
70
+ end
71
+
57
72
  have_func("&rb_process_status_new")
58
73
 
59
74
  $defs << "-DUM_KERNEL_VERSION=#{config[:kernel_version]}"
data/ext/um/um.c CHANGED
@@ -18,7 +18,7 @@ inline void prepare_io_uring_params(struct io_uring_params *params, uint sqpoll_
18
18
  params->flags |= IORING_SETUP_COOP_TASKRUN;
19
19
  }
20
20
 
21
- void um_setup(VALUE self, struct um *machine, uint size, uint sqpoll_timeout_msec) {
21
+ void um_setup(VALUE self, struct um *machine, uint size, uint sqpoll_timeout_msec, int sidecar_mode) {
22
22
  memset(machine, 0, sizeof(struct um));
23
23
 
24
24
  RB_OBJ_WRITE(self, &machine->self, self);
@@ -27,16 +27,26 @@ void um_setup(VALUE self, struct um *machine, uint size, uint sqpoll_timeout_mse
27
27
  machine->size = (size > 0) ? size : DEFAULT_SIZE;
28
28
  machine->sqpoll_mode = !!sqpoll_timeout_msec;
29
29
 
30
+ // sidecar handling
31
+ machine->sidecar_mode = sidecar_mode;
32
+ machine->sidecar_signal = aligned_alloc(4, sizeof(uint32_t));
33
+ memset(machine->sidecar_signal, 0, sizeof(uint32_t));
34
+
30
35
  struct io_uring_params params;
31
36
  prepare_io_uring_params(&params, sqpoll_timeout_msec);
32
37
  int ret = io_uring_queue_init_params(machine->size, &machine->ring, &params);
33
38
  if (ret) rb_syserr_fail(-ret, strerror(-ret));
34
39
  machine->ring_initialized = 1;
40
+
41
+ if (machine->sidecar_mode) um_sidecar_setup(machine);
35
42
  }
36
43
 
37
44
  inline void um_teardown(struct um *machine) {
38
45
  if (!machine->ring_initialized) return;
39
46
 
47
+ if (machine->sidecar_mode) um_sidecar_teardown(machine);
48
+ if (machine->sidecar_signal) free(machine->sidecar_signal);
49
+
40
50
  for (unsigned i = 0; i < machine->buffer_ring_count; i++) {
41
51
  struct buf_ring_descriptor *desc = machine->buffer_rings + i;
42
52
  io_uring_free_buf_ring(&machine->ring, desc->br, desc->buf_count, i);
@@ -59,8 +69,7 @@ inline struct io_uring_sqe *um_get_sqe(struct um *machine, struct um_op *op) {
59
69
  sqe = io_uring_get_sqe(&machine->ring);
60
70
  if (likely(sqe)) goto done;
61
71
 
62
- fprintf(stderr, "!!!Failed to get SQE\n");
63
- um_raise_internal_error("Failed to get SQE");
72
+ um_raise_internal_error("Submission queue full. Consider raising the machine size.");
64
73
 
65
74
  // TODO: retry getting SQE?
66
75
 
@@ -271,37 +280,60 @@ inline void um_profile_wait_cqe_post(struct um *machine, double time_monotonic0,
271
280
  // machine->metrics.time_last_cpu = time_cpu;
272
281
  }
273
282
 
283
+ inline void *um_wait_for_sidecar_signal(void *ptr) {
284
+ struct um *machine = ptr;
285
+ um_sidecar_signal_wait(machine);
286
+ return NULL;
287
+ }
288
+
274
289
  // Waits for the given minimum number of completion entries. The wait_nr is
275
290
  // either 1 - where we wait for at least one CQE to be ready, or 0, where we
276
291
  // don't wait, and just process any CQEs that already ready.
277
292
  static inline void um_wait_for_and_process_ready_cqes(struct um *machine, int wait_nr) {
278
293
  struct wait_for_cqe_ctx ctx = { .machine = machine, .cqe = NULL, .wait_nr = wait_nr };
279
294
  machine->metrics.total_waits++;
280
- double time_monotonic0 = 0.0;
281
- VALUE fiber;
282
- if (machine->profile_mode) um_profile_wait_cqe_pre(machine, &time_monotonic0, &fiber);
283
- rb_thread_call_without_gvl(um_wait_for_cqe_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
284
- if (machine->profile_mode) um_profile_wait_cqe_post(machine, time_monotonic0, fiber);
285
-
286
- if (unlikely(ctx.result < 0)) {
287
- // the internal calls to (maybe submit) and wait for cqes may fail with:
288
- // -EINTR (interrupted by signal)
289
- // -EAGAIN (apparently can be returned when wait_nr = 0)
290
- // both should not raise an exception.
291
- switch (ctx.result) {
292
- case -EINTR:
293
- case -EAGAIN:
294
- // do nothing
295
- break;
296
- default:
297
- rb_syserr_fail(-ctx.result, strerror(-ctx.result));
298
- }
299
- }
300
295
 
301
- if (ctx.cqe) {
302
- um_process_cqe(machine, ctx.cqe);
303
- io_uring_cq_advance(&machine->ring, 1);
296
+ if (machine->sidecar_mode) {
297
+ // fprintf(stderr, ">> sidecar wait cqes (unsubmitted: %d)\n", machine->metrics.ops_unsubmitted);
298
+ if (machine->metrics.ops_unsubmitted) {
299
+ io_uring_submit(&machine->ring);
300
+ machine->metrics.ops_unsubmitted = 0;
301
+ }
302
+ if (wait_nr) {
303
+ // fprintf(stderr, ">> um_wait_for_sidecar_signal\n");
304
+ // rb_thread_call_without_gvl(um_wait_for_sidecar_signal, (void *)machine, RUBY_UBF_PROCESS, 0);
305
+ // fprintf(stderr, "<< um_wait_for_sidecar_signal\n");
306
+ um_sidecar_signal_wait(machine);
307
+ }
304
308
  um_process_ready_cqes(machine);
309
+ // fprintf(stderr, "<< sidecar wait cqes\n");
310
+ }
311
+ else {
312
+ double time_monotonic0 = 0.0;
313
+ VALUE fiber;
314
+ if (machine->profile_mode) um_profile_wait_cqe_pre(machine, &time_monotonic0, &fiber);
315
+ rb_thread_call_without_gvl(um_wait_for_cqe_without_gvl, (void *)&ctx, RUBY_UBF_IO, 0);
316
+ if (machine->profile_mode) um_profile_wait_cqe_post(machine, time_monotonic0, fiber);
317
+
318
+ if (unlikely(ctx.result < 0)) {
319
+ // the internal calls to (maybe submit) and wait for cqes may fail with:
320
+ // -EINTR (interrupted by signal)
321
+ // -EAGAIN (apparently can be returned when wait_nr = 0)
322
+ // both should not raise an exception.
323
+ switch (ctx.result) {
324
+ case -EINTR:
325
+ case -EAGAIN:
326
+ // do nothing
327
+ break;
328
+ default:
329
+ rb_syserr_fail(-ctx.result, strerror(-ctx.result));
330
+ }
331
+ }
332
+ if (ctx.cqe) {
333
+ um_process_cqe(machine, ctx.cqe);
334
+ io_uring_cq_advance(&machine->ring, 1);
335
+ um_process_ready_cqes(machine);
336
+ }
305
337
  }
306
338
  }
307
339
 
@@ -336,30 +368,15 @@ inline VALUE um_switch(struct um *machine) {
336
368
  &machine->ring, machine->metrics.ops_unsubmitted, machine->metrics.ops_pending,
337
369
  machine->metrics.total_ops
338
370
  );
371
+
339
372
  while (true) {
340
373
  struct um_op *op = um_runqueue_shift(machine);
341
374
  if (op) {
342
375
  if (unlikely(op->flags & OP_F_RUNQUEUE_SKIP)) continue;
343
376
 
344
- // in case of a snooze, we need to prevent a situation where completions
345
- // are not processed because the runqueue is never empty. Theoretically,
346
- // we can still have a situation where multiple fibers are all doing a
347
- // snooze repeatedly, which can prevent completions from being processed.
348
-
349
- // is the op a snooze op and is this the same fiber as the current one?
350
- if (unlikely(op->kind == OP_SCHEDULE && op->fiber == rb_fiber_current())) {
351
- // are there any pending ops (i.e. waiting for completion)?
352
- if (machine->metrics.ops_pending > 0) {
353
- // if yes, process completions, get runqueue head, put original op
354
- // back on runqueue.
355
- // um_process_ready_cqes(machine);
356
- um_wait_for_and_process_ready_cqes(machine, 0);
357
- struct um_op *op2 = um_runqueue_shift(machine);
358
- if (likely(op2 && op2 != op)) {
359
- um_runqueue_push(machine, op);
360
- op = op2;
361
- }
362
- }
377
+ // in test mode we want to process I/O on each snooze
378
+ if (unlikely(machine->test_mode && (op->kind == OP_SCHEDULE))) {
379
+ um_wait_for_and_process_ready_cqes(machine, 0);
363
380
  }
364
381
  return process_runqueue_op(machine, op);
365
382
  }
@@ -513,7 +530,7 @@ VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t b
513
530
  VALUE ret = um_yield(machine);
514
531
 
515
532
  if (um_check_completion(machine, &op)) {
516
- um_update_read_buffer(machine, buffer, buffer_offset, op.result.res, op.result.flags);
533
+ um_update_read_buffer(buffer, buffer_offset, op.result.res);
517
534
  ret = INT2NUM(op.result.res);
518
535
 
519
536
  }
@@ -563,6 +580,22 @@ VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_
563
580
  return ret;
564
581
  }
565
582
 
583
+ size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t maxlen) {
584
+ struct um_op op;
585
+ um_prep_op(machine, &op, OP_WRITE, 0);
586
+ struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
587
+ io_uring_prep_write(sqe, fd, buffer, maxlen, 0);
588
+
589
+ VALUE ret = um_yield(machine);
590
+
591
+ if (um_check_completion(machine, &op))
592
+ return op.result.res;
593
+
594
+ RAISE_IF_EXCEPTION(ret);
595
+ RB_GC_GUARD(ret);
596
+ return 0;
597
+ }
598
+
566
599
  VALUE um_writev(struct um *machine, int fd, int argc, VALUE *argv) {
567
600
  __u64 file_offset = -1;
568
601
  if (TYPE(argv[argc - 1]) == T_FIXNUM) {
@@ -592,10 +625,10 @@ VALUE um_writev(struct um *machine, int fd, int argc, VALUE *argv) {
592
625
 
593
626
  int completed = um_op_completed_p(&op);
594
627
  if (unlikely(!completed)) goto cancelled;
595
-
628
+
596
629
  writev_res = op.result.res;
597
630
  if (unlikely(writev_res < 0)) goto done;
598
-
631
+
599
632
  len -= writev_res;
600
633
  if (len) {
601
634
  um_advance_iovecs_for_writing(&iovecs_ptr, &iovecs_len, (size_t)writev_res);
@@ -788,7 +821,7 @@ VALUE um_recv(struct um *machine, int fd, VALUE buffer, size_t maxlen, int flags
788
821
  VALUE ret = um_yield(machine);
789
822
 
790
823
  if (um_check_completion(machine, &op)) {
791
- um_update_read_buffer(machine, buffer, 0, op.result.res, op.result.flags);
824
+ um_update_read_buffer(buffer, 0, op.result.res);
792
825
  ret = INT2NUM(op.result.res);
793
826
  }
794
827
 
@@ -1016,7 +1049,7 @@ VALUE um_select(struct um *machine, VALUE rfds, VALUE wfds, VALUE efds) {
1016
1049
  }
1017
1050
 
1018
1051
  while (pending) {
1019
- um_wait_for_and_process_ready_cqes(machine, 0);
1052
+ um_wait_for_and_process_ready_cqes(machine, 1);
1020
1053
 
1021
1054
  for (uint i = 0; i < total_len; i++) {
1022
1055
  struct um_op *op = ops + i;
data/ext/um/um.h CHANGED
@@ -156,7 +156,11 @@ struct um {
156
156
  uint mark; // used to mark instances for debugging
157
157
 
158
158
  struct um_metrics metrics;
159
+ int test_mode;
159
160
  int profile_mode;
161
+ int sidecar_mode;
162
+ pthread_t sidecar_thread;
163
+ uint32_t *sidecar_signal;
160
164
 
161
165
  uint buffer_ring_count; // number of registered buffer rings
162
166
 
@@ -166,7 +170,7 @@ struct um {
166
170
  struct buf_ring_descriptor buffer_rings[BUFFER_RING_MAX_COUNT];
167
171
 
168
172
  struct um_op *transient_head; // list of pending transient ops
169
- VALUE pending_fibers; // hash containing pending fibers
173
+ VALUE pending_fibers; // set containing pending fibers
170
174
 
171
175
  struct um_op *runqueue_head;
172
176
  struct um_op *runqueue_tail;
@@ -227,7 +231,7 @@ extern VALUE cAsyncOp;
227
231
  extern VALUE eStreamRESPError;
228
232
 
229
233
  struct um *um_get_machine(VALUE self);
230
- void um_setup(VALUE self, struct um *machine, uint size, uint sqpoll_timeout_msec);
234
+ void um_setup(VALUE self, struct um *machine, uint size, uint sqpoll_timeout_msec, int sidecar_mode);
231
235
  void um_teardown(struct um *machine);
232
236
 
233
237
  VALUE um_metrics(struct um *machine, struct um_metrics *metrics);
@@ -264,7 +268,7 @@ void um_prep_op(struct um *machine, struct um_op *op, enum um_op_kind kind, unsi
264
268
  void um_raise_on_error_result(int result);
265
269
  void um_get_buffer_bytes_for_writing(VALUE buffer, const void **base, size_t *size);
266
270
  void * um_prepare_read_buffer(VALUE buffer, ssize_t len, ssize_t ofs);
267
- void um_update_read_buffer(struct um *machine, VALUE buffer, ssize_t buffer_offset, __s32 result, __u32 flags);
271
+ void um_update_read_buffer(VALUE buffer, ssize_t buffer_offset, __s32 result);
268
272
  int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count);
269
273
  VALUE um_get_string_from_buffer_ring(struct um *machine, int bgid, __s32 result, __u32 flags);
270
274
  void um_add_strings_to_buffer_ring(struct um *machine, int bgid, VALUE strings);
@@ -293,6 +297,7 @@ VALUE um_read(struct um *machine, int fd, VALUE buffer, size_t maxlen, ssize_t b
293
297
  size_t um_read_raw(struct um *machine, int fd, char *buffer, size_t maxlen);
294
298
  VALUE um_read_each(struct um *machine, int fd, int bgid);
295
299
  VALUE um_write(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset);
300
+ size_t um_write_raw(struct um *machine, int fd, const char *buffer, size_t maxlen);
296
301
  VALUE um_writev(struct um *machine, int fd, int argc, VALUE *argv);
297
302
  VALUE um_write_async(struct um *machine, int fd, VALUE buffer, size_t len, __u64 file_offset);
298
303
  VALUE um_close(struct um *machine, int fd);
@@ -350,6 +355,7 @@ VALUE stream_get_line(struct um_stream *stream, VALUE buf, ssize_t maxlen);
350
355
  VALUE stream_get_string(struct um_stream *stream, VALUE buf, ssize_t len);
351
356
  VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
352
357
  void resp_encode(struct um_write_buffer *buf, VALUE obj);
358
+ void resp_encode_cmd(struct um_write_buffer *buf, int argc, VALUE *argv);
353
359
 
354
360
  __attribute__((noreturn)) void um_raise_internal_error(const char *msg);
355
361
 
@@ -358,4 +364,13 @@ void write_buffer_update_len(struct um_write_buffer *buf);
358
364
 
359
365
  void um_define_net_constants(VALUE mod);
360
366
 
367
+ void um_sidecar_setup(struct um *machine);
368
+ void um_sidecar_teardown(struct um *machine);
369
+ void um_sidecar_signal_wait(struct um *machine);
370
+ void um_sidecar_signal_wake(struct um *machine);
371
+
372
+ void um_ssl_set_bio(struct um *machine, VALUE ssl_obj);
373
+ int um_ssl_read(struct um *machine, VALUE ssl, VALUE buf, int maxlen);
374
+ int um_ssl_write(struct um *machine, VALUE ssl, VALUE buf, int len);
375
+
361
376
  #endif // UM_H
@@ -1,6 +1,13 @@
1
1
  #include "um.h"
2
2
  #include <stdlib.h>
3
3
 
4
+ /*
5
+ * Document-class: UringMachine::AsyncOp
6
+ *
7
+ * Encapsulates an asynchronous operation. Currently the only asynchronous
8
+ * operation supported is a timeout operation.
9
+ */
10
+
4
11
  VALUE cAsyncOp;
5
12
 
6
13
  VALUE SYM_timeout;
@@ -59,6 +66,10 @@ inline int async_op_is_done(struct um_async_op *async_op) {
59
66
  return (async_op->op->flags & OP_F_COMPLETED);
60
67
  }
61
68
 
69
+ /* Returns the kind of asynchronous operation.
70
+ *
71
+ * @return [Symbol] operation kind
72
+ */
62
73
  VALUE AsyncOp_kind(VALUE self) {
63
74
  struct um_async_op *async_op = AsyncOp_data(self);
64
75
  raise_on_missing_op(async_op);
@@ -71,6 +82,10 @@ VALUE AsyncOp_kind(VALUE self) {
71
82
  }
72
83
  }
73
84
 
85
+ /* Returns true if the operation has completed.
86
+ *
87
+ * @return [bool] is the operation done
88
+ */
74
89
  VALUE AsyncOp_done_p(VALUE self) {
75
90
  struct um_async_op *async_op = AsyncOp_data(self);
76
91
  raise_on_missing_op(async_op);
@@ -78,6 +93,10 @@ VALUE AsyncOp_done_p(VALUE self) {
78
93
  return async_op_is_done(async_op) ? Qtrue : Qfalse;
79
94
  }
80
95
 
96
+ /* Returns the operation result. If the operation is not completed, returns nil.
97
+ *
98
+ * @return [Integer, nil] operation result
99
+ */
81
100
  VALUE AsyncOp_result(VALUE self) {
82
101
  struct um_async_op *async_op = AsyncOp_data(self);
83
102
  raise_on_missing_op(async_op);
@@ -85,6 +104,10 @@ VALUE AsyncOp_result(VALUE self) {
85
104
  return async_op_is_done(async_op) ? INT2NUM(async_op->op->result.res) : Qnil;
86
105
  }
87
106
 
107
+ /* Returns true if the operation has been cancelled.
108
+ *
109
+ * @return [bool] is the operation cancelled
110
+ */
88
111
  VALUE AsyncOp_cancelled_p(VALUE self) {
89
112
  struct um_async_op *async_op = AsyncOp_data(self);
90
113
  raise_on_missing_op(async_op);
@@ -94,6 +117,10 @@ VALUE AsyncOp_cancelled_p(VALUE self) {
94
117
  return (async_op->op->result.res == -ECANCELED) ? Qtrue : Qfalse;
95
118
  }
96
119
 
120
+ /* Waits for the operation to complete.
121
+ *
122
+ * @return [Integer] operation result
123
+ */
97
124
  VALUE AsyncOp_await(VALUE self) {
98
125
  struct um_async_op *async_op = AsyncOp_data(self);
99
126
  raise_on_missing_op(async_op);
@@ -104,6 +131,10 @@ VALUE AsyncOp_await(VALUE self) {
104
131
  return um_async_op_await(async_op);
105
132
  }
106
133
 
134
+ /* Cancels the operation.
135
+ *
136
+ * @return [UringMachine::AsyncOp] self
137
+ */
107
138
  VALUE AsyncOp_cancel(VALUE self) {
108
139
  struct um_async_op *async_op = AsyncOp_data(self);
109
140
  raise_on_missing_op(async_op);