uringmachine 0.8.2 → 0.11

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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/TODO.md +0 -1
  4. data/examples/bm_side_running.rb +83 -0
  5. data/examples/bm_sqlite.rb +1 -1
  6. data/ext/um/um.c +66 -4
  7. data/ext/um/um.h +36 -0
  8. data/ext/um/um_class.c +6 -0
  9. data/ext/um/um_const.c +36 -0
  10. data/ext/um/um_ext.c +2 -0
  11. data/ext/um/um_stream.c +344 -0
  12. data/ext/um/um_stream_class.c +140 -0
  13. data/ext/um/um_utils.c +4 -0
  14. data/lib/uringmachine/actor.rb +1 -1
  15. data/lib/uringmachine/version.rb +1 -1
  16. data/lib/uringmachine.rb +35 -17
  17. data/test/test_fiber.rb +23 -3
  18. data/test/test_stream.rb +133 -0
  19. data/test/test_um.rb +109 -2
  20. data/uringmachine.gemspec +0 -2
  21. data/vendor/liburing/.github/workflows/{build.yml → ci.yml} +107 -42
  22. data/vendor/liburing/.gitignore +1 -0
  23. data/vendor/liburing/CHANGELOG +10 -0
  24. data/vendor/liburing/README +5 -0
  25. data/vendor/liburing/configure +1 -1
  26. data/vendor/liburing/examples/Makefile +1 -0
  27. data/vendor/liburing/examples/helpers.c +25 -0
  28. data/vendor/liburing/examples/helpers.h +13 -0
  29. data/vendor/liburing/examples/io_uring-test.c +3 -0
  30. data/vendor/liburing/examples/proxy.c +1 -1
  31. data/vendor/liburing/examples/reg-wait.c +41 -6
  32. data/vendor/liburing/examples/send-zerocopy.c +79 -32
  33. data/vendor/liburing/examples/zcrx.c +436 -0
  34. data/vendor/liburing/liburing.spec +1 -1
  35. data/vendor/liburing/src/Makefile +0 -1
  36. data/vendor/liburing/src/arch/generic/syscall.h +2 -2
  37. data/vendor/liburing/src/arch/syscall-defs.h +2 -2
  38. data/vendor/liburing/src/include/liburing/io_uring.h +101 -17
  39. data/vendor/liburing/src/include/liburing.h +179 -59
  40. data/vendor/liburing/src/int_flags.h +4 -1
  41. data/vendor/liburing/src/liburing-ffi.map +14 -2
  42. data/vendor/liburing/src/liburing.map +9 -2
  43. data/vendor/liburing/src/queue.c +35 -30
  44. data/vendor/liburing/src/register.c +46 -15
  45. data/vendor/liburing/src/sanitize.c +6 -9
  46. data/vendor/liburing/src/setup.c +37 -71
  47. data/vendor/liburing/src/syscall.c +2 -2
  48. data/vendor/liburing/test/232c93d07b74.c +1 -0
  49. data/vendor/liburing/test/Makefile +9 -0
  50. data/vendor/liburing/test/accept-test.c +1 -0
  51. data/vendor/liburing/test/cmd-discard.c +16 -8
  52. data/vendor/liburing/test/connect.c +11 -7
  53. data/vendor/liburing/test/epwait.c +420 -0
  54. data/vendor/liburing/test/eventfd-ring.c +30 -5
  55. data/vendor/liburing/test/fallocate.c +1 -1
  56. data/vendor/liburing/test/fixed-hugepage.c +10 -7
  57. data/vendor/liburing/test/fixed-seg.c +187 -0
  58. data/vendor/liburing/test/helpers.c +121 -0
  59. data/vendor/liburing/test/helpers.h +13 -0
  60. data/vendor/liburing/test/init-mem.c +2 -0
  61. data/vendor/liburing/test/io_uring_passthrough.c +78 -62
  62. data/vendor/liburing/test/iopoll-overflow.c +5 -4
  63. data/vendor/liburing/test/iopoll.c +20 -10
  64. data/vendor/liburing/test/iowait.c +141 -0
  65. data/vendor/liburing/test/nvme.h +2 -0
  66. data/vendor/liburing/test/pipe-bug.c +11 -5
  67. data/vendor/liburing/test/pipe-eof.c +11 -1
  68. data/vendor/liburing/test/read-inc-file.c +150 -0
  69. data/vendor/liburing/test/read-write.c +21 -14
  70. data/vendor/liburing/test/recv-bundle-short-ooo.c +435 -0
  71. data/vendor/liburing/test/recv-multishot.c +2 -2
  72. data/vendor/liburing/test/reg-wait.c +449 -120
  73. data/vendor/liburing/test/regbuf-clone.c +53 -0
  74. data/vendor/liburing/test/resize-rings.c +25 -2
  75. data/vendor/liburing/test/rsrc_tags.c +67 -14
  76. data/vendor/liburing/test/send-zerocopy.c +52 -130
  77. data/vendor/liburing/test/sendmsg_iov_clean.c +216 -0
  78. data/vendor/liburing/test/socket-nb.c +158 -0
  79. data/vendor/liburing/test/sqwait.c +9 -11
  80. data/vendor/liburing/test/timeout.c +198 -0
  81. data/vendor/liburing/test/vec-regbuf.c +609 -0
  82. data/vendor/liburing/test/wait-timeout.c +1 -1
  83. data/vendor/liburing/test/wq-aff.c +5 -1
  84. data/vendor/liburing/test/zcrx.c +928 -0
  85. metadata +16 -32
  86. data/vendor/liburing/.github/workflows/codespell.yml +0 -25
  87. data/vendor/liburing/.github/workflows/shellcheck.yml +0 -20
