uringmachine 0.24.0 → 0.26.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 (279) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitmodules +0 -3
  4. data/CHANGELOG.md +13 -0
  5. data/Gemfile +11 -0
  6. data/README.md +266 -112
  7. data/Rakefile +8 -0
  8. data/TODO.md +14 -21
  9. data/benchmark/common.rb +2 -0
  10. data/benchmark/openssl.rb +77 -0
  11. data/benchmark/openssl_socketpair.rb +112 -0
  12. data/benchmark/sqlite.rb +1 -1
  13. data/docs/design/buffer_pool.md +1 -1
  14. data/docs/wroclove.rb.md +52 -0
  15. data/ext/um/extconf.rb +15 -0
  16. data/ext/um/um.c +392 -358
  17. data/ext/um/um.h +48 -23
  18. data/ext/um/um_async_op.c +9 -8
  19. data/ext/um/um_async_op_class.c +34 -3
  20. data/ext/um/um_class.c +705 -19
  21. data/ext/um/um_const.c +31 -0
  22. data/ext/um/um_mutex_class.c +12 -0
  23. data/ext/um/um_op.c +15 -1
  24. data/ext/um/um_queue_class.c +16 -0
  25. data/ext/um/um_ssl.c +109 -0
  26. data/ext/um/um_stream.c +9 -8
  27. data/ext/um/um_sync.c +18 -11
  28. data/ext/um/um_utils.c +17 -8
  29. data/grant-2025/interim-report.md +1 -1
  30. data/grant-2025/journal.md +4 -4
  31. data/grant-2025/tasks.md +6 -4
  32. data/lib/uringmachine/dns_resolver.rb +38 -0
  33. data/lib/uringmachine/fiber_scheduler.rb +7 -5
  34. data/lib/uringmachine/version.rb +1 -1
  35. data/lib/uringmachine.rb +106 -6
  36. data/test/helper.rb +15 -0
  37. data/test/test_async_op.rb +3 -2
  38. data/test/test_fiber_scheduler.rb +41 -1
  39. data/test/test_ssl.rb +85 -0
  40. data/test/test_stream.rb +11 -0
  41. data/test/test_um.rb +445 -11
  42. data/uringmachine.gemspec +1 -7
  43. data/vendor/liburing/examples/send-zerocopy.c +43 -31
  44. data/vendor/liburing/examples/zcrx.c +260 -69
  45. data/vendor/liburing/liburing.spec +1 -1
  46. data/vendor/liburing/src/include/liburing/io_uring.h +12 -0
  47. data/vendor/liburing/src/include/liburing.h +3 -2
  48. data/vendor/liburing/src/liburing-ffi.map +4 -0
  49. data/vendor/liburing/src/liburing.map +4 -0
  50. data/vendor/liburing/src/queue.c +12 -0
  51. data/vendor/liburing/src/register.c +1 -0
  52. data/vendor/liburing/src/setup.c +15 -7
  53. data/vendor/liburing/test/Makefile +8 -4
  54. data/vendor/liburing/test/conn-unreach.c +1 -1
  55. data/vendor/liburing/test/epwait.c +32 -6
  56. data/vendor/liburing/test/io-wq-exit.c +131 -0
  57. data/vendor/liburing/test/iowait.c +1 -1
  58. data/vendor/liburing/test/min-timeout.c +3 -1
  59. data/vendor/liburing/test/open-close.c +39 -0
  60. data/vendor/liburing/test/poll-update-trigger.c +85 -0
  61. data/vendor/liburing/test/recvsend_bundle.c +14 -11
  62. data/vendor/liburing/test/sendzc-bug.c +146 -0
  63. data/vendor/liburing/test/sqe-mixed-nop.c +151 -7
  64. data/vendor/liburing/test/test.h +2 -0
  65. data/vendor/liburing/test/timestamp-bug.c +135 -0
  66. data/vendor/liburing/test/timestamp.c +5 -0
  67. data/vendor/liburing/test/vec-regbuf.c +136 -1
  68. metadata +38 -283
  69. data/vendor/libressl/.github/scripts/changelog.sh +0 -74
  70. data/vendor/libressl/.github/workflows/android.yml +0 -35
  71. data/vendor/libressl/.github/workflows/cifuzz.yml +0 -33
  72. data/vendor/libressl/.github/workflows/cmake-config.yml +0 -98
  73. data/vendor/libressl/.github/workflows/coverity.yml +0 -69
  74. data/vendor/libressl/.github/workflows/emscripten.yml +0 -71
  75. data/vendor/libressl/.github/workflows/fedora-rawhide.yml +0 -39
  76. data/vendor/libressl/.github/workflows/freebsd.yml +0 -71
  77. data/vendor/libressl/.github/workflows/linux.yml +0 -71
  78. data/vendor/libressl/.github/workflows/macos.yml +0 -37
  79. data/vendor/libressl/.github/workflows/release.yml +0 -81
  80. data/vendor/libressl/.github/workflows/rust-openssl.yml +0 -47
  81. data/vendor/libressl/.github/workflows/solaris.yml +0 -37
  82. data/vendor/libressl/.github/workflows/windows.yml +0 -70
  83. data/vendor/libressl/.gitignore +0 -333
  84. data/vendor/libressl/CMakeLists.txt +0 -581
  85. data/vendor/libressl/COPYING +0 -133
  86. data/vendor/libressl/ChangeLog +0 -3280
  87. data/vendor/libressl/FindLibreSSL.cmake +0 -232
  88. data/vendor/libressl/LibreSSLConfig.cmake.in +0 -36
  89. data/vendor/libressl/Makefile.am +0 -60
  90. data/vendor/libressl/Makefile.am.common +0 -20
  91. data/vendor/libressl/OPENBSD_BRANCH +0 -1
  92. data/vendor/libressl/README.md +0 -238
  93. data/vendor/libressl/README.mingw.md +0 -43
  94. data/vendor/libressl/apps/CMakeLists.txt +0 -18
  95. data/vendor/libressl/apps/Makefile.am +0 -5
  96. data/vendor/libressl/apps/nc/CMakeLists.txt +0 -67
  97. data/vendor/libressl/apps/nc/Makefile.am +0 -64
  98. data/vendor/libressl/apps/nc/compat/accept4.c +0 -17
  99. data/vendor/libressl/apps/nc/compat/readpassphrase.c +0 -205
  100. data/vendor/libressl/apps/nc/compat/socket.c +0 -29
  101. data/vendor/libressl/apps/nc/compat/sys/socket.h +0 -30
  102. data/vendor/libressl/apps/ocspcheck/CMakeLists.txt +0 -44
  103. data/vendor/libressl/apps/ocspcheck/Makefile.am +0 -45
  104. data/vendor/libressl/apps/ocspcheck/compat/.gitignore +0 -0
  105. data/vendor/libressl/apps/openssl/CMakeLists.txt +0 -97
  106. data/vendor/libressl/apps/openssl/Makefile.am +0 -108
  107. data/vendor/libressl/apps/openssl/apps_win.c +0 -138
  108. data/vendor/libressl/apps/openssl/certhash_win.c +0 -13
  109. data/vendor/libressl/apps/openssl/compat/clock_gettime_osx.c +0 -26
  110. data/vendor/libressl/apps/openssl/compat/poll_win.c +0 -329
  111. data/vendor/libressl/appveyor.yml +0 -53
  112. data/vendor/libressl/autogen.sh +0 -15
  113. data/vendor/libressl/check-release.sh +0 -86
  114. data/vendor/libressl/cmake_export_symbol.cmake +0 -71
  115. data/vendor/libressl/cmake_uninstall.cmake.in +0 -36
  116. data/vendor/libressl/config +0 -17
  117. data/vendor/libressl/configure.ac +0 -165
  118. data/vendor/libressl/crypto/CMakeLists.txt +0 -863
  119. data/vendor/libressl/crypto/Makefile.am +0 -962
  120. data/vendor/libressl/crypto/Makefile.am.arc4random +0 -46
  121. data/vendor/libressl/crypto/Makefile.am.elf-mips +0 -14
  122. data/vendor/libressl/crypto/Makefile.am.elf-mips64 +0 -14
  123. data/vendor/libressl/crypto/Makefile.am.elf-x86_64 +0 -35
  124. data/vendor/libressl/crypto/Makefile.am.macosx-x86_64 +0 -35
  125. data/vendor/libressl/crypto/Makefile.am.masm-x86_64 +0 -22
  126. data/vendor/libressl/crypto/Makefile.am.mingw64-x86_64 +0 -23
  127. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_darwin.c +0 -60
  128. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_linux.c +0 -62
  129. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_none.c +0 -26
  130. data/vendor/libressl/crypto/arch/aarch64/crypto_cpu_caps_windows.c +0 -36
  131. data/vendor/libressl/crypto/arch/loongarch64/crypto_arch.h +0 -21
  132. data/vendor/libressl/crypto/arch/mips/crypto_arch.h +0 -21
  133. data/vendor/libressl/crypto/bn/arch/loongarch64/bn_arch.h +0 -23
  134. data/vendor/libressl/crypto/bn/arch/mips/bn_arch.h +0 -24
  135. data/vendor/libressl/crypto/compat/.gitignore +0 -31
  136. data/vendor/libressl/crypto/compat/arc4random.h +0 -41
  137. data/vendor/libressl/crypto/compat/b_win.c +0 -55
  138. data/vendor/libressl/crypto/compat/bsd-asprintf.c +0 -96
  139. data/vendor/libressl/crypto/compat/crypto_lock_win.c +0 -56
  140. data/vendor/libressl/crypto/compat/explicit_bzero_win.c +0 -13
  141. data/vendor/libressl/crypto/compat/freezero.c +0 -32
  142. data/vendor/libressl/crypto/compat/getdelim.c +0 -78
  143. data/vendor/libressl/crypto/compat/getline.c +0 -40
  144. data/vendor/libressl/crypto/compat/getopt_long.c +0 -528
  145. data/vendor/libressl/crypto/compat/getpagesize.c +0 -18
  146. data/vendor/libressl/crypto/compat/getprogname_linux.c +0 -23
  147. data/vendor/libressl/crypto/compat/getprogname_unimpl.c +0 -7
  148. data/vendor/libressl/crypto/compat/getprogname_windows.c +0 -13
  149. data/vendor/libressl/crypto/compat/posix_win.c +0 -296
  150. data/vendor/libressl/crypto/compat/syslog_r.c +0 -19
  151. data/vendor/libressl/crypto/compat/ui_openssl_win.c +0 -334
  152. data/vendor/libressl/dist.sh +0 -22
  153. data/vendor/libressl/gen-coverage-report.sh +0 -58
  154. data/vendor/libressl/gen-openbsd-tags.sh +0 -20
  155. data/vendor/libressl/include/CMakeLists.txt +0 -61
  156. data/vendor/libressl/include/Makefile.am +0 -79
  157. data/vendor/libressl/include/arch/loongarch64/opensslconf.h +0 -150
  158. data/vendor/libressl/include/arch/mips/opensslconf.h +0 -150
  159. data/vendor/libressl/include/compat/arpa/inet.h +0 -15
  160. data/vendor/libressl/include/compat/arpa/nameser.h +0 -25
  161. data/vendor/libressl/include/compat/cet.h +0 -19
  162. data/vendor/libressl/include/compat/dirent.h +0 -17
  163. data/vendor/libressl/include/compat/dirent_msvc.h +0 -611
  164. data/vendor/libressl/include/compat/endian.h +0 -161
  165. data/vendor/libressl/include/compat/err.h +0 -95
  166. data/vendor/libressl/include/compat/fcntl.h +0 -32
  167. data/vendor/libressl/include/compat/getopt.h +0 -50
  168. data/vendor/libressl/include/compat/limits.h +0 -25
  169. data/vendor/libressl/include/compat/netdb.h +0 -10
  170. data/vendor/libressl/include/compat/netinet/in.h +0 -19
  171. data/vendor/libressl/include/compat/netinet/ip.h +0 -49
  172. data/vendor/libressl/include/compat/netinet/tcp.h +0 -10
  173. data/vendor/libressl/include/compat/poll.h +0 -63
  174. data/vendor/libressl/include/compat/pthread.h +0 -122
  175. data/vendor/libressl/include/compat/readpassphrase.h +0 -44
  176. data/vendor/libressl/include/compat/resolv.h +0 -24
  177. data/vendor/libressl/include/compat/stdint.h +0 -31
  178. data/vendor/libressl/include/compat/stdio.h +0 -65
  179. data/vendor/libressl/include/compat/stdlib.h +0 -57
  180. data/vendor/libressl/include/compat/string.h +0 -98
  181. data/vendor/libressl/include/compat/sys/_null.h +0 -18
  182. data/vendor/libressl/include/compat/sys/ioctl.h +0 -11
  183. data/vendor/libressl/include/compat/sys/mman.h +0 -19
  184. data/vendor/libressl/include/compat/sys/param.h +0 -15
  185. data/vendor/libressl/include/compat/sys/queue.h +0 -536
  186. data/vendor/libressl/include/compat/sys/select.h +0 -10
  187. data/vendor/libressl/include/compat/sys/socket.h +0 -18
  188. data/vendor/libressl/include/compat/sys/stat.h +0 -129
  189. data/vendor/libressl/include/compat/sys/time.h +0 -37
  190. data/vendor/libressl/include/compat/sys/tree.h +0 -1006
  191. data/vendor/libressl/include/compat/sys/types.h +0 -69
  192. data/vendor/libressl/include/compat/sys/uio.h +0 -17
  193. data/vendor/libressl/include/compat/syslog.h +0 -38
  194. data/vendor/libressl/include/compat/time.h +0 -59
  195. data/vendor/libressl/include/compat/unistd.h +0 -83
  196. data/vendor/libressl/include/compat/win32netcompat.h +0 -57
  197. data/vendor/libressl/include/openssl/Makefile.am.tpl +0 -45
  198. data/vendor/libressl/libcrypto.pc.in +0 -28
  199. data/vendor/libressl/libressl.pub +0 -2
  200. data/vendor/libressl/libssl.pc.in +0 -28
  201. data/vendor/libressl/libtls.pc.in +0 -28
  202. data/vendor/libressl/m4/ax_add_fortify_source.m4 +0 -80
  203. data/vendor/libressl/m4/ax_check_compile_flag.m4 +0 -53
  204. data/vendor/libressl/m4/check-hardening-options.m4 +0 -110
  205. data/vendor/libressl/m4/check-libc.m4 +0 -189
  206. data/vendor/libressl/m4/check-os-options.m4 +0 -181
  207. data/vendor/libressl/m4/disable-compiler-warnings.m4 +0 -44
  208. data/vendor/libressl/man/CMakeLists.txt +0 -26
  209. data/vendor/libressl/man/links +0 -2780
  210. data/vendor/libressl/man/update_links.sh +0 -25
  211. data/vendor/libressl/openssl.pc.in +0 -11
  212. data/vendor/libressl/patches/bn_shift.patch +0 -34
  213. data/vendor/libressl/patches/crypto_arch.h.patch +0 -34
  214. data/vendor/libressl/patches/crypto_namespace.h.patch +0 -22
  215. data/vendor/libressl/patches/netcat.c.patch +0 -178
  216. data/vendor/libressl/patches/openssl.c.patch +0 -12
  217. data/vendor/libressl/patches/opensslfeatures.h.patch +0 -49
  218. data/vendor/libressl/patches/patch-amd64-crypto-cpu-caps.c.patch +0 -20
  219. data/vendor/libressl/patches/patch-i386-crypto-cpu-caps.c.patch +0 -20
  220. data/vendor/libressl/patches/speed.c.patch +0 -114
  221. data/vendor/libressl/patches/ssl_namespace.h.patch +0 -21
  222. data/vendor/libressl/patches/tls.h.patch +0 -16
  223. data/vendor/libressl/patches/tls_config.c.patch +0 -15
  224. data/vendor/libressl/patches/win32_amd64_bn_arch.h.patch +0 -28
  225. data/vendor/libressl/patches/windows_headers.patch +0 -80
  226. data/vendor/libressl/scripts/config.guess +0 -1774
  227. data/vendor/libressl/scripts/config.sub +0 -1907
  228. data/vendor/libressl/scripts/i686-w64-mingw32.cmake +0 -9
  229. data/vendor/libressl/scripts/test +0 -210
  230. data/vendor/libressl/scripts/wrap-compiler-for-flag-check +0 -31
  231. data/vendor/libressl/scripts/x86_64-w64-mingw32.cmake +0 -9
  232. data/vendor/libressl/ssl/CMakeLists.txt +0 -183
  233. data/vendor/libressl/ssl/Makefile.am +0 -187
  234. data/vendor/libressl/tests/CMakeLists.txt +0 -970
  235. data/vendor/libressl/tests/Makefile.am +0 -944
  236. data/vendor/libressl/tests/aeadtest.sh +0 -30
  237. data/vendor/libressl/tests/arc4randomforktest.sh +0 -21
  238. data/vendor/libressl/tests/asn1time_small.test +0 -10
  239. data/vendor/libressl/tests/cmake/CMakeLists.txt +0 -52
  240. data/vendor/libressl/tests/cmake/crypto.c +0 -7
  241. data/vendor/libressl/tests/cmake/ssl.c +0 -6
  242. data/vendor/libressl/tests/cmake/tls.c +0 -6
  243. data/vendor/libressl/tests/compat/pipe2.c +0 -186
  244. data/vendor/libressl/tests/dtlstest.sh +0 -28
  245. data/vendor/libressl/tests/evptest.sh +0 -22
  246. data/vendor/libressl/tests/keypairtest.sh +0 -27
  247. data/vendor/libressl/tests/mlkem_tests.sh +0 -39
  248. data/vendor/libressl/tests/ocsptest.bat +0 -25
  249. data/vendor/libressl/tests/ocsptest.sh +0 -23
  250. data/vendor/libressl/tests/openssl.cnf +0 -29
  251. data/vendor/libressl/tests/optionstest.c +0 -381
  252. data/vendor/libressl/tests/pidwraptest.c +0 -85
  253. data/vendor/libressl/tests/pidwraptest.sh +0 -26
  254. data/vendor/libressl/tests/quictest.bat +0 -27
  255. data/vendor/libressl/tests/quictest.sh +0 -30
  256. data/vendor/libressl/tests/renegotiation_test.bat +0 -27
  257. data/vendor/libressl/tests/renegotiation_test.sh +0 -30
  258. data/vendor/libressl/tests/rfc5280time_small.test +0 -10
  259. data/vendor/libressl/tests/servertest.bat +0 -27
  260. data/vendor/libressl/tests/servertest.sh +0 -30
  261. data/vendor/libressl/tests/shutdowntest.bat +0 -27
  262. data/vendor/libressl/tests/shutdowntest.sh +0 -30
  263. data/vendor/libressl/tests/ssltest.bat +0 -32
  264. data/vendor/libressl/tests/ssltest.sh +0 -48
  265. data/vendor/libressl/tests/testdsa.bat +0 -47
  266. data/vendor/libressl/tests/testdsa.sh +0 -57
  267. data/vendor/libressl/tests/testenc.bat +0 -85
  268. data/vendor/libressl/tests/testenc.sh +0 -93
  269. data/vendor/libressl/tests/testrsa.bat +0 -47
  270. data/vendor/libressl/tests/testrsa.sh +0 -57
  271. data/vendor/libressl/tests/testssl.bat +0 -171
  272. data/vendor/libressl/tests/tlstest.bat +0 -27
  273. data/vendor/libressl/tests/tlstest.sh +0 -28
  274. data/vendor/libressl/tls/CMakeLists.txt +0 -125
  275. data/vendor/libressl/tls/Makefile.am +0 -76
  276. data/vendor/libressl/tls/compat/ftruncate.c +0 -17
  277. data/vendor/libressl/tls/compat/pread.c +0 -29
  278. data/vendor/libressl/tls/compat/pwrite.c +0 -29
  279. data/vendor/libressl/update.sh +0 -460
