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/ext/um/um_class.c CHANGED
@@ -4,6 +4,7 @@
4
4
  #include <sys/syscall.h>
5
5
  #include <unistd.h>
6
6
  #include <sys/socket.h>
7
+ #include <sys/inotify.h>
7
8
 
8
9
  VALUE cUM;
9
10
  VALUE eUMError;
@@ -20,6 +21,10 @@ VALUE SYM_ops_transient;
20
21
  VALUE SYM_time_total_cpu;
21
22
  VALUE SYM_time_total_wait;
22
23
 
24
+ VALUE SYM_wd;
25
+ VALUE SYM_mask;
26
+ VALUE SYM_name;
27
+
23
28
  static ID id_fileno;
24
29
 
25
30
  static void UM_mark(void *ptr) {
@@ -86,6 +91,14 @@ static inline uint get_sqpoll_timeout_msec(VALUE sqpoll_timeout) {
86
91
  }
87
92
  }
88
93
 
94
+ /* Initializes a new UringMachine instance with the given options.
95
+ *
96
+ * @overload initialize(size: 4096, sqpoll: false, sidecar: false)
97
+ * @param size [Integer] SQ size (default: 4096)
98
+ * @param sqpoll [bool, Number] Set SQPOLL mode, SQPOLL timeout
99
+ * @param sidecar [bool] Set sidecar mode
100
+ * @return [void]
101
+ */
89
102
  VALUE UM_initialize(int argc, VALUE *argv, VALUE self) {
90
103
  static ID kwargs_ids[3];
91
104
  struct um *machine = RTYPEDDATA_DATA(self);
@@ -108,38 +121,68 @@ VALUE UM_initialize(int argc, VALUE *argv, VALUE self) {
108
121
  return self;
109
122
  }
110
123
 
124
+ /* Creates a buffer group (buffer ring) with the given buffer size and buffer count.
125
+ *
126
+ * @param size [Integer] buffer size in bytes
127
+ * @param count [Integer] number of buffers in group
128
+ * @return [Integer] buffer group id
129
+ */
111
130
  VALUE UM_setup_buffer_ring(VALUE self, VALUE size, VALUE count) {
112
131
  struct um *machine = um_get_machine(self);
113
132
  int bgid = um_setup_buffer_ring(machine, NUM2UINT(size), NUM2UINT(count));
114
133
  return INT2NUM(bgid);
115
134
  }
116
135
 
136
+ /* Returns the SQ (submission queue) size.
137
+ *
138
+ * @return [Integer] SQ size
139
+ */
117
140
  VALUE UM_size(VALUE self) {
118
141
  struct um *machine = um_get_machine(self);
119
142
  return UINT2NUM(machine->size);
120
143
  }
121
144
 
145
+ /* :nodoc:
146
+ */
122
147
  VALUE UM_mark_m(VALUE self, VALUE mark) {
123
148
  struct um *machine = um_get_machine(self);
124
149
  machine->mark = NUM2UINT(mark);
125
150
  return self;
126
151
  }
127
152
 
153
+ /* Returns a hash with different metrics about the functioning of the
154
+ * UringMachine instance.
155
+ *
156
+ * @return [Hash] metrics hash
157
+ */
128
158
  VALUE UM_metrics(VALUE self) {
129
159
  struct um *machine = um_get_machine(self);
130
160
  return um_metrics(machine, &machine->metrics);
131
161
  }
132
162
 
163
+ /* Returns the profile mode state.
164
+ *
165
+ * @return [bool] profile mode on/off
166
+ */
133
167
  VALUE UM_profile_mode_p(VALUE self) {
134
168
  struct um *machine = um_get_machine(self);
135
169
  return machine->profile_mode ? Qtrue : Qfalse;
136
170
  }
137
171
 
172
+ /* Returns the SQPOLL mode state.
173
+ *
174
+ * @return [bool] SQPOLL mode on/off
175
+ */
138
176
  VALUE UM_sqpoll_mode_p(VALUE self) {
139
177
  struct um *machine = um_get_machine(self);
140
178
  return machine->sqpoll_mode ? Qtrue : Qfalse;
141
179
  }
142
180
 
181
+ /* Sets/resets profile mode.
182
+ *
183
+ * @param value [bool] profile mode on/off
184
+ * @return [bool] profile mode on/off
185
+ */
143
186
  VALUE UM_profile_mode_set(VALUE self, VALUE value) {
144
187
  struct um *machine = um_get_machine(self);
145
188
  machine->profile_mode = RTEST(value);
@@ -150,29 +193,52 @@ VALUE UM_profile_mode_set(VALUE self, VALUE value) {
150
193
  return value;
151
194
  }
152
195
 
196
+ /* Sets/resets test mode.
197
+ *
198
+ * @param value [bool] test mode on/off
199
+ * @return [bool] test mode on/off
200
+ */
153
201
  VALUE UM_test_mode_set(VALUE self, VALUE value) {
154
202
  struct um *machine = um_get_machine(self);
155
203
  machine->test_mode = RTEST(value);
156
204
  return value;
157
205
  }
158
206
 
207
+ /* Returns the sidecar mode state.
208
+ *
209
+ * @return [bool] sidecar mode on/off
210
+ */
159
211
  VALUE UM_sidecar_mode_p(VALUE self) {
160
212
  struct um *machine = um_get_machine(self);
161
213
  return machine->sidecar_mode ? Qtrue : Qfalse;
162
214
  }
163
215
 
216
+ /* Starts sidecar mode.
217
+ *
218
+ * @return [UringMachine] self
219
+ */
164
220
  VALUE UM_sidecar_start(VALUE self) {
165
221
  struct um *machine = um_get_machine(self);
166
222
  um_sidecar_setup(machine);
167
223
  return self;
168
224
  }
169
225
 
226
+ /* Stops sidecar mode.
227
+ *
228
+ * @return [UringMachine] self
229
+ */
170
230
  VALUE UM_sidecar_stop(VALUE self) {
171
231
  struct um *machine = um_get_machine(self);
172
232
  um_sidecar_teardown(machine);
173
233
  return self;
174
234
  }
175
235
 
236
+ /* Adds the current fiber to the end of the runqueue and yields control to the
237
+ * next fiber in the runqueue. This method is usually used to yield control
238
+ * while performing CPU-intensive work in order not starve other fibers.
239
+ *
240
+ * @return [UringMachine] self
241
+ */
176
242
  VALUE UM_snooze(VALUE self) {
177
243
  struct um *machine = um_get_machine(self);
178
244
  um_schedule(machine, rb_fiber_current(), Qnil);
@@ -184,6 +250,13 @@ VALUE UM_snooze(VALUE self) {
184
250
  return ret;
185
251
  }
186
252
 
253
+ /* Yields control to the next fiber in the runqueue. The current fiber will not
254
+ * be resumed unless it is scheduled again by some other fiber. The call to
255
+ * `#yield` will return the value with which the current fiber will be
256
+ * eventually scheduled.
257
+ *
258
+ * @return [any] resume value
259
+ */
187
260
  VALUE UM_yield(VALUE self) {
188
261
  struct um *machine = um_get_machine(self);
189
262
 
@@ -192,6 +265,14 @@ VALUE UM_yield(VALUE self) {
192
265
  return ret;
193
266
  }
194
267
 
268
+ /* Yields control to the next fiber in the runqueue. The current fiber will not
269
+ * be resumed unless it is scheduled again by some other fiber. The call to
270
+ * `#yield` will return the value with which the current fiber will be
271
+ * eventually scheduled. If resumed with an exception, that exception will be
272
+ * raised when the fiber is resumed.
273
+ *
274
+ * @return [any] resume value
275
+ */
195
276
  VALUE UM_switch(VALUE self) {
196
277
  struct um *machine = um_get_machine(self);
197
278
 
@@ -200,43 +281,100 @@ VALUE UM_switch(VALUE self) {
200
281
  return ret;
201
282
  }
202
283
 
284
+ /* Wakes up the machine in order to start processing its runqueue again. This
285
+ * method is normally called from another thread in order to resume processing
286
+ * of the runqueue when a machine is waiting for I/O completions.
287
+ *
288
+ * @return [void]
289
+ */
203
290
  VALUE UM_wakeup(VALUE self) {
204
291
  struct um *machine = um_get_machine(self);
205
292
  return um_wakeup(machine);
206
293
  }
207
294
 
295
+ /* Submits any pending I/O operations that are not yet submitted.
296
+ *
297
+ * @return [Integer] number of I/O operations submitted
298
+ */
208
299
  VALUE UM_submit(VALUE self) {
209
300
  struct um *machine = um_get_machine(self);
210
301
  uint ret = um_submit(machine);
211
302
  return UINT2NUM(ret);
212
303
  }
213
304
 
305
+ /* Returns a set containing all fibers in pending state (i.e. waiting for an
306
+ * operation to complete.)
307
+ *
308
+ * @return [Set] set of pending fibers
309
+ */
214
310
  VALUE UM_pending_fibers(VALUE self) {
215
311
  struct um *machine = um_get_machine(self);
216
312
  return machine->pending_fibers;
217
313
  }
218
314
 
315
+ /* Schedules the given fiber by adding it to the runqueue. The fiber will be
316
+ * resumed with the given value.
317
+ *
318
+ * @param fiber [Fiber] fiber to schedule
319
+ * @param value [any] resume value
320
+ * @return [UringMachine] self
321
+ */
219
322
  VALUE UM_schedule(VALUE self, VALUE fiber, VALUE value) {
220
323
  struct um *machine = um_get_machine(self);
221
324
  um_schedule(machine, fiber, value);
222
325
  return self;
223
326
  }
224
327
 
225
- VALUE UM_timeout(VALUE self, VALUE interval, VALUE class) {
328
+ /* Runs the given block, interrupting its execution if its runtime exceeds the
329
+ * given timeout interval (in seconds).
330
+ *
331
+ * @param interval [Number] timeout interval in seconds
332
+ * @param exception_class [any] timeout exception class
333
+ * @return [any] block's return value
334
+ */
335
+ VALUE UM_timeout(VALUE self, VALUE interval, VALUE exception_class) {
226
336
  struct um *machine = um_get_machine(self);
227
- return um_timeout(machine, interval, class);
337
+ return um_timeout(machine, interval, exception_class);
228
338
  }
229
339
 
340
+ /* Puts the current fiber to sleep for the given time duration (in seconds),
341
+ * yielding control to the next fiber in the runqueue.
342
+ *
343
+ * @param duration [Number] sleep duration in seconds
344
+ * @return [void]
345
+ */
230
346
  VALUE UM_sleep(VALUE self, VALUE duration) {
231
347
  struct um *machine = um_get_machine(self);
232
348
  return um_sleep(machine, NUM2DBL(duration));
233
349
  }
234
350
 
351
+ /* Runs the given block at regular time intervals in an infinite loop.
352
+ *
353
+ * @param interval [Number] time interval (in seconds) between consecutive invocations
354
+ * @return [void]
355
+ */
235
356
  VALUE UM_periodically(VALUE self, VALUE interval) {
236
357
  struct um *machine = um_get_machine(self);
237
358
  return um_periodically(machine, NUM2DBL(interval));
238
359
  }
239
360
 
361
+ /* call-seq:
362
+ * machine.read(fd, buffer, maxlen[, buffer_offset[, file_offset]]) -> bytes_read
363
+ *
364
+ * Reads up to `maxlen` bytes from the given `fd` into the given buffer. The
365
+ * optional `buffer_offset` parameter determines the position in the buffer into
366
+ * which the data will be read. A negative `buffer_offset` denotes a position
367
+ * relative to the end of the buffer, e.g. a value of `-1` means the data will
368
+ * be appended to the buffer.
369
+ *
370
+ * @overload read(fd, buffer, maxlen, buffer_offset: nil, file_offset: nil)
371
+ * @param fd [Integer] file descriptor
372
+ * @param buffer [String, IO::Buffer] buffer
373
+ * @param maxlen [Integer] maximum number of bytes to read
374
+ * @param buffer_offset [Integer] optional buffer offset to read into
375
+ * @param file_offset [Integer] optional file offset to read from
376
+ * @return [Integer] number of bytes read
377
+ */
240
378
  VALUE UM_read(int argc, VALUE *argv, VALUE self) {
241
379
  struct um *machine = um_get_machine(self);
242
380
  VALUE fd;
@@ -244,7 +382,7 @@ VALUE UM_read(int argc, VALUE *argv, VALUE self) {
244
382
  VALUE maxlen;
245
383
  VALUE buffer_offset;
246
384
  VALUE file_offset;
247
- rb_scan_args(argc, argv, "23", &fd, &buffer, &maxlen, &buffer_offset, &file_offset);
385
+ rb_scan_args(argc, argv, "32", &fd, &buffer, &maxlen, &buffer_offset, &file_offset);
248
386
 
249
387
  ssize_t maxlen_i = NIL_P(maxlen) ? -1 : NUM2INT(maxlen);
250
388
  ssize_t buffer_offset_i = NIL_P(buffer_offset) ? 0 : NUM2INT(buffer_offset);
@@ -253,11 +391,35 @@ VALUE UM_read(int argc, VALUE *argv, VALUE self) {
253
391
  return um_read(machine, NUM2INT(fd), buffer, maxlen_i, buffer_offset_i, file_offset_i);
254
392
  }
255
393
 
394
+ /* call-seq:
395
+ * machine.read_each(fd, bgid) { |data| }
396
+ *
397
+ * Reads repeatedly from the given `fd` using the given buffer group id. The
398
+ * buffer group should have been previously setup using `#setup_buffer_ring`.
399
+ * Read data is yielded in an infinite loop to the given block.
400
+ *
401
+ * @param fd [Integer] file descriptor
402
+ * @param bgid [Integer] buffer group id
403
+ * @return [void]
404
+ */
256
405
  VALUE UM_read_each(VALUE self, VALUE fd, VALUE bgid) {
257
406
  struct um *machine = um_get_machine(self);
258
407
  return um_read_each(machine, NUM2INT(fd), NUM2INT(bgid));
259
408
  }
260
409
 
410
+ /* call-seq:
411
+ * machine.write(fd, buffer[, len[, file_offset]]) -> bytes_written
412
+ *
413
+ * Writes up to `len` bytes from the given buffer to the given `fd`. If `len`,
414
+ * is not given, the entire buffer length is used.
415
+ *
416
+ * @overload write(fd, buffer, len: nil, file_offset: nil)
417
+ * @param fd [Integer] file descriptor
418
+ * @param buffer [String, IO::Buffer] buffer
419
+ * @param len [Integer] maximum number of bytes to write
420
+ * @param file_offset [Integer] optional file offset to write to
421
+ * @return [Integer] number of bytes written
422
+ */
261
423
  VALUE UM_write(int argc, VALUE *argv, VALUE self) {
262
424
  struct um *machine = um_get_machine(self);
263
425
  VALUE fd;
@@ -272,6 +434,21 @@ VALUE UM_write(int argc, VALUE *argv, VALUE self) {
272
434
  return um_write(machine, NUM2INT(fd), buffer, len_i, file_offset_i);
273
435
  }
274
436
 
437
+ /* call-seq:
438
+ * machine.writev(fd, *buffers[, file_offset]) -> bytes_written
439
+ *
440
+ * Writes from the given buffers into the given fd. This method does not
441
+ * guarantee that all data will be written. The application code should check
442
+ * the return value which indicates the number of bytes written and potentially
443
+ * repeat the operation after adjusting the buffers accordingly. See also
444
+ * `#sendv`.
445
+ *
446
+ * @overload writev(fd, *buffers, file_offset: nil)
447
+ * @param fd [Integer] file descriptor
448
+ * @param *buffers [Array<String, IO::Buffer>] data buffers
449
+ * @param file_offset [Integer] optional file offset to write to
450
+ * @return [Integer] number of bytes written
451
+ */
275
452
  VALUE UM_writev(int argc, VALUE *argv, VALUE self) {
276
453
  struct um *machine = um_get_machine(self);
277
454
  if (argc < 1)
@@ -282,6 +459,22 @@ VALUE UM_writev(int argc, VALUE *argv, VALUE self) {
282
459
  return um_writev(machine, fd, argc - 1, argv + 1);
283
460
  }
284
461
 
462
+ /* call-seq:
463
+ * machine.write_async(fd, buffer[, len[, file_offset]]) -> buffer
464
+ *
465
+ * Writes up to `len` bytes from the given buffer to the given `fd`. If `len`,
466
+ * is not given, the entire buffer length is used. This method submits the
467
+ * operation but does not wait for it to complete. This method may be used to
468
+ * improve performance in situations where the application does not care about
469
+ * whether the I/O operation succeeds or not.
470
+ *
471
+ * @overload write_async(fd, buffer, len: nil, file_offset: nil)
472
+ * @param fd [Integer] file descriptor
473
+ * @param buffer [String, IO::Buffer] buffer
474
+ * @param len [Integer] maximum number of bytes to write
475
+ * @param file_offset [Integer] optional file offset to write to
476
+ * @return [String, IO::Buffer] buffer
477
+ */
285
478
  VALUE UM_write_async(int argc, VALUE *argv, VALUE self) {
286
479
  struct um *machine = um_get_machine(self);
287
480
  VALUE fd;
@@ -296,51 +489,150 @@ VALUE UM_write_async(int argc, VALUE *argv, VALUE self) {
296
489
  return um_write_async(machine, NUM2INT(fd), buffer, len_i, file_offset_i);
297
490
  }
298
491
 
492
+ /* call-seq:
493
+ * machine.statx(fd, nil, flags, mask) -> hash
494
+ * machine.statx(dirfd, path, flags, mask) -> hash
495
+ * machine.statx(UM::AT_FDCWD, path, flags, mask) -> hash
496
+ *
497
+ * Returns information about a file.
498
+ *
499
+ * @param dirfd [Integer] file or directory descriptor
500
+ * @param path [String, nil] file path
501
+ * @param flags [Integer] flags
502
+ * @param mask [Integer] mask of information to return
503
+ * @return [hash] hash containing file information
504
+ */
299
505
  VALUE UM_statx(VALUE self, VALUE dirfd, VALUE path, VALUE flags, VALUE mask) {
300
506
  struct um *machine = um_get_machine(self);
301
507
  return um_statx(machine, NUM2INT(dirfd), path, NUM2INT(flags), NUM2UINT(mask));
302
508
  }
303
509
 
510
+ /* call-seq:
511
+ * machine.close(fd) -> 0
512
+ *
513
+ * Closes the given file descriptor.
514
+ *
515
+ * @param fd [Integer] file descriptor
516
+ * @return [0] success
517
+ */
304
518
  VALUE UM_close(VALUE self, VALUE fd) {
305
519
  struct um *machine = um_get_machine(self);
306
520
  return um_close(machine, NUM2INT(fd));
307
521
  }
308
522
 
523
+ /* call-seq:
524
+ * machine.close_async(fd) -> hash
525
+ *
526
+ * Closes the given file descriptor. This method submits the operation but does
527
+ * not wait for it to complete. This method may be used to improve performance
528
+ * in cases where the application des not care whether it succeeds or not.
529
+ *
530
+ * @param fd [Integer] file descriptor
531
+ * @return [Integer] file descriptor
532
+ */
309
533
  VALUE UM_close_async(VALUE self, VALUE fd) {
310
534
  struct um *machine = um_get_machine(self);
311
535
  return um_close_async(machine, NUM2INT(fd));
312
536
  }
313
537
 
314
- VALUE UM_accept(VALUE self, VALUE fd) {
538
+ /* call-seq:
539
+ * machine.accept(server_fd) -> connection_fd
540
+ *
541
+ * Accepts an incoming TCP connection.
542
+ *
543
+ * @param server_fd [Integer] listening socket file descriptor
544
+ * @return [Integer] connection file descriptor
545
+ */
546
+ VALUE UM_accept(VALUE self, VALUE server_fd) {
315
547
  struct um *machine = um_get_machine(self);
316
- return um_accept(machine, NUM2INT(fd));
317
- }
318
-
319
- VALUE UM_accept_each(VALUE self, VALUE fd) {
548
+ return um_accept(machine, NUM2INT(server_fd));
549
+ }
550
+
551
+ /* call-seq:
552
+ * machine.accept_each(server_fd) { |connection_fd| ... }
553
+ *
554
+ * Repeatedly accepts incoming TCP connections in a loop, yielding the
555
+ * connection file descriptors to the given block.
556
+ *
557
+ * @param server_fd [Integer] listening socket file descriptor
558
+ * @return [void]
559
+ */
560
+ VALUE UM_accept_each(VALUE self, VALUE server_fd) {
320
561
  struct um *machine = um_get_machine(self);
321
- return um_accept_each(machine, NUM2INT(fd));
322
- }
323
-
324
- VALUE UM_accept_into_queue(VALUE self, VALUE fd, VALUE queue) {
562
+ return um_accept_each(machine, NUM2INT(server_fd));
563
+ }
564
+
565
+ /* call-seq:
566
+ * machine.accept_each(server_fd, queue)
567
+ *
568
+ * Repeatedly accepts incoming TCP connections in a loop, pushing the connection
569
+ * file descriptors into the given queue.
570
+ *
571
+ * @param server_fd [Integer] listening socket file descriptor
572
+ * @param queue [UM::Queue] connection queue
573
+ * @return [void]
574
+ */
575
+ VALUE UM_accept_into_queue(VALUE self, VALUE server_fd, VALUE queue) {
325
576
  struct um *machine = um_get_machine(self);
326
- return um_accept_into_queue(machine, NUM2INT(fd), queue);
327
- }
328
-
577
+ return um_accept_into_queue(machine, NUM2INT(server_fd), queue);
578
+ }
579
+
580
+ /* call-seq:
581
+ * machine.socket(domain, type, protocol, flags) -> fd
582
+ *
583
+ * Creates a socket.
584
+ *
585
+ * @param domain [Integer] socket domain
586
+ * @param type [Integer] socket type
587
+ * @param protocol [Integer] socket protocol
588
+ * @param flags [Integer] flags
589
+ * @return [Integer] file descriptor
590
+ */
329
591
  VALUE UM_socket(VALUE self, VALUE domain, VALUE type, VALUE protocol, VALUE flags) {
330
592
  struct um *machine = um_get_machine(self);
331
593
  return um_socket(machine, NUM2INT(domain), NUM2INT(type), NUM2INT(protocol), NUM2UINT(flags));
332
594
  }
333
595
 
596
+ /* call-seq:
597
+ * machine.shutdown(fd, how) -> 0
598
+ *
599
+ * Shuts down a socket for sending and/or receiving.
600
+ *
601
+ * @param fd [Integer] file descriptor
602
+ * @param how [Integer] how the socket should be shutdown
603
+ * @return [0] success
604
+ */
334
605
  VALUE UM_shutdown(VALUE self, VALUE fd, VALUE how) {
335
606
  struct um *machine = um_get_machine(self);
336
607
  return um_shutdown(machine, NUM2INT(fd), NUM2INT(how));
337
608
  }
338
609
 
610
+ /* call-seq:
611
+ * machine.shutdown_async(fd, how) -> 0
612
+ *
613
+ * Shuts down a socket for sending and/or receiving. This method may be used to
614
+ * improve performance in situations where the application does not care about
615
+ * whether the operation succeeds or not.
616
+ *
617
+ * @param fd [Integer] file descriptor
618
+ * @param how [Integer] how the socket should be shutdown
619
+ * @return [0] success
620
+ */
339
621
  VALUE UM_shutdown_async(VALUE self, VALUE fd, VALUE how) {
340
622
  struct um *machine = um_get_machine(self);
341
623
  return um_shutdown_async(machine, NUM2INT(fd), NUM2INT(how));
342
624
  }
343
625
 
626
+ /* call-seq:
627
+ * machine.connect(fd, host, port) -> 0
628
+ *
629
+ * Connects the given socket to the given host and port.
630
+ *
631
+ * @param fd [Integer] file descriptor
632
+ * @param host [String] hostname or IP address
633
+ * @param port [Integer] port number
634
+ * @return [0] success
635
+ */
344
636
  VALUE UM_connect(VALUE self, VALUE fd, VALUE host, VALUE port) {
345
637
  struct um *machine = um_get_machine(self);
346
638
 
@@ -353,12 +645,37 @@ VALUE UM_connect(VALUE self, VALUE fd, VALUE host, VALUE port) {
353
645
  return um_connect(machine, NUM2INT(fd), (struct sockaddr *)&addr, sizeof(addr));
354
646
  }
355
647
 
648
+ /* call-seq:
649
+ * machine.send(fd, buffer, len, flags) -> bytes_sent
650
+ *
651
+ * Sends data on the given socket. This method is not guaranteed to send all of
652
+ * the data in the buffer, unless `UM::MSG_WAITALL` is specified in the flags
653
+ * mask.
654
+ *
655
+ * @param fd [Integer] file descriptor
656
+ * @param buffer [String, IO::Buffer] buffer
657
+ * @param len [Integer] number of bytes to send
658
+ * @param flags [Integer] flags mask
659
+ * @return [Integer] number of bytes sent
660
+ */
356
661
  VALUE UM_send(VALUE self, VALUE fd, VALUE buffer, VALUE len, VALUE flags) {
357
662
  struct um *machine = um_get_machine(self);
358
663
  return um_send(machine, NUM2INT(fd), buffer, NUM2INT(len), NUM2INT(flags));
359
664
  }
360
665
 
361
666
  #ifdef HAVE_IO_URING_SEND_VECTORIZED
667
+
668
+ /* call-seq:
669
+ * machine.sendv(fd, *buffers) -> bytes_sent
670
+ *
671
+ * Sends data on the given socket from the given buffers. This method is only
672
+ * available on Linux kernel >= 6.17. This method is guaranteed to send
673
+ *
674
+ * @overload sendv(fd, *buffers)
675
+ * @param fd [Integer] file descriptor
676
+ * @param *buffers [Array<String, IO::Buffer>] buffers
677
+ * @return [Integer] number of bytes sent
678
+ */
362
679
  VALUE UM_sendv(int argc, VALUE *argv, VALUE self) {
363
680
  struct um *machine = um_get_machine(self);
364
681
  if (argc < 1)
@@ -368,8 +685,22 @@ VALUE UM_sendv(int argc, VALUE *argv, VALUE self) {
368
685
 
369
686
  return um_sendv(machine, fd, argc - 1, argv + 1);
370
687
  }
688
+
371
689
  #endif
372
690
 
691
+ /* call-seq:
692
+ * machine.send_bundle(fd, bgid, *buffers) -> bytes_sent
693
+ *
694
+ * Sends data on the given socket from the given buffers using a registered
695
+ * buffer group. The buffer group should have been previously registered using
696
+ * `#setup_buffer_ring`.
697
+ *
698
+ * @overload send_bundle(fd, bgid, *buffers)
699
+ * @param fd [Integer] file descriptor
700
+ * @param bgid [Integer] buffer group id
701
+ * @param *buffers [Array<String, IO::Buffer>] buffers
702
+ * @return [Integer] number of bytes sent
703
+ */
373
704
  VALUE UM_send_bundle(int argc, VALUE *argv, VALUE self) {
374
705
  struct um *machine = um_get_machine(self);
375
706
  VALUE fd;
@@ -386,16 +717,49 @@ VALUE UM_send_bundle(int argc, VALUE *argv, VALUE self) {
386
717
  return um_send_bundle(machine, NUM2INT(fd), NUM2INT(bgid), strings);
387
718
  }
388
719
 
720
+ /* call-seq:
721
+ * machine.recv(fd, buffer, maxlen, flags) -> bytes_received
722
+ *
723
+ * Receives data from the given socket.
724
+ *
725
+ * @param fd [Integer] file descriptor
726
+ * @param buffer [String, IO::Buffer] buffer
727
+ * @param maxlen [Integer] maximum number of bytes to receive
728
+ * @param flags [Integer] flags mask
729
+ * @return [Integer] number of bytes received
730
+ */
389
731
  VALUE UM_recv(VALUE self, VALUE fd, VALUE buffer, VALUE maxlen, VALUE flags) {
390
732
  struct um *machine = um_get_machine(self);
391
733
  return um_recv(machine, NUM2INT(fd), buffer, NUM2INT(maxlen), NUM2INT(flags));
392
734
  }
393
735
 
736
+ /* call-seq:
737
+ * machine.recv_each(fd, bgid, flags) { |data| ... }
738
+ *
739
+ * Repeatedlty receives data from the given socket in an infinite loop using the
740
+ * given buffer group id. The buffer group should have been previously setup
741
+ * using `#setup_buffer_ring`.
742
+ *
743
+ * @param fd [Integer] file descriptor
744
+ * @param bgid [Integer] buffer group id
745
+ * @param flags [Integer] flags mask
746
+ * @return [void]
747
+ */
394
748
  VALUE UM_recv_each(VALUE self, VALUE fd, VALUE bgid, VALUE flags) {
395
749
  struct um *machine = um_get_machine(self);
396
750
  return um_recv_each(machine, NUM2INT(fd), NUM2INT(bgid), NUM2INT(flags));
397
751
  }
398
752
 
753
+ /* call-seq:
754
+ * machine.bind(fd, host, port) -> 0
755
+ *
756
+ * Binds the given socket to the given host and port.
757
+ *
758
+ * @param fd [Integer] file descriptor
759
+ * @param host [String] hostname or IP address
760
+ * @param port [Integer] port number
761
+ * @return [0] success
762
+ */
399
763
  VALUE UM_bind(VALUE self, VALUE fd, VALUE host, VALUE port) {
400
764
  struct sockaddr_in addr;
401
765
  memset(&addr, 0, sizeof(addr));
@@ -414,6 +778,15 @@ VALUE UM_bind(VALUE self, VALUE fd, VALUE host, VALUE port) {
414
778
  #endif
415
779
  }
416
780
 
781
+ /* call-seq:
782
+ * machine.listen(fd, backlog) -> 0
783
+ *
784
+ * Starts listening for incoming connections on the given socket.
785
+ *
786
+ * @param fd [Integer] file descriptor
787
+ * @param backlog [String] pending connection queue length
788
+ * @return [0] success
789
+ */
417
790
  VALUE UM_listen(VALUE self, VALUE fd, VALUE backlog) {
418
791
  #ifdef HAVE_IO_URING_PREP_LISTEN
419
792
  struct um *machine = um_get_machine(self);
@@ -437,40 +810,104 @@ static inline int numeric_value(VALUE value) {
437
810
  }
438
811
  }
439
812
 
813
+ /* call-seq:
814
+ * machine.getsockopt(fd, level, opt) -> value
815
+ *
816
+ * Returns the value of a socket option.
817
+ *
818
+ * @param fd [Integer] file descriptor
819
+ * @param level [Integer] level
820
+ * @param opt [Integer] level
821
+ * @return [Integer] option value
822
+ */
440
823
  VALUE UM_getsockopt(VALUE self, VALUE fd, VALUE level, VALUE opt) {
441
824
  struct um *machine = um_get_machine(self);
442
825
  return um_getsockopt(machine, NUM2INT(fd), NUM2INT(level), NUM2INT(opt));
443
826
  }
444
827
 
828
+ /* call-seq:
829
+ * machine.getsockopt(fd, level, opt, value) -> 0
830
+ *
831
+ * Sets the value of a socket option.
832
+ *
833
+ * @param fd [Integer] file descriptor
834
+ * @param level [Integer] level
835
+ * @param opt [Integer] level
836
+ * @param value [Integer] option value
837
+ * @return [0] success
838
+ */
445
839
  VALUE UM_setsockopt(VALUE self, VALUE fd, VALUE level, VALUE opt, VALUE value) {
446
840
  struct um *machine = um_get_machine(self);
447
841
  return um_setsockopt(machine, NUM2INT(fd), NUM2INT(level), NUM2INT(opt), numeric_value(value));
448
842
  }
449
843
 
844
+ /* call-seq:
845
+ * machine.synchronize(mutex) { }
846
+ *
847
+ * Synchronizes access to the given mutex. The mutex is locked, the given block
848
+ * is executed and finally the mutex is unlocked.
849
+ *
850
+ * @param mutex [UM::Mutex] mutex
851
+ * @return [any] block return value
852
+ */
450
853
  VALUE UM_mutex_synchronize(VALUE self, VALUE mutex) {
451
854
  struct um *machine = um_get_machine(self);
452
855
  struct um_mutex *mutex_data = Mutex_data(mutex);
453
856
  return um_mutex_synchronize(machine, mutex_data);
454
857
  }
455
858
 
859
+ /* call-seq:
860
+ * machine.push(queue, value) -> queue
861
+ *
862
+ * Pushes a value to the tail of the given queue.
863
+ *
864
+ * @param queue [UM::Queue] queue
865
+ * @param value [any] value
866
+ * @return [UM::Queue] queue
867
+ */
456
868
  VALUE UM_queue_push(VALUE self, VALUE queue, VALUE value) {
457
869
  struct um *machine = um_get_machine(self);
458
870
  struct um_queue *que = Queue_data(queue);
459
871
  return um_queue_push(machine, que, value);
460
872
  }
461
873
 
874
+ /* call-seq:
875
+ * machine.pop(queue) -> value
876
+ *
877
+ * removes a value from the tail of the given queue.
878
+ *
879
+ * @param queue [UM::Queue] queue
880
+ * @return [any] value
881
+ */
462
882
  VALUE UM_queue_pop(VALUE self, VALUE queue) {
463
883
  struct um *machine = um_get_machine(self);
464
884
  struct um_queue *que = Queue_data(queue);
465
885
  return um_queue_pop(machine, que);
466
886
  }
467
887
 
888
+ /* call-seq:
889
+ * machine.unshift(queue, value) -> queue
890
+ *
891
+ * Pushes a value to the head of the given queue.
892
+ *
893
+ * @param queue [UM::Queue] queue
894
+ * @param value [any] value
895
+ * @return [UM::Queue] queue
896
+ */
468
897
  VALUE UM_queue_unshift(VALUE self, VALUE queue, VALUE value) {
469
898
  struct um *machine = um_get_machine(self);
470
899
  struct um_queue *que = Queue_data(queue);
471
900
  return um_queue_unshift(machine, que, value);
472
901
  }
473
902
 
903
+ /* call-seq:
904
+ * machine.pop(queue) -> value
905
+ *
906
+ * removes a value from the head of the given queue.
907
+ *
908
+ * @param queue [UM::Queue] queue
909
+ * @return [any] value
910
+ */
474
911
  VALUE UM_queue_shift(VALUE self, VALUE queue) {
475
912
  struct um *machine = um_get_machine(self);
476
913
  struct um_queue *que = Queue_data(queue);
@@ -488,6 +925,18 @@ VALUE UM_open_complete(VALUE arg) {
488
925
  return ctx->self;
489
926
  }
490
927
 
928
+ /* call-seq:
929
+ * machine.open(pathname, flags) -> fd
930
+ * machine.open(pathname, flags) { |fd| ... }
931
+ *
932
+ * Opens a file using the given pathname and flags. If a block is given, the
933
+ * file descriptor is passed to the block, and the file is automatically closed
934
+ * when the block returns.
935
+ *
936
+ * @param pathname [String] file path
937
+ * @param flags [Integer] flags mask
938
+ * @return [Integer] fd
939
+ */
491
940
  VALUE UM_open(VALUE self, VALUE pathname, VALUE flags) {
492
941
  struct um *machine = um_get_machine(self);
493
942
  // TODO: take optional perm (mode) arg
@@ -500,33 +949,136 @@ VALUE UM_open(VALUE self, VALUE pathname, VALUE flags) {
500
949
  return fd;
501
950
  }
502
951
 
952
+ /* call-seq:
953
+ * machine.poll(fd, mask) -> fd
954
+ *
955
+ * Waits for readiness of the given file descriptor according to the given event
956
+ * mask.
957
+ *
958
+ * @param fd [Integer] file descriptor
959
+ * @param mask [Integer] events mask
960
+ * @return [Integer] fd
961
+ */
503
962
  VALUE UM_poll(VALUE self, VALUE fd, VALUE mask) {
504
963
  struct um *machine = um_get_machine(self);
505
964
  return um_poll(machine, NUM2INT(fd), NUM2UINT(mask));
506
965
  }
507
966
 
508
- VALUE UM_select(VALUE self, VALUE rfds, VALUE wfds, VALUE efds) {
967
+ /* call-seq:
968
+ * machine.select(read_fds, write_fds, except_fds) -> [read_ready_fds, write_read_fds, except_ready_fds]
969
+ *
970
+ * Waits for readyness of at least one fd for read, write or exception condition
971
+ * from the given fds. This method provides a similar interface to `IO#select`.
972
+ *
973
+ * @param read_fds [Array<Integer>] file descriptors for reading
974
+ * @param write_fds [Array<Integer>] file descriptors for writing
975
+ * @param except_fds [Array<Integer>] file descriptors for exception
976
+ * @return [Array<Array<Integer>>] read-ready, write-ready, and exception-ready fds
977
+ */
978
+ VALUE UM_select(VALUE self, VALUE read_fds, VALUE write_fds, VALUE except_fds) {
509
979
  struct um *machine = um_get_machine(self);
510
- return um_select(machine, rfds, wfds, efds);
511
- }
512
-
980
+ return um_select(machine, read_fds, write_fds, except_fds);
981
+ }
982
+
983
+ /* call-seq:
984
+ * machine.waitid(idtype, id, options) -> [pid, status, code)]
985
+ *
986
+ * Waits for a process to change state. The process to wait for can be specified
987
+ * as a pid or as a pidfd, according to the given `idtype` and `id`.
988
+ *
989
+ * @param idtype [Integer] id type
990
+ * @param id [Integer] id
991
+ * @param options [Integer] options
992
+ * @return [Array<Integer>] pid status
993
+ */
513
994
  VALUE UM_waitid(VALUE self, VALUE idtype, VALUE id, VALUE options) {
514
995
  struct um *machine = um_get_machine(self);
515
996
  return um_waitid(machine, NUM2INT(idtype), NUM2INT(id), NUM2INT(options));
516
997
  }
517
998
 
518
999
  #ifdef HAVE_RB_PROCESS_STATUS_NEW
1000
+
1001
+ /* :nodoc:
1002
+ *
1003
+ * This method depends on the availability of `rb_process_status_new`. See:
1004
+ * https://github.com/ruby/ruby/pull/15213
1005
+ *
1006
+ */
519
1007
  VALUE UM_waitid_status(VALUE self, VALUE idtype, VALUE id, VALUE options) {
520
1008
  struct um *machine = um_get_machine(self);
521
1009
  return um_waitid_status(machine, NUM2INT(idtype), NUM2INT(id), NUM2INT(options));
522
1010
  }
1011
+
523
1012
  #endif
524
1013
 
1014
+ /* call-seq:
1015
+ * machine.prep_timeout(interval) -> timeout
1016
+ *
1017
+ * Prepares an asynchronous timeout instance.
1018
+ *
1019
+ * @param interval [Integer] timeout interval in seconds
1020
+ * @return [UM::AsyncOp] async operation instance
1021
+ */
525
1022
  VALUE UM_prep_timeout(VALUE self, VALUE interval) {
526
1023
  struct um *machine = um_get_machine(self);
527
1024
  return um_prep_timeout(machine, NUM2DBL(interval));
528
1025
  }
529
1026
 
1027
+ /* call-seq:
1028
+ * machine.ssl_set_bio(ssl) -> machine
1029
+ *
1030
+ * Sets up the given ssl socket to use the machine for sending and receiving.
1031
+ *
1032
+ * @param ssl [OpenSSL::SSL::SSLSocket] ssl socket
1033
+ * @return [UringMachine] machine
1034
+ */
1035
+ VALUE UM_ssl_set_bio(VALUE self, VALUE ssl) {
1036
+ struct um *machine = um_get_machine(self);
1037
+ um_ssl_set_bio(machine, ssl);
1038
+ return self;
1039
+ }
1040
+
1041
+ /* call-seq:
1042
+ * machine.ssl_read(ssl, buf, maxlen) -> bytes_read
1043
+ *
1044
+ * Reads from the given SSL socket. This method should be used after first
1045
+ * having called `#ssl_set_bio`.
1046
+ *
1047
+ * @param ssl [OpenSSL::SSL::SSLSocket] ssl socket
1048
+ * @param buf [String, IO::Buffer] buffer
1049
+ * @param maxlen [Integer] maximum number of bytes to read
1050
+ * @return [Integer] number of bytes read
1051
+ */
1052
+ VALUE UM_ssl_read(VALUE self, VALUE ssl, VALUE buf, VALUE maxlen) {
1053
+ struct um *machine = um_get_machine(self);
1054
+ int ret = um_ssl_read(machine, ssl, buf, NUM2INT(maxlen));
1055
+ return INT2NUM(ret);
1056
+ }
1057
+
1058
+ /* call-seq:
1059
+ * machine.ssl_write(ssl, buf, len) -> bytes_written
1060
+ *
1061
+ * Writes to the given SSL socket. This method should be used after first
1062
+ * having called `#ssl_set_bio`.
1063
+ *
1064
+ * @param ssl [OpenSSL::SSL::SSLSocket] ssl socket
1065
+ * @param buf [String, IO::Buffer] buffer
1066
+ * @param len [Integer] number of bytes to write
1067
+ * @return [Integer] number of bytes written
1068
+ */
1069
+ VALUE UM_ssl_write(VALUE self, VALUE ssl, VALUE buf, VALUE len) {
1070
+ struct um *machine = um_get_machine(self);
1071
+ int ret = um_ssl_write(machine, ssl, buf, NUM2INT(len));
1072
+ return INT2NUM(ret);
1073
+ }
1074
+
1075
+ /* call-seq:
1076
+ * UringMachine.pipe -> [read_fd, write_fd]
1077
+ *
1078
+ * Creates a pipe, returning the file descriptors for the read and write ends.
1079
+ *
1080
+ * @return [Array<Integer>] array containing the read and write file descriptors
1081
+ */
530
1082
  VALUE UM_pipe(VALUE self) {
531
1083
  int fds[2];
532
1084
  int ret = pipe(fds);
@@ -538,6 +1090,16 @@ VALUE UM_pipe(VALUE self) {
538
1090
  return rb_ary_new_from_args(2, INT2NUM(fds[0]), INT2NUM(fds[1]));
539
1091
  }
540
1092
 
1093
+ /* call-seq:
1094
+ * UringMachine.socketpair(domain, type, protocol) -> [s1_fd, s2_fd]
1095
+ *
1096
+ * Creates a pair of connected sockets, returning the two file descriptors.
1097
+ *
1098
+ * @param domain [Integer] domain
1099
+ * @param type [Integer] type
1100
+ * @param protocol [Integer] protocol
1101
+ * @return [Array<Integer>] array containing the two file descriptors
1102
+ */
541
1103
  VALUE UM_socketpair(VALUE self, VALUE domain, VALUE type, VALUE protocol) {
542
1104
  int fds[2];
543
1105
  int ret = socketpair(NUM2INT(domain), NUM2INT(type), NUM2INT(protocol), fds);
@@ -549,6 +1111,15 @@ VALUE UM_socketpair(VALUE self, VALUE domain, VALUE type, VALUE protocol) {
549
1111
  return rb_ary_new_from_args(2, INT2NUM(fds[0]), INT2NUM(fds[1]));
550
1112
  }
551
1113
 
1114
+ /* call-seq:
1115
+ * UringMachine.pidfd_open(pid) -> fd
1116
+ *
1117
+ * Creates a file descriptor representing the given process pid. The file
1118
+ * descriptor can then be used with methods such as `#waitid` or `.pidfd_open`.
1119
+ *
1120
+ * @param pid [Integer] process pid
1121
+ * @return [Integer] file descriptor
1122
+ */
552
1123
  VALUE UM_pidfd_open(VALUE self, VALUE pid) {
553
1124
  int fd = syscall(SYS_pidfd_open, NUM2INT(pid), 0);
554
1125
  if (fd == -1) {
@@ -559,6 +1130,15 @@ VALUE UM_pidfd_open(VALUE self, VALUE pid) {
559
1130
  return INT2NUM(fd);
560
1131
  }
561
1132
 
1133
+ /* call-seq:
1134
+ * UringMachine.pidfd_send_signal(fd, sig) -> fd
1135
+ *
1136
+ * Sends a signal to a pidfd.
1137
+ *
1138
+ * @param fd [Integer] pidfd
1139
+ * @param sig [Integer] signal
1140
+ * @return [Integer] pidfd
1141
+ */
562
1142
  VALUE UM_pidfd_send_signal(VALUE self, VALUE fd, VALUE sig) {
563
1143
  int ret = syscall(
564
1144
  SYS_pidfd_send_signal, NUM2INT(fd), NUM2INT(sig), NULL, 0
@@ -571,6 +1151,8 @@ VALUE UM_pidfd_send_signal(VALUE self, VALUE fd, VALUE sig) {
571
1151
  return fd;
572
1152
  }
573
1153
 
1154
+ /* :nodoc:
1155
+ */
574
1156
  VALUE UM_io_nonblock_p(VALUE self, VALUE io) {
575
1157
  int fd = rb_io_descriptor(io);
576
1158
  int oflags = fcntl(fd, F_GETFL);
@@ -579,6 +1161,8 @@ VALUE UM_io_nonblock_p(VALUE self, VALUE io) {
579
1161
  return (oflags & O_NONBLOCK) ? Qtrue : Qfalse;
580
1162
  }
581
1163
 
1164
+ /* :nodoc:
1165
+ */
582
1166
  VALUE UM_io_set_nonblock(VALUE self, VALUE io, VALUE nonblock) {
583
1167
  int fd = rb_io_descriptor(io);
584
1168
  int oflags = fcntl(fd, F_GETFL);
@@ -599,15 +1183,104 @@ VALUE UM_io_set_nonblock(VALUE self, VALUE io, VALUE nonblock) {
599
1183
  return nonblock;
600
1184
  }
601
1185
 
1186
+ /* call-seq:
1187
+ * UringMachine.kernel_version -> version
1188
+ *
1189
+ * Returns the kernel version.
1190
+ *
1191
+ * @return [Integer] kernel version
1192
+ */
602
1193
  VALUE UM_kernel_version(VALUE self) {
603
1194
  return INT2NUM(UM_KERNEL_VERSION);
604
1195
  }
605
1196
 
1197
+ /* call-seq:
1198
+ * UringMachine.debug(str)
1199
+ *
1200
+ * Prints the given string to STDERR.
1201
+ *
1202
+ * @param str [String] debug message
1203
+ * @return [void]
1204
+ */
606
1205
  VALUE UM_debug(VALUE self, VALUE str) {
607
1206
  fprintf(stderr, "%s\n", StringValueCStr(str));
608
1207
  return Qnil;
609
1208
  }
610
1209
 
1210
+ /* call-seq:
1211
+ * UringMachine.inotify_init -> fd
1212
+ *
1213
+ * Creates an inotify file descriptor.
1214
+ *
1215
+ * @return [Integer] file descriptor
1216
+ */
1217
+ VALUE UM_inotify_init(VALUE self) {
1218
+ int fd = inotify_init();
1219
+ if (fd == -1) {
1220
+ int e = errno;
1221
+ rb_syserr_fail(e, strerror(e));
1222
+ }
1223
+ return INT2NUM(fd);
1224
+ }
1225
+
1226
+ /* call-seq:
1227
+ * UringMachine.inotify_add_watch(fd, path, mask) -> wd
1228
+ *
1229
+ * Adds a watch on the given inotify file descriptor.
1230
+ *
1231
+ * @param fd [Integer] inotify file descriptor
1232
+ * @param path [String] file/directory path
1233
+ * @param mask [Integer] inotify event mask
1234
+ * @return [Integer] watch descriptor
1235
+ */
1236
+ VALUE UM_inotify_add_watch(VALUE self, VALUE fd, VALUE path, VALUE mask) {
1237
+ int ret = inotify_add_watch(NUM2INT(fd), StringValueCStr(path), NUM2UINT(mask));
1238
+ if (ret == -1) {
1239
+ int e = errno;
1240
+ rb_syserr_fail(e, strerror(e));
1241
+ }
1242
+ return INT2NUM(ret);
1243
+ }
1244
+
1245
+ static inline VALUE inotify_get_events(char *buf, size_t len) {
1246
+ VALUE array = rb_ary_new();
1247
+ while (len > 0) {
1248
+ struct inotify_event *evt = (struct inotify_event *)buf;
1249
+ size_t evt_len = sizeof(struct inotify_event) + evt->len;
1250
+
1251
+ VALUE hash = rb_hash_new();
1252
+ rb_hash_aset(hash, SYM_wd, INT2NUM(evt->wd));
1253
+ rb_hash_aset(hash, SYM_mask, UINT2NUM(evt->mask));
1254
+ rb_hash_aset(hash, SYM_name, rb_str_new_cstr(evt->name));
1255
+ rb_ary_push(array, hash);
1256
+ RB_GC_GUARD(hash);
1257
+
1258
+ buf += evt_len;
1259
+ len -= evt_len;
1260
+ }
1261
+ RB_GC_GUARD(array);
1262
+ return array;
1263
+ }
1264
+
1265
+ /* call-seq:
1266
+ * machine.inotify_get_events(fd) -> events
1267
+ *
1268
+ * Waits for and returns one or more events on the given inotify file
1269
+ * descriptor. Each event is returned as a hash containing the watch descriptor,
1270
+ * the file name, and the event mask.
1271
+ *
1272
+ * @param fd [Integer] inotify file descriptor
1273
+ * @return [Array<Hash>] array of one or more events
1274
+ */
1275
+ VALUE UM_inotify_get_events(VALUE self, VALUE fd) {
1276
+ struct um *machine = um_get_machine(self);
1277
+
1278
+ char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event))));
1279
+
1280
+ size_t ret = um_read_raw(machine, NUM2INT(fd), buf, sizeof(buf));
1281
+ return inotify_get_events(buf, ret);
1282
+ }
1283
+
611
1284
  void Init_UM(void) {
612
1285
  rb_ext_ractor_safe(true);
613
1286
 
@@ -639,6 +1312,9 @@ void Init_UM(void) {
639
1312
  rb_define_singleton_method(cUM, "kernel_version", UM_kernel_version, 0);
640
1313
  rb_define_singleton_method(cUM, "debug", UM_debug, 1);
641
1314
 
1315
+ rb_define_singleton_method(cUM, "inotify_init", UM_inotify_init, 0);
1316
+ rb_define_singleton_method(cUM, "inotify_add_watch", UM_inotify_add_watch, 3);
1317
+
642
1318
  rb_define_method(cUM, "schedule", UM_schedule, 2);
643
1319
  rb_define_method(cUM, "snooze", UM_snooze, 0);
644
1320
  rb_define_method(cUM, "timeout", UM_timeout, 2);
@@ -697,6 +1373,12 @@ void Init_UM(void) {
697
1373
  rb_define_method(cUM, "synchronize", UM_mutex_synchronize, 1);
698
1374
  rb_define_method(cUM, "unshift", UM_queue_unshift, 2);
699
1375
 
1376
+ rb_define_method(cUM, "ssl_set_bio", UM_ssl_set_bio, 1);
1377
+ rb_define_method(cUM, "ssl_read", UM_ssl_read, 3);
1378
+ rb_define_method(cUM, "ssl_write", UM_ssl_write, 3);
1379
+
1380
+ rb_define_method(cUM, "inotify_get_events", UM_inotify_get_events, 1);
1381
+
700
1382
  eUMError = rb_define_class_under(cUM, "Error", rb_eStandardError);
701
1383
 
702
1384
  um_define_net_constants(cUM);
@@ -713,5 +1395,9 @@ void Init_UM(void) {
713
1395
  SYM_time_total_cpu = ID2SYM(rb_intern("time_total_cpu"));
714
1396
  SYM_time_total_wait = ID2SYM(rb_intern("time_total_wait"));
715
1397
 
1398
+ SYM_wd = ID2SYM(rb_intern("wd"));
1399
+ SYM_mask = ID2SYM(rb_intern("mask"));
1400
+ SYM_name = ID2SYM(rb_intern("name"));
1401
+
716
1402
  id_fileno = rb_intern_const("fileno");
717
1403
  }