@@ -0,0 +1,158 @@
1
+ /* SPDX-License-Identifier: MIT */
2
+ /*
3
+ * Check that recv on an empty socket will bubble back -EAGAIN if
4
+ * MSG_DONTWAIT is set, regardless of whether or not O_NONBLOCK is set
5
+ * on the socket itself.
6
+ */
7
+ #include <stdio.h>
8
+ #include <stdlib.h>
9
+ #include <stdint.h>
10
+ #include <assert.h>
11
+
12
+ #include <errno.h>
13
+ #include <fcntl.h>
14
+ #include <unistd.h>
15
+ #include <sys/socket.h>
16
+ #include <sys/un.h>
17
+ #include <netinet/tcp.h>
18
+ #include <netinet/in.h>
19
+ #include <arpa/inet.h>
20
+
21
+ #include "liburing.h"
22
+ #include "helpers.h"
23
+
24
+ static int test(int o_nonblock, int msg_dontwait)
25
+ {
26
+ int p_fd[2], ret, flags, recv_s0, val;
27
+ struct io_uring_sqe *sqe;
28
+ struct io_uring_cqe *cqe;
29
+ struct sockaddr_in addr;
30
+ struct io_uring ring;
31
+ char recv_buff[128];
32
+
33
+ recv_s0 = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
34
+
35
+ val = 1;
36
+ ret = setsockopt(recv_s0, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
37
+ assert(ret != -1);
38
+ ret = setsockopt(recv_s0, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
39
+ assert(ret != -1);
40
+
41
+ addr.sin_family = AF_INET;
42
+ addr.sin_addr.s_addr = inet_addr("127.0.0.1");
43
+ ret = t_bind_ephemeral_port(recv_s0, &addr);
44
+ assert(!ret);
45
+ ret = listen(recv_s0, 128);
46
+ assert(ret != -1);
47
+
48
+ p_fd[1] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
49
+
50
+ val = 1;
51
+ ret = setsockopt(p_fd[1], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
52
+ assert(ret != -1);
53
+
54
+ flags = fcntl(p_fd[1], F_GETFL, 0);
55
+ assert(flags != -1);
56
+
57
+ flags |= O_NONBLOCK;
58
+ ret = fcntl(p_fd[1], F_SETFL, flags);
59
+ assert(ret != -1);
60
+
61
+ ret = connect(p_fd[1], (struct sockaddr *) &addr, sizeof(addr));
62
+ assert(ret == -1);
63
+
64
+ p_fd[0] = accept(recv_s0, NULL, NULL);
65
+ assert(p_fd[0] != -1);
66
+
67
+ if (o_nonblock) {
68
+ flags = fcntl(p_fd[0], F_GETFL, 0);
69
+ assert(flags != -1);
70
+
71
+ flags |= O_NONBLOCK;
72
+ ret = fcntl(p_fd[0], F_SETFL, flags);
73
+ assert(ret != -1);
74
+ }
75
+
76
+ while (1) {
77
+ int32_t code;
78
+ socklen_t code_len = sizeof(code);
79
+
80
+ ret = getsockopt(p_fd[1], SOL_SOCKET, SO_ERROR, &code, &code_len);
81
+ assert(ret != -1);
82
+
83
+ if (!code)
84
+ break;
85
+ }
86
+
87
+ ret = io_uring_queue_init(32, &ring, 0);
88
+ assert(ret >= 0);
89
+
90
+ flags = msg_dontwait ? MSG_DONTWAIT : 0;
91
+ sqe = io_uring_get_sqe(&ring);
92
+ io_uring_prep_recv(sqe, p_fd[0], recv_buff, sizeof(recv_buff), flags);
93
+ sqe->user_data = 1;
94
+ io_uring_submit(&ring);
95
+
96
+ ret = io_uring_peek_cqe(&ring, &cqe);
97
+ if (ret) {
98
+ if (ret != -EAGAIN) {
99
+ fprintf(stderr, "bad peek: %d\n", ret);
100
+ goto err;
101
+ }
102
+ if (msg_dontwait) {
103
+ fprintf(stderr, "Got -EAGAIN without MSG_DONTWAIT\n");
104
+ goto err;
105
+ }
106
+ } else {
107
+ if (!msg_dontwait) {
108
+ fprintf(stderr, "Unexpected completion\n");
109
+ goto err;
110
+ }
111
+ }
112
+
113
+ io_uring_queue_exit(&ring);
114
+ close(p_fd[0]);
115
+ close(p_fd[1]);
116
+ close(recv_s0);
117
+ return T_EXIT_PASS;
118
+ err:
119
+ io_uring_queue_exit(&ring);
120
+ close(p_fd[0]);
121
+ close(p_fd[1]);
122
+ close(recv_s0);
123
+ return T_EXIT_FAIL;
124
+ }
125
+
126
+ int main(int argc, char *argv[])
127
+ {
128
+ int ret;
129
+
130
+ if (argc > 1)
131
+ return T_EXIT_SKIP;
132
+
133
+ ret = test(0, 0);
134
+ if (ret) {
135
+ fprintf(stderr, "test 0 0 failed\n");
136
+ return T_EXIT_FAIL;
137
+ }
138
+
139
+ ret = test(0, 1);
140
+ if (ret) {
141
+ fprintf(stderr, "test 0 1 failed\n");
142
+ return T_EXIT_FAIL;
143
+ }
144
+
145
+ ret = test(1, 0);
146
+ if (ret) {
147
+ fprintf(stderr, "test 1 0 failed\n");
148
+ return T_EXIT_FAIL;
149
+ }
150
+
151
+ ret = test(1, 1);
152
+ if (ret) {
153
+ fprintf(stderr, "test 1 1 failed\n");
154
+ return T_EXIT_FAIL;
155
+ }
156
+
157
+ return T_EXIT_PASS;
158
+ }
@@ -60,6 +60,12 @@ int main(int argc, char *argv[])
60
60
  }
61
61
 
62
62
  fret = T_EXIT_SKIP;
63
+ for (i = 0; i < INFLIGHT; i++) {
64
+ if (posix_memalign(&iovs[i].iov_base, 4096, 4096))
65
+ goto err;
66
+ iovs[i].iov_len = 4096;
67
+ }
68
+
63
69
  ret = io_uring_queue_init(8, &ring, IORING_SETUP_SQPOLL);
64
70
  if (ret < 0) {
65
71
  if (errno == EINVAL || errno == EPERM)
@@ -78,12 +84,6 @@ int main(int argc, char *argv[])
78
84
  goto err;
79
85
  }
80
86
 
81
- for (i = 0; i < INFLIGHT; i++) {
82
- if (posix_memalign(&iovs[i].iov_base, 4096, 4096))
83
- goto err;
84
- iovs[i].iov_len = 4096;
85
- }
86
-
87
87
  iov_off = off = 0;
88
88
  for (i = 0; i < NR_IOS; i++) {
89
89
  struct iovec *iov = &iovs[iov_off];
@@ -121,16 +121,14 @@ int main(int argc, char *argv[])
121
121
  }
122
122
  }
123
123
 
124
- if (fd != -1)
125
- close(fd);
126
- if (fname != argv[1])
127
- unlink(fname);
128
124
  io_uring_queue_exit(&ring);
129
- return T_EXIT_PASS;
125
+ fret = T_EXIT_PASS;
130
126
  err:
131
127
  if (fd != -1)
132
128
  close(fd);
133
129
  if (fname != argv[1])
134
130
  unlink(fname);
131
+ for (i = 0; i < INFLIGHT; i++)
132
+ free(iovs[i].iov_base);
135
133
  return fret;
136
134
  }