data/lib/uringmachine.rb CHANGED
@@ -6,27 +6,52 @@ require 'uringmachine/dns_resolver'
6
6
 
7
7
  UM = UringMachine
8
8
 
9
+ # A UringMachine instance provides an interface for performing I/O operations
10
+ # and automatically switching between fibers. A single UringMachine instance
11
+ # should be used for each thread.
9
12
  class UringMachine
10
- def fiber_map
11
- @fiber_map ||= {}
13
+
14
+ # Returns the set of running fibers.
15
+ #
16
+ # return [Set]
17
+ def fiber_set
18
+ @fiber_set ||= Set.new
12
19
  end
13
20
 
21
+ # Terminate is an exception used to terminate fibers without further bubbling.
14
22
  class Terminate < Exception
15
23
  end
16
24
 
25
+ # Creates a new fiber and schedules it to be ran.
26
+ #
27
+ # @param value [any] Value to be passed to the given block
28
+ # @param klass [Class] fiber class
29
+ # @param block [Proc] block to run in fiber
30
+ # @return [Fiber] new fiber
17
31
  def spin(value = nil, klass = Fiber, &block)
18
- fiber = klass.new { |v| run_block_in_fiber(block, fiber, v) }
32
+ fiber = klass.new(blocking: false) { |v| run_block_in_fiber(block, fiber, v) }
19
33
  self.schedule(fiber, value)