@@ -13,6 +13,7 @@
13
13
  #include <sys/wait.h>
14
14
  #include <sys/types.h>
15
15
  #include <sys/stat.h>
16
+ #include <sys/eventfd.h>
16
17
 
17
18
  #include "helpers.h"
18
19
  #include "liburing.h"
@@ -1062,6 +1063,153 @@ err:
1062
1063
  return 1;
1063
1064
  }
1064
1065
 
1066
+ static int test_update_multishot_timeouts(struct io_uring *ring, unsigned long ms)
1067
+ {
1068
+ struct io_uring_sqe *sqe;
1069
+ struct io_uring_cqe *cqe;
1070
+ struct __kernel_timespec ts, ts_upd;
1071
+ unsigned long long exp_ms, base_ms = 10000;
1072
+ struct timeval tv1, tv2;
1073
+ int ret, i, nr = 6;
1074
+ __u32 mode = 0;
1075
+
1076
+ if (no_multishot)
1077
+ return T_EXIT_SKIP;
1078
+
1079
+ msec_to_ts(&ts, base_ms);
1080
+
1081
+ msec_to_ts(&ts_upd, ms);
1082
+ gettimeofday(&tv1, NULL);
1083
+ gettimeofday(&tv2, NULL);
1084
+
1085
+ sqe = io_uring_get_sqe(ring);
1086
+ if (!sqe) {
1087
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1088
+ goto err;
1089
+ }
1090
+
1091
+ msec_to_ts(&ts, base_ms);
1092
+ io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_MULTISHOT);
1093
+ sqe->user_data = 1;
1094
+
1095
+ sqe = io_uring_get_sqe(ring);
1096
+ if (!sqe) {
1097
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1098
+ goto err;
1099
+ }
1100
+
1101
+ io_uring_prep_timeout(sqe, &ts, 0, IORING_TIMEOUT_MULTISHOT);
1102
+ sqe->user_data = 2;
1103
+
1104
+ sqe = io_uring_get_sqe(ring);
1105
+ if (!sqe) {
1106
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1107
+ goto err;
1108
+ }
1109
+
1110
+ io_uring_prep_timeout_update(sqe, &ts_upd, 1, mode);
1111
+ sqe->user_data = 3;
1112
+
1113
+ sqe = io_uring_get_sqe(ring);
1114
+ if (!sqe) {
1115
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1116
+ goto err;
1117
+ }
1118
+
1119
+ io_uring_prep_timeout_update(sqe, &ts_upd, 2, mode);
1120
+ sqe->user_data = 4;
1121
+
1122
+ ret = io_uring_submit(ring);
1123
+ if (ret == 0) {
1124
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1125
+ goto err;
1126
+ }
1127
+
1128
+ for (i = 0; i < nr; i++) {
1129
+ ret = io_uring_wait_cqe(ring, &cqe);
1130
+ if (ret < 0) {
1131
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1132
+ goto err;
1133
+ }
1134
+
1135
+ switch (cqe->user_data) {
1136
+ case 1:
1137
+ if (cqe->res != -ETIME) {
1138
+ fprintf(stderr, "%s: got %d, wanted %d\n",
1139
+ __FUNCTION__, cqe->res, -ETIME);
1140
+ goto err;
1141
+ }
1142
+ exp_ms = mtime_since_now(&tv1);
1143
+ if (exp_ms > 1.05 * ms) {
1144
+ fprintf(stderr, "too long, timeout wasn't updated (expired after %llu instead of %lu)\n", exp_ms, ms);
1145
+ goto err;
1146
+ }
1147
+ gettimeofday(&tv1, NULL);
1148
+
1149
+ break;
1150
+ case 2:
1151
+ if (cqe->res != -ETIME) {
1152
+ fprintf(stderr, "%s: got %d, wanted %d\n",
1153
+ __FUNCTION__, cqe->res, -ETIME);
1154
+ goto err;
1155
+ }
1156
+ exp_ms = mtime_since_now(&tv2);
1157
+ if (exp_ms > 1.05 * ms) {
1158
+ fprintf(stderr, "too long, timeout wasn't updated (expired after %llu instead of %lu)\n", exp_ms, ms);
1159
+ goto err;
1160
+ }
1161
+ gettimeofday(&tv2, NULL);
1162
+ break;
1163
+ case 3:
1164
+ case 4:
1165
+ if (cqe->res != 0) {
1166
+ fprintf(stderr, "%s: got %d, wanted %d\n",
1167
+ __FUNCTION__, cqe->res, 0);
1168
+ goto err;
1169
+ }
1170
+ break;
1171
+ default:
1172
+ goto err;
1173
+ }
1174
+ io_uring_cqe_seen(ring, cqe);
1175
+ }
1176
+
1177
+ sqe = io_uring_get_sqe(ring);
1178
+ if (!sqe) {
1179
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1180
+ goto err;
1181
+ }
1182
+
1183
+ io_uring_prep_timeout_remove(sqe, 1, 0);
1184
+
1185
+ sqe = io_uring_get_sqe(ring);
1186
+ if (!sqe) {
1187
+ fprintf(stderr, "%s: get sqe failed\n", __FUNCTION__);
1188
+ goto err;
1189
+ }
1190
+
1191
+ io_uring_prep_timeout_remove(sqe, 2, 0);
1192
+
1193
+ ret = io_uring_submit(ring);
1194
+ if (ret != 2) {
1195
+ fprintf(stderr, "%s: sqe submit failed: %d\n", __FUNCTION__, ret);
1196
+ goto err;
1197
+ }
1198
+
1199
+ for (i = 0; i < 2; i++) {
1200
+ ret = io_uring_wait_cqe(ring, &cqe);
1201
+ if (ret < 0) {
1202
+ fprintf(stderr, "%s: wait completion %d\n", __FUNCTION__, ret);
1203
+ goto err;
1204
+ }
1205
+ io_uring_cqe_seen(ring, cqe);
1206
+ }
1207
+
1208
+ return 0;
1209
+ err:
1210
+ return 1;
1211
+ }
1212
+
1065
1213
  static int test_update_nonexistent_timeout(struct io_uring *ring)
1066
1214
  {
1067
1215
  struct io_uring_sqe *sqe;
@@ -1559,6 +1707,44 @@ err:
1559
1707
  return 1;
1560
1708
  }
1561
1709
 
1710
+ static int test_eventfd(void)
1711
+ {
1712
+ struct __kernel_timespec ts = { .tv_sec = 5, };
1713
+ struct io_uring_sqe *sqe;
1714
+ struct io_uring ring;
1715
+ int ev, ret;
1716
+
1717
+ ret = io_uring_queue_init(2, &ring, IORING_SETUP_DEFER_TASKRUN |
1718
+ IORING_SETUP_SINGLE_ISSUER);
1719
+ if (ret == -EINVAL) {
1720
+ return T_EXIT_SKIP;
1721
+ } else if (ret < 0) {
1722
+ fprintf(stderr, "queue_init: %d\n", ret);
1723
+ return T_EXIT_FAIL;
1724
+ }
1725
+
1726
+ ev = eventfd(0, 0);
1727
+ if (ev < 0) {
1728
+ perror("eventfd");
1729
+ return T_EXIT_SKIP;
1730
+ }
1731
+
1732
+ ret = io_uring_register_eventfd(&ring, ev);
1733
+ if (ret) {
1734
+ fprintf(stderr, "register_eventfd: %d\n", ret);
1735
+ return ret;
1736
+ }
1737
+
1738
+ sqe = io_uring_get_sqe(&ring);
1739
+ io_uring_prep_timeout(sqe, &ts, 100, 0);
1740
+ sqe->user_data = 0x1234;
1741
+ sqe->flags |= IOSQE_ASYNC;
1742
+ io_uring_submit(&ring);
1743
+
1744
+ io_uring_queue_exit(&ring);
1745
+ close(ev);
1746
+ return T_EXIT_PASS;
1747
+ }
1562
1748
 
1563
1749
  int main(int argc, char *argv[])
1564
1750
  {
@@ -1751,6 +1937,12 @@ int main(int argc, char *argv[])
1751
1937
  return ret;
1752
1938
  }
1753
1939
 
1940
+ ret = test_update_multishot_timeouts(&ring, 200);
1941
+ if (ret && ret != T_EXIT_SKIP) {
1942
+ fprintf(stderr, "test_update_multishot_timeouts linked failed\n");
1943
+ return ret;
1944
+ }
1945
+
1754
1946
  if (sqpoll) {
1755
1947
  ret = test_update_timeout(&sqpoll_ring, 0, false, false,
1756
1948
  false);
@@ -1762,6 +1954,12 @@ int main(int argc, char *argv[])
1762
1954
  }
1763
1955
  }
1764
1956
 
1957
+ ret = test_eventfd();
1958
+ if (ret == T_EXIT_FAIL) {
1959
+ fprintf(stderr, "test_eventfd failed\n");
1960
+ return ret;
1961
+ }
1962
+
1765
1963
  /*
1766
1964
  * this test must go last, it kills the ring
1767
1965
  */