20
34
 
21
- fiber_map[fiber] = fiber
35
+ fiber_set << fiber
36
+ fiber
22
37
  end
23
38
 
39
+ # Runs the given block in the given fiber. This method is used to run fibers
40
+ # indirectly.
41
+ #
42
+ # @param fiber [Fiber] fiber
43
+ # @param block [Proc] block to run
44
+ # @return [Fiber]
24
45
  def run(fiber, &block)
25
46
  run_block_in_fiber(block, fiber, nil)
26
47
  self.schedule(fiber, nil)
27
- fiber_map[fiber] = fiber
48
+ fiber_set << fiber
49
+ fiber
28
50
  end
29
51
 
52
+ # Waits for the given fibers to terminate.
53
+ #
54
+ # @return [Array<any>] return values of the given fibers
30
55
  def join(*fibers)
31
56
  results = fibers.inject({}) { |h, f| h[f] = nil; h }
32
57
  queue = nil
@@ -51,6 +76,11 @@ class UringMachine
51
76
  fibers.size == 1 ? values.first : values
52
77
  end
53
78
 
79
+ # Waits for the given fibers to terminate, without collecting their return
80
+ # values.
81
+ #
82
+ # @param fibers [Fiber, Array<Fiber>] fibers to wait for
83
+ # @return [Integer] number of fibers
54
84
  def await_fibers(fibers)
55
85
  if fibers.is_a?(Fiber)
56
86
  f = fibers
@@ -80,13 +110,50 @@ class UringMachine
80
110
  fibers.count
81
111
  end
82
112
 
113
+ # Resolves a hostname to an IP address by performing a DNS query.
114
+ #
115
+ # @param hostname [String] hostname
116
+ # @param type [Symbol] record type
117
+ # @return [String] IP address
83
118
  def resolve(hostname, type = :A)
84
119
  @resolver ||= DNSResolver.new(self)
85
120
  @resolver.resolve(hostname, type)
86
121
  end
87
122
 
123
+ # Watches for filesystem events using inotify in an infinite loop, yielding
124
+ # incoming events to the given block.
125
+ #
126
+ # @param root [String] directory to watch
127
+ # @param mask [Integer] event mask
128
+ # @return [void]
129
+ def file_watch(root, mask)
130
+ fd = UM.inotify_init
131
+ wd_map = {}
132
+ recursive_file_watch(fd, root, wd_map, mask)
133
+ while true
134
+ events = inotify_get_events(fd)
135
+ events.each do |event|
136
+ if event[:mask] | UM::IN_IGNORED == UM::IN_IGNORED
137
+ wd_map.delete(event[:wd])
138
+ next
139
+ end
140
+ transformed_event = transform_file_watch_event(event, wd_map)
141
+ if event[:mask] == UM::IN_CREATE | UM::IN_ISDIR
142
+ recursive_file_watch(fd, transformed_event[:fn], wd_map, mask)
143
+ end
144
+ yield transformed_event
145
+ end
146
+ end
147
+ ensure
148
+ close_async(fd)
149
+ end
150
+
88
151
  private
89
152
 
153
+ # @param block [Proc]
154
+ # @param fiber [Fiber]
155
+ # @param value [any]
156
+ # @return [void]
90
157
  def run_block_in_fiber(block, fiber, value)
91
158
  ret = block.(value)
92
159
  fiber.set_result(ret)
@@ -95,13 +162,15 @@ class UringMachine
95
162
  ensure
96
163
  fiber.mark_as_done
97
164
  # cleanup
98
- fiber_map.delete(fiber)
165
+ fiber_set.delete(fiber)
99
166
  self.notify_done_listeners(fiber)
100
167
 
101
168
  # switch away to a different fiber
102
169
  self.switch
103
170
  end
104
171
 
172
+ # @param fiber [Fiber]
173
+ # @return [void]
105
174
  def notify_done_listeners(fiber)
106
175
  listeners = fiber.done_listeners
107
176
  return if !listeners
@@ -109,25 +178,53 @@ class UringMachine
109
178
  listeners.each { self.push(it, fiber) }
110
179
  end
111
180
 
181
+ # @param fd [Integer] inotify fd
182
+ # @param dir [String] directory path
183
+ # @param wd_map [Hash] hash mapping wd to directory
184
+ # @param mask [Integer] inotify event mask
185
+ # @return [void]
186
+ def recursive_file_watch(fd, dir, wd_map, mask)
187
+ wd = UM.inotify_add_watch(fd, dir, mask)
188
+ wd_map[wd] = dir
189
+ Dir[File.join(dir, '*')].each do
190
+ recursive_file_watch(fd, it, wd_map, mask) if File.directory?(it)
191
+ end
192
+ end
193
+
194
+ # @param event [Hash] inotify event
195
+ # @param wd_map [Hash] hash mapping wd to directory
196
+ def transform_file_watch_event(event, wd_map)
197
+ {
198
+ mask: event[:mask],
199
+ fn: File.join(wd_map[event[:wd]], event[:name])
200
+ }
201
+ end
202
+
203
+ # Fiber extensions
112
204
  module FiberExtensions
113
205
  attr_reader :result, :done, :done_listeners
114
206
 
207
+ # Marks the fiber as done (terminated)
115
208
  def mark_as_done
116
209
  @done = true
117
210
  end
118
211
 
212
+ # Sets the fiber return value
119
213
  def set_result(value)
120
214
  @result = value
121
215
  end
122
216
 
217
+ # Returns true if the fiber is done (terminated)
123
218
  def done?
124
219
  @done
125
220
  end
126
221
 
222
+ # Adds the given queue to the list of done listeners
127
223
  def add_done_listener(queue)
128
224
  (@done_listeners ||= []) << queue
129
225
  end
130
226
 
227
+ # Returns the fiber's associated mailbox
131
228
  def mailbox
132
229
  @mailbox ||= UM::Queue.new
133
230
  end
@@ -137,7 +234,10 @@ class UringMachine
137
234
  include FiberExtensions
138
235
  end
139
236
 
237
+ # Thread extensions
140
238
  module ThreadExtensions
239
+
240
+ # Returns the thread's associated UringMachine instance
141
241
  def machine
142
242
  @machine ||= UM.new
143
243
  end
data/test/helper.rb CHANGED
@@ -85,4 +85,19 @@ class UMBaseTest < Minitest::Test
85
85
  @@port += 1
86
86
  end
87
87
  end
88
+
89
+ def make_tmp_file_tree(dir, spec)
90
+ FileUtils.mkdir(dir) rescue nil
91
+ spec.each do |k, v|
92
+ fn = File.join(dir, k.to_s)
93
+ case v
94
+ when String
95
+ IO.write(fn, v)
96
+ when Hash
97
+ FileUtils.mkdir(fn) rescue nil
98
+ make_tmp_file_tree(fn, v)
99
+ end
100
+ end
101
+ dir
102
+ end
88
103
  end
@@ -51,11 +51,12 @@ class AsyncOpTest < UMBaseTest
51
51
  @op.cancel
52
52
  end
53
53
 
54
- res = @op.await
54
+ assert_raises(Errno::ECANCELED) {
55
+ @op.await
56
+ }
55
57
 
56
58
  assert_equal 0, machine.metrics[:ops_pending]
57
59
  assert_equal true, @op.done?
58
- assert_equal (-ECANCELED), res
59
60
  assert_equal true, @op.cancelled?
60
61
  end
61
62
 
@@ -112,6 +112,43 @@ class FiberSchedulerTest < UMBaseTest
112
112
  o.close rescue nil
113
113
  end
114
114
 
115
+ def test_fiber_scheduler_io_with_machine_spin
116
+ i, o = IO.pipe
117
+ buffer = []
118
+
119
+ f1 = machine.spin do
120
+ sleep 0.01
121
+ o.write 'foo'
122
+ buffer << :f1
123
+ end
124
+
125
+ f2 = machine.spin do
126
+ sleep 0.02
127
+ o.write 'bar'
128
+ buffer << :f2
129
+ o.close
130
+ end
131
+
132
+ f3 = machine.spin do
133
+ str = i.read
134
+ buffer << str
135
+ end
136
+
137
+ machine.join(f1, f2, f3)
138
+ assert_equal [true] * 3, [f1, f2, f3].map(&:done?)
139
+ assert_equal [:f1, :f2, 'foobar'], buffer
140
+
141
+ assert_equal({
142
+ kernel_sleep: 2,
143
+ io_write: 2,
144
+ io_read: 3,
145
+ io_close: 1
146
+ }, scheduler_calls_tally)
147
+ ensure
148
+ i.close rescue nil
149
+ o.close rescue nil
150
+ end
151
+
115
152
  def test_io_read_with_timeout
116
153
  i, o = IO.pipe
117
154
  i.timeout = 0.01
@@ -356,9 +393,12 @@ class FiberSchedulerTest < UMBaseTest
356
393
  sleep 0.001
357
394
  buf = IO.read(fn)
358
395
  end
359
- assert_equal 2, machine.metrics[:total_ops]
360
396
 
361
397
  @scheduler.join
398
+ metrics = machine.metrics
399
+ assert_in_range 5..12, metrics[:total_ops]
400
+ assert_equal 0, metrics[:ops_pending]
401
+ assert_equal 256, metrics[:ops_free]
362
402
  assert_equal 'foobar', buf
363
403
  assert_equal({
364
404
  fiber: 2,
data/test/test_ssl.rb ADDED
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require 'openssl'
5
+ require 'localhost/authority'
6
+
7
+ class SSLTest < UMBaseTest
8
+ def setup
9
+ super
10
+ authority = Localhost::Authority.fetch
11
+ @server_ctx = authority.server_context
12
+ end
13
+
14
+ def test_ssl_stock
15
+ sock1, sock2 = UNIXSocket.pair
16
+
17
+ s1 = OpenSSL::SSL::SSLSocket.new(sock1, @server_ctx)
18
+ s1.sync_close = true
19
+ s2 = OpenSSL::SSL::SSLSocket.new(sock2, OpenSSL::SSL::SSLContext.new)
20
+ s2.sync_close = true
21
+
22
+ t = Thread.new { s1.accept rescue nil }
23
+
24
+ s2.connect
25
+
26
+ assert_equal 6, s1.write('foobar')
27
+ assert_equal 'foobar', s2.readpartial(6)
28
+ ensure
29
+ t.join(0.1)
30
+ sock1&.close rescue nil
31
+ sock2&.close rescue nil
32
+ end
33
+
34
+ def test_ssl_custom_bio
35
+ sock1, sock2 = UNIXSocket.pair
36
+
37
+ s1 = OpenSSL::SSL::SSLSocket.new(sock1, @server_ctx)
38
+ s1.sync_close = true
39
+ s2 = OpenSSL::SSL::SSLSocket.new(sock2, OpenSSL::SSL::SSLContext.new)
40
+ s2.sync_close = true
41
+
42
+ @machine.ssl_set_bio(s2)
43
+ assert_equal true, s2.instance_variable_get(:@__um_bio__)
44
+
45
+ t = Thread.new { s1.accept rescue nil }
46
+
47
+ assert_equal 0, @machine.metrics[:total_ops]
48
+ s2.connect
49
+ refute_equal 0, @machine.metrics[:total_ops]
50
+
51
+ assert_equal 6, s1.write('foobar')
52
+ assert_equal 'foobar', s2.readpartial(6)
53
+ ensure
54
+ t&.join(0.1)
55
+ sock1&.close rescue nil
56
+ sock2&.close rescue nil
57
+ end
58
+
59
+ def test_ssl_read_write
60
+ sock1, sock2 = UNIXSocket.pair
61
+
62
+ s1 = OpenSSL::SSL::SSLSocket.new(sock1, @server_ctx)
63
+ s1.sync_close = true
64
+ s2 = OpenSSL::SSL::SSLSocket.new(sock2, OpenSSL::SSL::SSLContext.new)
65
+ s2.sync_close = true
66
+
67
+ @machine.ssl_set_bio(s2)
68
+ assert_equal true, s2.instance_variable_get(:@__um_bio__)
69
+
70
+ t = Thread.new { s1.accept rescue nil }
71
+
72
+ assert_equal 0, @machine.metrics[:total_ops]
73
+ s2.connect
74
+ refute_equal 0, @machine.metrics[:total_ops]
75
+
76
+ assert_equal 6, @machine.ssl_write(s1, 'foobar', 6)
77
+ buf = +''
78
+ assert_equal 6, @machine.ssl_read(s2, buf, 6)
79
+ assert_equal 'foobar', buf
80
+ ensure
81
+ t&.join(0.1)
82
+ sock1&.close rescue nil
83
+ sock2&.close rescue nil
84
+ end
85
+ end
data/test/test_stream.rb CHANGED
@@ -163,6 +163,8 @@ class StreamRespTest < StreamBaseTest
163
163
  machine.write(@wfd, "%2\r\n+a\r\n:42\r\n+b\r\n*3\r\n+foo\r\n+bar\r\n+baz\r\n")
164
164
  assert_equal({ 'a' => 42, 'b' => ['foo', 'bar', 'baz'] }, @stream.resp_decode)
165
165
 
166
+ machine.write(@wfd, "%2\r\n+a\r\n:42\r\n+b\r\n*3\r\n+foo\r\n+xbar\r\n+yybaz\r\n")
167
+ assert_equal({ 'a' => 42, 'b' => ['foo', 'xbar', 'yybaz'] }, @stream.resp_decode)
166
168
  end
167
169
 
168
170
  def test_resp_encode
@@ -181,6 +183,9 @@ class StreamRespTest < StreamBaseTest
181
183
  assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
182
184
  s.resp_encode(+'', ['foo', 'bar'])
183
185
 
186
+ assert_equal "*2\r\n$3\r\nfoo\r\n$4\r\nxbar\r\n",
187
+ s.resp_encode(+'', ['foo', 'xbar'])
188
+
184
189
  assert_equal "%2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n$3\r\nbaz\r\n:42\r\n",
185
190
  s.resp_encode(+'', { 'foo' => 'bar', 'baz' => 42 })
186
191
  end
@@ -191,10 +196,16 @@ class StreamRespTest < StreamBaseTest
191
196
  assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
192
197
  s.resp_encode_cmd(+'', 'foo', 'bar')
193
198
 
199
+ assert_equal "*2\r\n$3\r\nfoo\r\n$4\r\nxbar\r\n",
200
+ s.resp_encode_cmd(+'', 'foo', 'xbar')
201
+
194
202
  assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",
195
203
  s.resp_encode_cmd(+'', 'foo', :bar)
196
204
 
197
205
  assert_equal "*2\r\n$3\r\nfoo\r\n$3\r\n123\r\n",
198
206
  s.resp_encode_cmd(+'', 'foo', 123)
207
+
208
+ assert_equal "*4\r\n$3\r\nset\r\n$6\r\nfoobar\r\n$2\r\nnx\r\n$2\r\nxx\r\n",
209
+ s.resp_encode_cmd(+'', :set, 'foobar', :nx, :xx)
199
210
  end
200
211
  end