uringmachine 0.26.0 → 0.27.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/TODO.md +2 -14
- data/ext/um/um.c +87 -0
- data/ext/um/um.h +5 -1
- data/ext/um/um_class.c +215 -75
- data/ext/um/um_op.c +3 -1
- data/grant-2025/tasks.md +2 -2
- data/lib/uringmachine/version.rb +1 -1
- data/test/test_um.rb +125 -22
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1211434f5b2f4aad1e47d1bd166204cce6792a80e3ef845ae4dee097d8e1ea45
|
|
4
|
+
data.tar.gz: eff370b4564c88c3daf57cbed3d8b165113ddee697ee1b16aa63ad3452a38c02
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cdb26cf58a41a9f7ad2d025ccc473b0088f4c3e622a65058b1ee6e0aeb95c0eb3775f980cccb60e81b2213ed8fb49263c6500b2c05fbbb71abb156be00dca636
|
|
7
|
+
data.tar.gz: 06f509928387d2812578c143dfb96ed031be10994c7b43908babfef02d72d149b8f2a3932dee7a4d3577150b5512addb8b7c44d5b7ea2e63dddb7f2b427df604
|
data/CHANGELOG.md
CHANGED
data/TODO.md
CHANGED
|
@@ -64,19 +64,6 @@ stream = UM::Stream.new(conn) # io mode
|
|
|
64
64
|
- select on multiple queues (ala Go)
|
|
65
65
|
- select on mixture of queues and fds
|
|
66
66
|
|
|
67
|
-
(see also simplified op management below)
|
|
68
|
-
|
|
69
|
-
## simplified op management
|
|
70
|
-
|
|
71
|
-
Op lifecycle management can be much much simpler
|
|
72
|
-
|
|
73
|
-
- make all ops heap-allocated
|
|
74
|
-
- clear up state transitions:
|
|
75
|
-
|
|
76
|
-
- kernel-side state: unsubmitted, submitted, completed, done (for multishot ops)
|
|
77
|
-
- app-side state: unsubmitted, submitted, ...
|
|
78
|
-
|
|
79
|
-
|
|
80
67
|
## ops
|
|
81
68
|
|
|
82
69
|
- splice / - tee
|
|
@@ -104,7 +91,8 @@ We're still missing:
|
|
|
104
91
|
- ability to supply buffer to `get_line` and `get_string`
|
|
105
92
|
- allow read to eof, maybe with `read_to_eof`
|
|
106
93
|
|
|
107
|
-
For the sake of performance, simplicity and explicitness, we change the API as
|
|
94
|
+
For the sake of performance, simplicity and explicitness, we change the API as
|
|
95
|
+
follows:
|
|
108
96
|
|
|
109
97
|
```ruby
|
|
110
98
|
stream.get_line(buf, limit)
|
data/ext/um/um.c
CHANGED
|
@@ -977,6 +977,93 @@ VALUE um_shutdown_async(struct um *machine, int fd, int how) {
|
|
|
977
977
|
return INT2NUM(fd);
|
|
978
978
|
}
|
|
979
979
|
|
|
980
|
+
struct send_recv_fd_data {
|
|
981
|
+
struct msghdr msgh;
|
|
982
|
+
char iobuf[1];
|
|
983
|
+
struct iovec iov;
|
|
984
|
+
union { // Ancillary data buffer, wrapped in a union for alignment
|
|
985
|
+
char buf[CMSG_SPACE(sizeof(int))];
|
|
986
|
+
struct cmsghdr align;
|
|
987
|
+
} u;
|
|
988
|
+
};
|
|
989
|
+
|
|
990
|
+
inline void recv_fd_prepare(struct send_recv_fd_data *data) {
|
|
991
|
+
memset(&data->msgh, 0, sizeof(data->msgh));
|
|
992
|
+
data->iov.iov_base = data->iobuf;
|
|
993
|
+
data->iov.iov_len = sizeof(data->iobuf);
|
|
994
|
+
data->msgh.msg_iov = &data->iov;
|
|
995
|
+
data->msgh.msg_iovlen = 1;
|
|
996
|
+
data->msgh.msg_control = data->u.buf;
|
|
997
|
+
data->msgh.msg_controllen = sizeof(data->u.buf);
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
inline void send_fd_prepare(struct send_recv_fd_data *data, int fd) {
|
|
1001
|
+
memset(&data->msgh, 0, sizeof(data->msgh));
|
|
1002
|
+
data->iov.iov_base = data->iobuf;
|
|
1003
|
+
data->iov.iov_len = sizeof(data->iobuf);
|
|
1004
|
+
data->msgh.msg_iov = &data->iov;
|
|
1005
|
+
data->msgh.msg_iovlen = 1;
|
|
1006
|
+
data->msgh.msg_control = data->u.buf;
|
|
1007
|
+
data->msgh.msg_controllen = sizeof(data->u.buf);
|
|
1008
|
+
|
|
1009
|
+
struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&data->msgh);
|
|
1010
|
+
cmsgp->cmsg_level = SOL_SOCKET;
|
|
1011
|
+
cmsgp->cmsg_type = SCM_RIGHTS;
|
|
1012
|
+
cmsgp->cmsg_len = CMSG_LEN(sizeof(fd));
|
|
1013
|
+
memcpy(CMSG_DATA(cmsgp), &fd, sizeof(fd));
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
VALUE um_send_fd(struct um *machine, int sock_fd, int fd) {
|
|
1017
|
+
struct send_recv_fd_data data;
|
|
1018
|
+
send_fd_prepare(&data, fd);
|
|
1019
|
+
|
|
1020
|
+
VALUE ret = Qnil;
|
|
1021
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1022
|
+
um_prep_op(machine, op, OP_SENDMSG, 2, 0);
|
|
1023
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
1024
|
+
io_uring_prep_sendmsg(sqe, sock_fd, &data.msgh, 0);
|
|
1025
|
+
|
|
1026
|
+
ret = um_yield(machine);
|
|
1027
|
+
|
|
1028
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(fd);
|
|
1029
|
+
um_op_release(machine, op);
|
|
1030
|
+
|
|
1031
|
+
RAISE_IF_EXCEPTION(ret);
|
|
1032
|
+
RB_GC_GUARD(ret);
|
|
1033
|
+
return ret;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
inline int recv_fd_get_fd(struct send_recv_fd_data *data) {
|
|
1037
|
+
int fd;
|
|
1038
|
+
struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&data->msgh);
|
|
1039
|
+
|
|
1040
|
+
if (cmsgp == NULL || cmsgp->cmsg_len != CMSG_LEN(sizeof(int)) ||
|
|
1041
|
+
cmsgp->cmsg_level != SOL_SOCKET || cmsgp->cmsg_type != SCM_RIGHTS
|
|
1042
|
+
) um_raise_on_error_result(-EINVAL);
|
|
1043
|
+
|
|
1044
|
+
memcpy(&fd, CMSG_DATA(cmsgp), sizeof(int));
|
|
1045
|
+
return fd;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
VALUE um_recv_fd(struct um *machine, int sock_fd) {
|
|
1049
|
+
struct send_recv_fd_data data;
|
|
1050
|
+
recv_fd_prepare(&data);
|
|
1051
|
+
|
|
1052
|
+
struct um_op *op = um_op_acquire(machine);
|
|
1053
|
+
um_prep_op(machine, op, OP_RECVMSG, 2, 0);
|
|
1054
|
+
struct io_uring_sqe *sqe = um_get_sqe(machine, op);
|
|
1055
|
+
io_uring_prep_recvmsg(sqe, sock_fd, &data.msgh, 0);
|
|
1056
|
+
|
|
1057
|
+
VALUE ret = um_yield(machine);
|
|
1058
|
+
|
|
1059
|
+
if (likely(um_verify_op_completion(machine, op, true))) ret = INT2NUM(recv_fd_get_fd(&data));
|
|
1060
|
+
um_op_release(machine, op);
|
|
1061
|
+
|
|
1062
|
+
RAISE_IF_EXCEPTION(ret);
|
|
1063
|
+
RB_GC_GUARD(ret);
|
|
1064
|
+
return ret;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
980
1067
|
VALUE um_open(struct um *machine, VALUE pathname, int flags, int mode) {
|
|
981
1068
|
struct um_op *op = um_op_acquire(machine);
|
|
982
1069
|
um_prep_op(machine, op, OP_OPEN, 2, 0);
|
data/ext/um/um.h
CHANGED
|
@@ -51,9 +51,11 @@ enum um_op_kind {
|
|
|
51
51
|
|
|
52
52
|
OP_ACCEPT,
|
|
53
53
|
OP_RECV,
|
|
54
|
+
OP_RECVMSG,
|
|
54
55
|
OP_SEND,
|
|
55
|
-
OP_SENDV,
|
|
56
56
|
OP_SEND_BUNDLE,
|
|
57
|
+
OP_SENDMSG,
|
|
58
|
+
OP_SENDV,
|
|
57
59
|
OP_SOCKET,
|
|
58
60
|
OP_CONNECT,
|
|
59
61
|
OP_BIND,
|
|
@@ -349,6 +351,8 @@ VALUE um_getsockopt(struct um *machine, int fd, int level, int opt);
|
|
|
349
351
|
VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value);
|
|
350
352
|
VALUE um_shutdown(struct um *machine, int fd, int how);
|
|
351
353
|
VALUE um_shutdown_async(struct um *machine, int fd, int how);
|
|
354
|
+
VALUE um_send_fd(struct um *machine, int sock_fd, int fd);
|
|
355
|
+
VALUE um_recv_fd(struct um *machine, int sock_fd);
|
|
352
356
|
|
|
353
357
|
void um_async_op_set(VALUE self, struct um *machine, struct um_op *op);
|
|
354
358
|
VALUE um_async_op_await(struct um_async_op *async_op);
|
data/ext/um/um_class.c
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
#include <unistd.h>
|
|
6
6
|
#include <sys/socket.h>
|
|
7
7
|
#include <sys/inotify.h>
|
|
8
|
+
#include <linux/prctl.h>
|
|
9
|
+
#include <sys/prctl.h>
|
|
8
10
|
|
|
9
11
|
VALUE cUM;
|
|
10
12
|
VALUE eUMError;
|
|
@@ -328,6 +330,8 @@ VALUE UM_schedule(VALUE self, VALUE fiber, VALUE value) {
|
|
|
328
330
|
/* Runs the given block, interrupting its execution if its runtime exceeds the
|
|
329
331
|
* given timeout interval (in seconds).
|
|
330
332
|
*
|
|
333
|
+
* - https://www.man7.org/linux/man-pages//man3/io_uring_prep_timeoute.3.html
|
|
334
|
+
*
|
|
331
335
|
* @param interval [Number] timeout interval in seconds
|
|
332
336
|
* @param exception_class [any] timeout exception class
|
|
333
337
|
* @return [any] block's return value
|
|
@@ -340,6 +344,8 @@ VALUE UM_timeout(VALUE self, VALUE interval, VALUE exception_class) {
|
|
|
340
344
|
/* Puts the current fiber to sleep for the given time duration (in seconds),
|
|
341
345
|
* yielding control to the next fiber in the runqueue.
|
|
342
346
|
*
|
|
347
|
+
* - https://www.man7.org/linux/man-pages//man3/io_uring_prep_timeoute.3.html
|
|
348
|
+
*
|
|
343
349
|
* @param duration [Number] sleep duration in seconds
|
|
344
350
|
* @return [void]
|
|
345
351
|
*/
|
|
@@ -349,6 +355,8 @@ VALUE UM_sleep(VALUE self, VALUE duration) {
|
|
|
349
355
|
}
|
|
350
356
|
|
|
351
357
|
/* Runs the given block at regular time intervals in an infinite loop.
|
|
358
|
+
*
|
|
359
|
+
* - https://www.man7.org/linux/man-pages//man3/io_uring_prep_timeoute.3.html
|
|
352
360
|
*
|
|
353
361
|
* @param interval [Number] time interval (in seconds) between consecutive invocations
|
|
354
362
|
* @return [void]
|
|
@@ -359,21 +367,23 @@ VALUE UM_periodically(VALUE self, VALUE interval) {
|
|
|
359
367
|
}
|
|
360
368
|
|
|
361
369
|
/* call-seq:
|
|
362
|
-
* machine.read(fd, buffer, maxlen
|
|
370
|
+
* machine.read(fd, buffer, maxlen, buffer_offset = nil, file_offset = nil) -> bytes_read
|
|
363
371
|
*
|
|
364
372
|
* Reads up to `maxlen` bytes from the given `fd` into the given buffer. The
|
|
365
373
|
* optional `buffer_offset` parameter determines the position in the buffer into
|
|
366
374
|
* which the data will be read. A negative `buffer_offset` denotes a position
|
|
367
375
|
* relative to the end of the buffer, e.g. a value of `-1` means the data will
|
|
368
376
|
* be appended to the buffer.
|
|
377
|
+
*
|
|
378
|
+
* - https://www.man7.org/linux/man-pages/man2/read.2.html
|
|
379
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_read.3.html
|
|
369
380
|
*
|
|
370
|
-
* @
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
* @return [Integer] number of bytes read
|
|
381
|
+
* @param fd [Integer] file descriptor
|
|
382
|
+
* @param buffer [String, IO::Buffer] buffer
|
|
383
|
+
* @param maxlen [Integer] maximum number of bytes to read
|
|
384
|
+
* @param buffer_offset [Integer] optional buffer offset to read into
|
|
385
|
+
* @param file_offset [Integer] optional file offset to read from
|
|
386
|
+
* @return [Integer] number of bytes read
|
|
377
387
|
*/
|
|
378
388
|
VALUE UM_read(int argc, VALUE *argv, VALUE self) {
|
|
379
389
|
struct um *machine = um_get_machine(self);
|
|
@@ -398,6 +408,8 @@ VALUE UM_read(int argc, VALUE *argv, VALUE self) {
|
|
|
398
408
|
* buffer group should have been previously setup using `#setup_buffer_ring`.
|
|
399
409
|
* Read data is yielded in an infinite loop to the given block.
|
|
400
410
|
*
|
|
411
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_read_multishot.3.html
|
|
412
|
+
*
|
|
401
413
|
* @param fd [Integer] file descriptor
|
|
402
414
|
* @param bgid [Integer] buffer group id
|
|
403
415
|
* @return [void]
|
|
@@ -408,17 +420,19 @@ VALUE UM_read_each(VALUE self, VALUE fd, VALUE bgid) {
|
|
|
408
420
|
}
|
|
409
421
|
|
|
410
422
|
/* call-seq:
|
|
411
|
-
* machine.write(fd, buffer
|
|
423
|
+
* machine.write(fd, buffer, len = nil, file_offset = nil) -> bytes_written
|
|
412
424
|
*
|
|
413
425
|
* Writes up to `len` bytes from the given buffer to the given `fd`. If `len`,
|
|
414
426
|
* is not given, the entire buffer length is used.
|
|
415
427
|
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
428
|
+
* - https://man7.org/linux/man-pages/man2/write.2.html
|
|
429
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_write.3.html
|
|
430
|
+
*
|
|
431
|
+
* @param fd [Integer] file descriptor
|
|
432
|
+
* @param buffer [String, IO::Buffer] buffer
|
|
433
|
+
* @param len [Integer] maximum number of bytes to write
|
|
434
|
+
* @param file_offset [Integer] optional file offset to write to
|
|
435
|
+
* @return [Integer] number of bytes written
|
|
422
436
|
*/
|
|
423
437
|
VALUE UM_write(int argc, VALUE *argv, VALUE self) {
|
|
424
438
|
struct um *machine = um_get_machine(self);
|
|
@@ -435,7 +449,7 @@ VALUE UM_write(int argc, VALUE *argv, VALUE self) {
|
|
|
435
449
|
}
|
|
436
450
|
|
|
437
451
|
/* call-seq:
|
|
438
|
-
* machine.writev(fd, *buffers
|
|
452
|
+
* machine.writev(fd, *buffers, file_offset = nil) -> bytes_written
|
|
439
453
|
*
|
|
440
454
|
* Writes from the given buffers into the given fd. This method does not
|
|
441
455
|
* guarantee that all data will be written. The application code should check
|
|
@@ -443,11 +457,13 @@ VALUE UM_write(int argc, VALUE *argv, VALUE self) {
|
|
|
443
457
|
* repeat the operation after adjusting the buffers accordingly. See also
|
|
444
458
|
* `#sendv`.
|
|
445
459
|
*
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
460
|
+
* - https://man7.org/linux/man-pages/man2/writev.2.html
|
|
461
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_writev.3.html
|
|
462
|
+
*
|
|
463
|
+
* @param fd [Integer] file descriptor
|
|
464
|
+
* @param *buffers [Array<String, IO::Buffer>] data buffers
|
|
465
|
+
* @param file_offset [Integer] optional file offset to write to
|
|
466
|
+
* @return [Integer] number of bytes written
|
|
451
467
|
*/
|
|
452
468
|
VALUE UM_writev(int argc, VALUE *argv, VALUE self) {
|
|
453
469
|
struct um *machine = um_get_machine(self);
|
|
@@ -460,7 +476,7 @@ VALUE UM_writev(int argc, VALUE *argv, VALUE self) {
|
|
|
460
476
|
}
|
|
461
477
|
|
|
462
478
|
/* call-seq:
|
|
463
|
-
* machine.write_async(fd, buffer
|
|
479
|
+
* machine.write_async(fd, buffer, len = nil, file_offset = nil) -> buffer
|
|
464
480
|
*
|
|
465
481
|
* Writes up to `len` bytes from the given buffer to the given `fd`. If `len`,
|
|
466
482
|
* is not given, the entire buffer length is used. This method submits the
|
|
@@ -468,12 +484,14 @@ VALUE UM_writev(int argc, VALUE *argv, VALUE self) {
|
|
|
468
484
|
* improve performance in situations where the application does not care about
|
|
469
485
|
* whether the I/O operation succeeds or not.
|
|
470
486
|
*
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
487
|
+
* - https://man7.org/linux/man-pages/man2/write.2.html
|
|
488
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_write.3.html
|
|
489
|
+
*
|
|
490
|
+
* @param fd [Integer] file descriptor
|
|
491
|
+
* @param buffer [String, IO::Buffer] buffer
|
|
492
|
+
* @param len [Integer] maximum number of bytes to write
|
|
493
|
+
* @param file_offset [Integer] optional file offset to write to
|
|
494
|
+
* @return [String, IO::Buffer] buffer
|
|
477
495
|
*/
|
|
478
496
|
VALUE UM_write_async(int argc, VALUE *argv, VALUE self) {
|
|
479
497
|
struct um *machine = um_get_machine(self);
|
|
@@ -496,6 +514,9 @@ VALUE UM_write_async(int argc, VALUE *argv, VALUE self) {
|
|
|
496
514
|
*
|
|
497
515
|
* Returns information about a file.
|
|
498
516
|
*
|
|
517
|
+
* - https://www.man7.org/linux/man-pages/man2/statx.2.html
|
|
518
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_statx.3.html
|
|
519
|
+
*
|
|
499
520
|
* @param dirfd [Integer] file or directory descriptor
|
|
500
521
|
* @param path [String, nil] file path
|
|
501
522
|
* @param flags [Integer] flags
|
|
@@ -512,6 +533,9 @@ VALUE UM_statx(VALUE self, VALUE dirfd, VALUE path, VALUE flags, VALUE mask) {
|
|
|
512
533
|
*
|
|
513
534
|
* Closes the given file descriptor.
|
|
514
535
|
*
|
|
536
|
+
* - https://www.man7.org/linux/man-pages/man2/close.2.html
|
|
537
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_close.3.html
|
|
538
|
+
*
|
|
515
539
|
* @param fd [Integer] file descriptor
|
|
516
540
|
* @return [0] success
|
|
517
541
|
*/
|
|
@@ -527,6 +551,9 @@ VALUE UM_close(VALUE self, VALUE fd) {
|
|
|
527
551
|
* not wait for it to complete. This method may be used to improve performance
|
|
528
552
|
* in cases where the application des not care whether it succeeds or not.
|
|
529
553
|
*
|
|
554
|
+
* - https://www.man7.org/linux/man-pages/man2/close.2.html
|
|
555
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_close.3.html
|
|
556
|
+
*
|
|
530
557
|
* @param fd [Integer] file descriptor
|
|
531
558
|
* @return [Integer] file descriptor
|
|
532
559
|
*/
|
|
@@ -540,6 +567,9 @@ VALUE UM_close_async(VALUE self, VALUE fd) {
|
|
|
540
567
|
*
|
|
541
568
|
* Accepts an incoming TCP connection.
|
|
542
569
|
*
|
|
570
|
+
* - https://www.man7.org/linux/man-pages/man2/accept4.2.html
|
|
571
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_accept.3.html
|
|
572
|
+
*
|
|
543
573
|
* @param server_fd [Integer] listening socket file descriptor
|
|
544
574
|
* @return [Integer] connection file descriptor
|
|
545
575
|
*/
|
|
@@ -554,6 +584,9 @@ VALUE UM_accept(VALUE self, VALUE server_fd) {
|
|
|
554
584
|
* Repeatedly accepts incoming TCP connections in a loop, yielding the
|
|
555
585
|
* connection file descriptors to the given block.
|
|
556
586
|
*
|
|
587
|
+
* - https://www.man7.org/linux/man-pages/man2/accept4.2.html
|
|
588
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_accept.3.html
|
|
589
|
+
*
|
|
557
590
|
* @param server_fd [Integer] listening socket file descriptor
|
|
558
591
|
* @return [void]
|
|
559
592
|
*/
|
|
@@ -563,11 +596,14 @@ VALUE UM_accept_each(VALUE self, VALUE server_fd) {
|
|
|
563
596
|
}
|
|
564
597
|
|
|
565
598
|
/* call-seq:
|
|
566
|
-
* machine.
|
|
599
|
+
* machine.accept_into_queue(server_fd, queue)
|
|
567
600
|
*
|
|
568
601
|
* Repeatedly accepts incoming TCP connections in a loop, pushing the connection
|
|
569
602
|
* file descriptors into the given queue.
|
|
570
603
|
*
|
|
604
|
+
* - https://www.man7.org/linux/man-pages/man2/accept4.2.html
|
|
605
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_accept.3.html
|
|
606
|
+
*
|
|
571
607
|
* @param server_fd [Integer] listening socket file descriptor
|
|
572
608
|
* @param queue [UM::Queue] connection queue
|
|
573
609
|
* @return [void]
|
|
@@ -582,6 +618,9 @@ VALUE UM_accept_into_queue(VALUE self, VALUE server_fd, VALUE queue) {
|
|
|
582
618
|
*
|
|
583
619
|
* Creates a socket.
|
|
584
620
|
*
|
|
621
|
+
* - https://www.man7.org/linux/man-pages/man2/socket.2.html
|
|
622
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_socket.3.html
|
|
623
|
+
*
|
|
585
624
|
* @param domain [Integer] socket domain
|
|
586
625
|
* @param type [Integer] socket type
|
|
587
626
|
* @param protocol [Integer] socket protocol
|
|
@@ -598,6 +637,9 @@ VALUE UM_socket(VALUE self, VALUE domain, VALUE type, VALUE protocol, VALUE flag
|
|
|
598
637
|
*
|
|
599
638
|
* Shuts down a socket for sending and/or receiving.
|
|
600
639
|
*
|
|
640
|
+
* - https://man7.org/linux/man-pages/man2/shutdown.2.html
|
|
641
|
+
* - https://man7.org/linux/man-pages/man3/io_uring_prep_shutdown.3.html
|
|
642
|
+
*
|
|
601
643
|
* @param fd [Integer] file descriptor
|
|
602
644
|
* @param how [Integer] how the socket should be shutdown
|
|
603
645
|
* @return [0] success
|
|
@@ -614,6 +656,9 @@ VALUE UM_shutdown(VALUE self, VALUE fd, VALUE how) {
|
|
|
614
656
|
* improve performance in situations where the application does not care about
|
|
615
657
|
* whether the operation succeeds or not.
|
|
616
658
|
*
|
|
659
|
+
* - https://man7.org/linux/man-pages/man2/shutdown.2.html
|
|
660
|
+
* - https://man7.org/linux/man-pages/man3/io_uring_prep_shutdown.3.html
|
|
661
|
+
*
|
|
617
662
|
* @param fd [Integer] file descriptor
|
|
618
663
|
* @param how [Integer] how the socket should be shutdown
|
|
619
664
|
* @return [0] success
|
|
@@ -623,11 +668,47 @@ VALUE UM_shutdown_async(VALUE self, VALUE fd, VALUE how) {
|
|
|
623
668
|
return um_shutdown_async(machine, NUM2INT(fd), NUM2INT(how));
|
|
624
669
|
}
|
|
625
670
|
|
|
671
|
+
/* call-seq:
|
|
672
|
+
* machine.send_fd(sock_fd, fd) -> fd
|
|
673
|
+
*
|
|
674
|
+
* Sends the given file descriptor over the given socket.
|
|
675
|
+
*
|
|
676
|
+
* - https://www.man7.org/linux/man-pages/man3/sendmsg.3p.html
|
|
677
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_sendmsg.3.html
|
|
678
|
+
*
|
|
679
|
+
* @param sock_fd [Integer] socket file descriptor
|
|
680
|
+
* @param fd [Integer] file descriptor to send
|
|
681
|
+
* @return [Integer] file descriptor to send
|
|
682
|
+
*/
|
|
683
|
+
VALUE UM_send_fd(VALUE self, VALUE sock_fd, VALUE fd) {
|
|
684
|
+
struct um *machine = um_get_machine(self);
|
|
685
|
+
return um_send_fd(machine, NUM2INT(sock_fd), NUM2INT(fd));
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/* call-seq:
|
|
689
|
+
* machine.recv_fd(sock_fd) -> fd
|
|
690
|
+
*
|
|
691
|
+
* Receives a file descriptor over the given socket.
|
|
692
|
+
*
|
|
693
|
+
* - https://www.man7.org/linux/man-pages/man3/recvmsg.3p.html
|
|
694
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_recvmsg.3.html
|
|
695
|
+
*
|
|
696
|
+
* @param sock_fd [Integer] socket file descriptor
|
|
697
|
+
* @return [Integer] rececived file descriptor
|
|
698
|
+
*/
|
|
699
|
+
VALUE UM_recv_fd(VALUE self, VALUE sock_fd) {
|
|
700
|
+
struct um *machine = um_get_machine(self);
|
|
701
|
+
return um_recv_fd(machine, NUM2INT(sock_fd));
|
|
702
|
+
}
|
|
703
|
+
|
|
626
704
|
/* call-seq:
|
|
627
705
|
* machine.connect(fd, host, port) -> 0
|
|
628
706
|
*
|
|
629
707
|
* Connects the given socket to the given host and port.
|
|
630
708
|
*
|
|
709
|
+
* - https://www.man7.org/linux/man-pages/man2/connect.2.html
|
|
710
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_connect.3.html
|
|
711
|
+
*
|
|
631
712
|
* @param fd [Integer] file descriptor
|
|
632
713
|
* @param host [String] hostname or IP address
|
|
633
714
|
* @param port [Integer] port number
|
|
@@ -652,6 +733,9 @@ VALUE UM_connect(VALUE self, VALUE fd, VALUE host, VALUE port) {
|
|
|
652
733
|
* the data in the buffer, unless `UM::MSG_WAITALL` is specified in the flags
|
|
653
734
|
* mask.
|
|
654
735
|
*
|
|
736
|
+
* - https://www.man7.org/linux/man-pages/man2/send.2.html
|
|
737
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_send.3.html
|
|
738
|
+
*
|
|
655
739
|
* @param fd [Integer] file descriptor
|
|
656
740
|
* @param buffer [String, IO::Buffer] buffer
|
|
657
741
|
* @param len [Integer] number of bytes to send
|
|
@@ -671,6 +755,9 @@ VALUE UM_send(VALUE self, VALUE fd, VALUE buffer, VALUE len, VALUE flags) {
|
|
|
671
755
|
* Sends data on the given socket from the given buffers. This method is only
|
|
672
756
|
* available on Linux kernel >= 6.17. This method is guaranteed to send
|
|
673
757
|
*
|
|
758
|
+
* - https://www.man7.org/linux/man-pages/man2/send.2.html
|
|
759
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_send.3.html
|
|
760
|
+
*
|
|
674
761
|
* @overload sendv(fd, *buffers)
|
|
675
762
|
* @param fd [Integer] file descriptor
|
|
676
763
|
* @param *buffers [Array<String, IO::Buffer>] buffers
|
|
@@ -695,6 +782,9 @@ VALUE UM_sendv(int argc, VALUE *argv, VALUE self) {
|
|
|
695
782
|
* buffer group. The buffer group should have been previously registered using
|
|
696
783
|
* `#setup_buffer_ring`.
|
|
697
784
|
*
|
|
785
|
+
* - https://www.man7.org/linux/man-pages/man2/send.2.html
|
|
786
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_send.3.html
|
|
787
|
+
*
|
|
698
788
|
* @overload send_bundle(fd, bgid, *buffers)
|
|
699
789
|
* @param fd [Integer] file descriptor
|
|
700
790
|
* @param bgid [Integer] buffer group id
|
|
@@ -722,6 +812,9 @@ VALUE UM_send_bundle(int argc, VALUE *argv, VALUE self) {
|
|
|
722
812
|
*
|
|
723
813
|
* Receives data from the given socket.
|
|
724
814
|
*
|
|
815
|
+
* - https://www.man7.org/linux/man-pages/man2/recv.2.html
|
|
816
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_recv.3.html
|
|
817
|
+
*
|
|
725
818
|
* @param fd [Integer] file descriptor
|
|
726
819
|
* @param buffer [String, IO::Buffer] buffer
|
|
727
820
|
* @param maxlen [Integer] maximum number of bytes to receive
|
|
@@ -740,6 +833,9 @@ VALUE UM_recv(VALUE self, VALUE fd, VALUE buffer, VALUE maxlen, VALUE flags) {
|
|
|
740
833
|
* given buffer group id. The buffer group should have been previously setup
|
|
741
834
|
* using `#setup_buffer_ring`.
|
|
742
835
|
*
|
|
836
|
+
* - https://www.man7.org/linux/man-pages/man2/recv.2.html
|
|
837
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_recv.3.html
|
|
838
|
+
*
|
|
743
839
|
* @param fd [Integer] file descriptor
|
|
744
840
|
* @param bgid [Integer] buffer group id
|
|
745
841
|
* @param flags [Integer] flags mask
|
|
@@ -755,6 +851,9 @@ VALUE UM_recv_each(VALUE self, VALUE fd, VALUE bgid, VALUE flags) {
|
|
|
755
851
|
*
|
|
756
852
|
* Binds the given socket to the given host and port.
|
|
757
853
|
*
|
|
854
|
+
* - https://www.man7.org/linux/man-pages/man2/bind.2.html
|
|
855
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_bind.3.html
|
|
856
|
+
*
|
|
758
857
|
* @param fd [Integer] file descriptor
|
|
759
858
|
* @param host [String] hostname or IP address
|
|
760
859
|
* @param port [Integer] port number
|
|
@@ -783,6 +882,9 @@ VALUE UM_bind(VALUE self, VALUE fd, VALUE host, VALUE port) {
|
|
|
783
882
|
*
|
|
784
883
|
* Starts listening for incoming connections on the given socket.
|
|
785
884
|
*
|
|
885
|
+
* - https://www.man7.org/linux/man-pages/man2/listen.2.html
|
|
886
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_listen.3.html
|
|
887
|
+
*
|
|
786
888
|
* @param fd [Integer] file descriptor
|
|
787
889
|
* @param backlog [String] pending connection queue length
|
|
788
890
|
* @return [0] success
|
|
@@ -815,6 +917,9 @@ static inline int numeric_value(VALUE value) {
|
|
|
815
917
|
*
|
|
816
918
|
* Returns the value of a socket option.
|
|
817
919
|
*
|
|
920
|
+
* - https://www.man7.org/linux/man-pages//man2/getsockopt.2.html
|
|
921
|
+
* - https://www.man7.org/linux/man-pages//man3/io_uring_prep_cmd.3.html
|
|
922
|
+
*
|
|
818
923
|
* @param fd [Integer] file descriptor
|
|
819
924
|
* @param level [Integer] level
|
|
820
925
|
* @param opt [Integer] level
|
|
@@ -826,10 +931,13 @@ VALUE UM_getsockopt(VALUE self, VALUE fd, VALUE level, VALUE opt) {
|
|
|
826
931
|
}
|
|
827
932
|
|
|
828
933
|
/* call-seq:
|
|
829
|
-
* machine.
|
|
934
|
+
* machine.setsockopt(fd, level, opt, value) -> 0
|
|
830
935
|
*
|
|
831
936
|
* Sets the value of a socket option.
|
|
832
937
|
*
|
|
938
|
+
* - https://www.man7.org/linux/man-pages//man2/setsockopt.2.html
|
|
939
|
+
* - https://www.man7.org/linux/man-pages//man3/io_uring_prep_cmd.3.html
|
|
940
|
+
*
|
|
833
941
|
* @param fd [Integer] file descriptor
|
|
834
942
|
* @param level [Integer] level
|
|
835
943
|
* @param opt [Integer] level
|
|
@@ -847,6 +955,9 @@ VALUE UM_setsockopt(VALUE self, VALUE fd, VALUE level, VALUE opt, VALUE value) {
|
|
|
847
955
|
* Synchronizes access to the given mutex. The mutex is locked, the given block
|
|
848
956
|
* is executed and finally the mutex is unlocked.
|
|
849
957
|
*
|
|
958
|
+
* - https://www.man7.org/linux/man-pages/man2/futex.2.html
|
|
959
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_futex_wait.3.html
|
|
960
|
+
*
|
|
850
961
|
* @param mutex [UM::Mutex] mutex
|
|
851
962
|
* @return [any] block return value
|
|
852
963
|
*/
|
|
@@ -861,6 +972,9 @@ VALUE UM_mutex_synchronize(VALUE self, VALUE mutex) {
|
|
|
861
972
|
*
|
|
862
973
|
* Pushes a value to the tail of the given queue.
|
|
863
974
|
*
|
|
975
|
+
* - https://www.man7.org/linux/man-pages/man2/futex.2.html
|
|
976
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_futex_wait.3.html
|
|
977
|
+
*
|
|
864
978
|
* @param queue [UM::Queue] queue
|
|
865
979
|
* @param value [any] value
|
|
866
980
|
* @return [UM::Queue] queue
|
|
@@ -876,6 +990,9 @@ VALUE UM_queue_push(VALUE self, VALUE queue, VALUE value) {
|
|
|
876
990
|
*
|
|
877
991
|
* removes a value from the tail of the given queue.
|
|
878
992
|
*
|
|
993
|
+
* - https://www.man7.org/linux/man-pages/man2/futex.2.html
|
|
994
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_futex_wait.3.html
|
|
995
|
+
*
|
|
879
996
|
* @param queue [UM::Queue] queue
|
|
880
997
|
* @return [any] value
|
|
881
998
|
*/
|
|
@@ -890,6 +1007,9 @@ VALUE UM_queue_pop(VALUE self, VALUE queue) {
|
|
|
890
1007
|
*
|
|
891
1008
|
* Pushes a value to the head of the given queue.
|
|
892
1009
|
*
|
|
1010
|
+
* - https://www.man7.org/linux/man-pages/man2/futex.2.html
|
|
1011
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_futex_wait.3.html
|
|
1012
|
+
*
|
|
893
1013
|
* @param queue [UM::Queue] queue
|
|
894
1014
|
* @param value [any] value
|
|
895
1015
|
* @return [UM::Queue] queue
|
|
@@ -905,6 +1025,9 @@ VALUE UM_queue_unshift(VALUE self, VALUE queue, VALUE value) {
|
|
|
905
1025
|
*
|
|
906
1026
|
* removes a value from the head of the given queue.
|
|
907
1027
|
*
|
|
1028
|
+
* - https://www.man7.org/linux/man-pages/man2/futex.2.html
|
|
1029
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_futex_wait.3.html
|
|
1030
|
+
*
|
|
908
1031
|
* @param queue [UM::Queue] queue
|
|
909
1032
|
* @return [any] value
|
|
910
1033
|
*/
|
|
@@ -933,6 +1056,9 @@ VALUE UM_open_complete(VALUE arg) {
|
|
|
933
1056
|
* file descriptor is passed to the block, and the file is automatically closed
|
|
934
1057
|
* when the block returns.
|
|
935
1058
|
*
|
|
1059
|
+
* - https://www.man7.org/linux/man-pages/man2/open.2.html
|
|
1060
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_openat.3.html
|
|
1061
|
+
*
|
|
936
1062
|
* @param pathname [String] file path
|
|
937
1063
|
* @param flags [Integer] flags mask
|
|
938
1064
|
* @return [Integer] fd
|
|
@@ -955,6 +1081,9 @@ VALUE UM_open(VALUE self, VALUE pathname, VALUE flags) {
|
|
|
955
1081
|
* Waits for readiness of the given file descriptor according to the given event
|
|
956
1082
|
* mask.
|
|
957
1083
|
*
|
|
1084
|
+
* - https://www.man7.org/linux/man-pages/man2/poll.2.html
|
|
1085
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_poll_add.3.html
|
|
1086
|
+
*
|
|
958
1087
|
* @param fd [Integer] file descriptor
|
|
959
1088
|
* @param mask [Integer] events mask
|
|
960
1089
|
* @return [Integer] fd
|
|
@@ -970,6 +1099,9 @@ VALUE UM_poll(VALUE self, VALUE fd, VALUE mask) {
|
|
|
970
1099
|
* Waits for readyness of at least one fd for read, write or exception condition
|
|
971
1100
|
* from the given fds. This method provides a similar interface to `IO#select`.
|
|
972
1101
|
*
|
|
1102
|
+
* - https://www.man7.org/linux/man-pages/man2/select.2.html
|
|
1103
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_poll_add.3.html
|
|
1104
|
+
*
|
|
973
1105
|
* @param read_fds [Array<Integer>] file descriptors for reading
|
|
974
1106
|
* @param write_fds [Array<Integer>] file descriptors for writing
|
|
975
1107
|
* @param except_fds [Array<Integer>] file descriptors for exception
|
|
@@ -986,6 +1118,9 @@ VALUE UM_select(VALUE self, VALUE read_fds, VALUE write_fds, VALUE except_fds) {
|
|
|
986
1118
|
* Waits for a process to change state. The process to wait for can be specified
|
|
987
1119
|
* as a pid or as a pidfd, according to the given `idtype` and `id`.
|
|
988
1120
|
*
|
|
1121
|
+
* - https://www.man7.org/linux/man-pages/man2/waitid.2.html
|
|
1122
|
+
* - https://www.man7.org/linux/man-pages/man3/io_uring_prep_waitid.3.html
|
|
1123
|
+
*
|
|
989
1124
|
* @param idtype [Integer] id type
|
|
990
1125
|
* @param id [Integer] id
|
|
991
1126
|
* @param options [Integer] options
|
|
@@ -1077,6 +1212,8 @@ VALUE UM_ssl_write(VALUE self, VALUE ssl, VALUE buf, VALUE len) {
|
|
|
1077
1212
|
*
|
|
1078
1213
|
* Creates a pipe, returning the file descriptors for the read and write ends.
|
|
1079
1214
|
*
|
|
1215
|
+
* - https://www.man7.org/linux/man-pages/man2/pipe.2.html
|
|
1216
|
+
*
|
|
1080
1217
|
* @return [Array<Integer>] array containing the read and write file descriptors
|
|
1081
1218
|
*/
|
|
1082
1219
|
VALUE UM_pipe(VALUE self) {
|
|
@@ -1095,6 +1232,8 @@ VALUE UM_pipe(VALUE self) {
|
|
|
1095
1232
|
*
|
|
1096
1233
|
* Creates a pair of connected sockets, returning the two file descriptors.
|
|
1097
1234
|
*
|
|
1235
|
+
* - https://www.man7.org/linux/man-pages/man2/socketpair.2.html
|
|
1236
|
+
*
|
|
1098
1237
|
* @param domain [Integer] domain
|
|
1099
1238
|
* @param type [Integer] type
|
|
1100
1239
|
* @param protocol [Integer] protocol
|
|
@@ -1117,6 +1256,8 @@ VALUE UM_socketpair(VALUE self, VALUE domain, VALUE type, VALUE protocol) {
|
|
|
1117
1256
|
* Creates a file descriptor representing the given process pid. The file
|
|
1118
1257
|
* descriptor can then be used with methods such as `#waitid` or `.pidfd_open`.
|
|
1119
1258
|
*
|
|
1259
|
+
* - https://www.man7.org/linux/man-pages/man2/pidfd_open.2.html
|
|
1260
|
+
*
|
|
1120
1261
|
* @param pid [Integer] process pid
|
|
1121
1262
|
* @return [Integer] file descriptor
|
|
1122
1263
|
*/
|
|
@@ -1135,6 +1276,8 @@ VALUE UM_pidfd_open(VALUE self, VALUE pid) {
|
|
|
1135
1276
|
*
|
|
1136
1277
|
* Sends a signal to a pidfd.
|
|
1137
1278
|
*
|
|
1279
|
+
* - https://www.man7.org/linux/man-pages/man2/pidfd_send_signal.2.html
|
|
1280
|
+
*
|
|
1138
1281
|
* @param fd [Integer] pidfd
|
|
1139
1282
|
* @param sig [Integer] signal
|
|
1140
1283
|
* @return [Integer] pidfd
|
|
@@ -1151,38 +1294,6 @@ VALUE UM_pidfd_send_signal(VALUE self, VALUE fd, VALUE sig) {
|
|
|
1151
1294
|
return fd;
|
|
1152
1295
|
}
|
|
1153
1296
|
|
|
1154
|
-
/* :nodoc:
|
|
1155
|
-
*/
|
|
1156
|
-
VALUE UM_io_nonblock_p(VALUE self, VALUE io) {
|
|
1157
|
-
int fd = rb_io_descriptor(io);
|
|
1158
|
-
int oflags = fcntl(fd, F_GETFL);
|
|
1159
|
-
if (oflags == -1) return Qnil;
|
|
1160
|
-
|
|
1161
|
-
return (oflags & O_NONBLOCK) ? Qtrue : Qfalse;
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
/* :nodoc:
|
|
1165
|
-
*/
|
|
1166
|
-
VALUE UM_io_set_nonblock(VALUE self, VALUE io, VALUE nonblock) {
|
|
1167
|
-
int fd = rb_io_descriptor(io);
|
|
1168
|
-
int oflags = fcntl(fd, F_GETFL);
|
|
1169
|
-
if (oflags == -1) return Qnil;
|
|
1170
|
-
|
|
1171
|
-
if (RTEST(nonblock)) {
|
|
1172
|
-
if (!(oflags & O_NONBLOCK)) {
|
|
1173
|
-
oflags |= O_NONBLOCK;
|
|
1174
|
-
fcntl(fd, F_SETFL, oflags);
|
|
1175
|
-
}
|
|
1176
|
-
}
|
|
1177
|
-
else {
|
|
1178
|
-
if (oflags & O_NONBLOCK) {
|
|
1179
|
-
oflags &= ~O_NONBLOCK;
|
|
1180
|
-
fcntl(fd, F_SETFL, oflags);
|
|
1181
|
-
}
|
|
1182
|
-
}
|
|
1183
|
-
return nonblock;
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
1297
|
/* call-seq:
|
|
1187
1298
|
* UringMachine.kernel_version -> version
|
|
1188
1299
|
*
|
|
@@ -1212,6 +1323,8 @@ VALUE UM_debug(VALUE self, VALUE str) {
|
|
|
1212
1323
|
*
|
|
1213
1324
|
* Creates an inotify file descriptor.
|
|
1214
1325
|
*
|
|
1326
|
+
* - https://www.man7.org/linux/man-pages/man2/inotify_init.2.html
|
|
1327
|
+
*
|
|
1215
1328
|
* @return [Integer] file descriptor
|
|
1216
1329
|
*/
|
|
1217
1330
|
VALUE UM_inotify_init(VALUE self) {
|
|
@@ -1228,6 +1341,8 @@ VALUE UM_inotify_init(VALUE self) {
|
|
|
1228
1341
|
*
|
|
1229
1342
|
* Adds a watch on the given inotify file descriptor.
|
|
1230
1343
|
*
|
|
1344
|
+
* - https://www.man7.org/linux/man-pages/man2/inotify_add_watch.2.html
|
|
1345
|
+
*
|
|
1231
1346
|
* @param fd [Integer] inotify file descriptor
|
|
1232
1347
|
* @param path [String] file/directory path
|
|
1233
1348
|
* @param mask [Integer] inotify event mask
|
|
@@ -1269,6 +1384,8 @@ static inline VALUE inotify_get_events(char *buf, size_t len) {
|
|
|
1269
1384
|
* descriptor. Each event is returned as a hash containing the watch descriptor,
|
|
1270
1385
|
* the file name, and the event mask.
|
|
1271
1386
|
*
|
|
1387
|
+
* - https://www.man7.org/linux/man-pages/man7/inotify.7.html
|
|
1388
|
+
*
|
|
1272
1389
|
* @param fd [Integer] inotify file descriptor
|
|
1273
1390
|
* @return [Array<Hash>] array of one or more events
|
|
1274
1391
|
*/
|
|
@@ -1281,12 +1398,46 @@ VALUE UM_inotify_get_events(VALUE self, VALUE fd) {
|
|
|
1281
1398
|
return inotify_get_events(buf, ret);
|
|
1282
1399
|
}
|
|
1283
1400
|
|
|
1401
|
+
/* call-seq:
|
|
1402
|
+
* UringMachine.pr_set_child_subreaper(vaule) -> value
|
|
1403
|
+
*
|
|
1404
|
+
* Sets/unsets the "child subreaper" attribute of the calling process.
|
|
1405
|
+
*
|
|
1406
|
+
* - https://man7.org/linux/man-pages/man2/PR_SET_CHILD_SUBREAPER.2const.html
|
|
1407
|
+
*
|
|
1408
|
+
* @param value [bool] set/unset value
|
|
1409
|
+
* @return [bool] set/unset value
|
|
1410
|
+
*/
|
|
1411
|
+
VALUE UM_pr_set_child_subreaper(VALUE self, VALUE set) {
|
|
1412
|
+
int ret = prctl(PR_SET_CHILD_SUBREAPER, RTEST(set) ? 1 : 0);
|
|
1413
|
+
if (ret) {
|
|
1414
|
+
int e = errno;
|
|
1415
|
+
rb_syserr_fail(e, strerror(e));
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
return set;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1284
1421
|
void Init_UM(void) {
|
|
1285
1422
|
rb_ext_ractor_safe(true);
|
|
1286
1423
|
|
|
1287
1424
|
cUM = rb_define_class("UringMachine", rb_cObject);
|
|
1288
1425
|
rb_define_alloc_func(cUM, UM_allocate);
|
|
1289
1426
|
|
|
1427
|
+
rb_define_singleton_method(cUM, "pipe", UM_pipe, 0);
|
|
1428
|
+
rb_define_singleton_method(cUM, "socketpair", UM_socketpair, 3);
|
|
1429
|
+
rb_define_singleton_method(cUM, "pidfd_open", UM_pidfd_open, 1);
|
|
1430
|
+
rb_define_singleton_method(cUM, "pidfd_send_signal", UM_pidfd_send_signal, 2);
|
|
1431
|
+
|
|
1432
|
+
rb_define_singleton_method(cUM, "kernel_version", UM_kernel_version, 0);
|
|
1433
|
+
rb_define_singleton_method(cUM, "debug", UM_debug, 1);
|
|
1434
|
+
|
|
1435
|
+
rb_define_singleton_method(cUM, "inotify_init", UM_inotify_init, 0);
|
|
1436
|
+
rb_define_singleton_method(cUM, "inotify_add_watch", UM_inotify_add_watch, 3);
|
|
1437
|
+
|
|
1438
|
+
rb_define_singleton_method(cUM, "pr_set_child_subreaper", UM_pr_set_child_subreaper, 1);
|
|
1439
|
+
|
|
1440
|
+
|
|
1290
1441
|
rb_define_method(cUM, "initialize", UM_initialize, -1);
|
|
1291
1442
|
rb_define_method(cUM, "size", UM_size, 0);
|
|
1292
1443
|
rb_define_method(cUM, "mark", UM_mark_m, 1);
|
|
@@ -1302,19 +1453,6 @@ void Init_UM(void) {
|
|
|
1302
1453
|
|
|
1303
1454
|
rb_define_method(cUM, "setup_buffer_ring", UM_setup_buffer_ring, 2);
|
|
1304
1455
|
|
|
1305
|
-
rb_define_singleton_method(cUM, "pipe", UM_pipe, 0);
|
|
1306
|
-
rb_define_singleton_method(cUM, "socketpair", UM_socketpair, 3);
|
|
1307
|
-
rb_define_singleton_method(cUM, "pidfd_open", UM_pidfd_open, 1);
|
|
1308
|
-
rb_define_singleton_method(cUM, "pidfd_send_signal", UM_pidfd_send_signal, 2);
|
|
1309
|
-
|
|
1310
|
-
rb_define_singleton_method(cUM, "io_nonblock?", UM_io_nonblock_p, 1);
|
|
1311
|
-
rb_define_singleton_method(cUM, "io_set_nonblock", UM_io_set_nonblock, 2);
|
|
1312
|
-
rb_define_singleton_method(cUM, "kernel_version", UM_kernel_version, 0);
|
|
1313
|
-
rb_define_singleton_method(cUM, "debug", UM_debug, 1);
|
|
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
|
-
|
|
1318
1456
|
rb_define_method(cUM, "schedule", UM_schedule, 2);
|
|
1319
1457
|
rb_define_method(cUM, "snooze", UM_snooze, 0);
|
|
1320
1458
|
rb_define_method(cUM, "timeout", UM_timeout, 2);
|
|
@@ -1364,6 +1502,8 @@ void Init_UM(void) {
|
|
|
1364
1502
|
rb_define_method(cUM, "socket", UM_socket, 4);
|
|
1365
1503
|
rb_define_method(cUM, "shutdown", UM_shutdown, 2);
|
|
1366
1504
|
rb_define_method(cUM, "shutdown_async", UM_shutdown_async, 2);
|
|
1505
|
+
rb_define_method(cUM, "send_fd", UM_send_fd, 2);
|
|
1506
|
+
rb_define_method(cUM, "recv_fd", UM_recv_fd, 1);
|
|
1367
1507
|
|
|
1368
1508
|
rb_define_method(cUM, "prep_timeout", UM_prep_timeout, 1);
|
|
1369
1509
|
|
data/ext/um/um_op.c
CHANGED
|
@@ -18,9 +18,11 @@ const char * um_op_kind_name(enum um_op_kind kind) {
|
|
|
18
18
|
case OP_STATX: return "OP_STATX";
|
|
19
19
|
case OP_ACCEPT: return "OP_ACCEPT";
|
|
20
20
|
case OP_RECV: return "OP_RECV";
|
|
21
|
+
case OP_RECVMSG: return "OP_RECVMSG";
|
|
21
22
|
case OP_SEND: return "OP_SEND";
|
|
22
|
-
case OP_SENDV: return "OP_SENDV";
|
|
23
23
|
case OP_SEND_BUNDLE: return "OP_SEND_BUNDLE";
|
|
24
|
+
case OP_SENDMSG: return "OP_SENDMSG";
|
|
25
|
+
case OP_SENDV: return "OP_SENDV";
|
|
24
26
|
case OP_SOCKET: return "OP_SOCKET";
|
|
25
27
|
case OP_CONNECT: return "OP_CONNECT";
|
|
26
28
|
case OP_BIND: return "OP_BIND";
|
data/grant-2025/tasks.md
CHANGED
|
@@ -129,10 +129,10 @@
|
|
|
129
129
|
|
|
130
130
|
- [v] Postgres test
|
|
131
131
|
|
|
132
|
-
- [
|
|
132
|
+
- [v] Ruby Fiber::Scheduler interface
|
|
133
133
|
- [v] Make a PR for resetting the scheduler and resetting the fiber non-blocking flag.
|
|
134
134
|
- [v] hook for close
|
|
135
|
-
- [
|
|
135
|
+
- [x] hooks for send/recv/sendmsg/recvmsg (Ruby core PR pending for send/recv)
|
|
136
136
|
|
|
137
137
|
- [v] SSL
|
|
138
138
|
- [v] setup custom BIO
|
data/lib/uringmachine/version.rb
CHANGED
data/test/test_um.rb
CHANGED
|
@@ -733,7 +733,7 @@ class ReadEachTest < UMBaseTest
|
|
|
733
733
|
class TOError < StandardError; end
|
|
734
734
|
|
|
735
735
|
def test_read_each_timeout
|
|
736
|
-
r,
|
|
736
|
+
r, _w = IO.pipe
|
|
737
737
|
bgid = machine.setup_buffer_ring(4096, 1024)
|
|
738
738
|
|
|
739
739
|
bufs = []
|
|
@@ -1344,7 +1344,7 @@ class AcceptEachTest < UMBaseTest
|
|
|
1344
1344
|
def test_accept_each_closed
|
|
1345
1345
|
count = 0
|
|
1346
1346
|
done = nil
|
|
1347
|
-
|
|
1347
|
+
@machine.spin do
|
|
1348
1348
|
machine.accept_each(@server.fileno) do |fd|
|
|
1349
1349
|
count += 1
|
|
1350
1350
|
end
|
|
@@ -1816,7 +1816,7 @@ class RecvEachTest < UMBaseTest
|
|
|
1816
1816
|
|
|
1817
1817
|
def test_recv_each_timeout
|
|
1818
1818
|
t = Thread.new do
|
|
1819
|
-
|
|
1819
|
+
@server.accept
|
|
1820
1820
|
sleep
|
|
1821
1821
|
end
|
|
1822
1822
|
|
|
@@ -1847,7 +1847,7 @@ class RecvEachTest < UMBaseTest
|
|
|
1847
1847
|
|
|
1848
1848
|
def test_recv_each_shutdown
|
|
1849
1849
|
t = Thread.new do
|
|
1850
|
-
|
|
1850
|
+
@server.accept
|
|
1851
1851
|
sleep
|
|
1852
1852
|
end
|
|
1853
1853
|
|
|
@@ -1861,7 +1861,7 @@ class RecvEachTest < UMBaseTest
|
|
|
1861
1861
|
bufs = []
|
|
1862
1862
|
e = nil
|
|
1863
1863
|
|
|
1864
|
-
|
|
1864
|
+
machine.spin {
|
|
1865
1865
|
machine.sleep(0.01)
|
|
1866
1866
|
machine.shutdown(fd, UM::SHUT_RDWR)
|
|
1867
1867
|
}
|
|
@@ -1881,6 +1881,90 @@ class RecvEachTest < UMBaseTest
|
|
|
1881
1881
|
end
|
|
1882
1882
|
end
|
|
1883
1883
|
|
|
1884
|
+
class SendRecvFdTest < UMBaseTest
|
|
1885
|
+
def setup
|
|
1886
|
+
@s1_fd, @s2_fd = UM.socketpair(UM::AF_UNIX, UM::SOCK_STREAM, 0)
|
|
1887
|
+
super
|
|
1888
|
+
end
|
|
1889
|
+
|
|
1890
|
+
def teardown
|
|
1891
|
+
[@s1_fd, @s2_fd].each { machine.close(it) rescue nil }
|
|
1892
|
+
super
|
|
1893
|
+
end
|
|
1894
|
+
|
|
1895
|
+
class TOError < StandardError; end
|
|
1896
|
+
|
|
1897
|
+
def test_send_recv_fd
|
|
1898
|
+
r_fd, w_fd = UM.pipe
|
|
1899
|
+
|
|
1900
|
+
res = machine.send_fd(@s1_fd, w_fd)
|
|
1901
|
+
assert_equal w_fd, res
|
|
1902
|
+
|
|
1903
|
+
fd = machine.recv_fd(@s2_fd)
|
|
1904
|
+
assert_kind_of Integer, fd
|
|
1905
|
+
refute_equal w_fd, fd
|
|
1906
|
+
|
|
1907
|
+
machine.close(w_fd)
|
|
1908
|
+
machine.write(fd, 'foobar')
|
|
1909
|
+
machine.close(fd)
|
|
1910
|
+
|
|
1911
|
+
buf = +''
|
|
1912
|
+
res = machine.read(r_fd, buf, 12)
|
|
1913
|
+
assert_equal 6, res
|
|
1914
|
+
assert_equal 'foobar', buf
|
|
1915
|
+
end
|
|
1916
|
+
|
|
1917
|
+
def test_send_recv_fd_fork
|
|
1918
|
+
pid = fork do
|
|
1919
|
+
m = UM.new
|
|
1920
|
+
fd = m.recv_fd(@s2_fd)
|
|
1921
|
+
m.write(fd, 'Hello!')
|
|
1922
|
+
ensure
|
|
1923
|
+
m.close(fd) rescue nil
|
|
1924
|
+
end
|
|
1925
|
+
|
|
1926
|
+
r_fd, w_fd = UM.pipe
|
|
1927
|
+
|
|
1928
|
+
res = machine.send_fd(@s1_fd, w_fd)
|
|
1929
|
+
assert_equal w_fd, res
|
|
1930
|
+
Process.wait(pid)
|
|
1931
|
+
pid = nil
|
|
1932
|
+
machine.close(w_fd)
|
|
1933
|
+
|
|
1934
|
+
buf = +''
|
|
1935
|
+
len = machine.timeout(1, TOError) { machine.read(r_fd, buf, 12) }
|
|
1936
|
+
assert_equal 6, len
|
|
1937
|
+
assert_equal 'Hello!', buf
|
|
1938
|
+
ensure
|
|
1939
|
+
if pid
|
|
1940
|
+
Process.kill('KILL', pid) rescue nil
|
|
1941
|
+
Process.wait(pid) rescue nil
|
|
1942
|
+
end
|
|
1943
|
+
machine.close(r_fd) rescue nil
|
|
1944
|
+
machine.close(w_fd) rescue nil
|
|
1945
|
+
end
|
|
1946
|
+
|
|
1947
|
+
def test_send_fd_bad_sock_fd
|
|
1948
|
+
_r_fd, w_fd = UM.pipe
|
|
1949
|
+
assert_raises(Errno::ENOTSOCK) { machine.send_fd(0, w_fd) }
|
|
1950
|
+
end
|
|
1951
|
+
|
|
1952
|
+
def test_send_fd_bad_fd
|
|
1953
|
+
assert_raises(TypeError) { machine.send_fd(@s1_fd, nil) }
|
|
1954
|
+
assert_raises(Errno::EBADF) { machine.send_fd(@s1_fd, 1111) }
|
|
1955
|
+
end
|
|
1956
|
+
|
|
1957
|
+
def test_recv_fd_bad_msg
|
|
1958
|
+
buf = "\0" * 1000
|
|
1959
|
+
machine.write(@s1_fd, buf)
|
|
1960
|
+
|
|
1961
|
+
assert_raises(Errno::EINVAL) {
|
|
1962
|
+
res = machine.recv_fd(@s2_fd)
|
|
1963
|
+
p res: res
|
|
1964
|
+
}
|
|
1965
|
+
end
|
|
1966
|
+
end
|
|
1967
|
+
|
|
1884
1968
|
class BindTest < UMBaseTest
|
|
1885
1969
|
def setup
|
|
1886
1970
|
super
|
|
@@ -2836,23 +2920,6 @@ class SendBundleTest < UMBaseTest
|
|
|
2836
2920
|
end
|
|
2837
2921
|
end
|
|
2838
2922
|
|
|
2839
|
-
class NonBlockTest < UMBaseTest
|
|
2840
|
-
def test_io_nonblock?
|
|
2841
|
-
assert_equal false, UM.io_nonblock?(STDIN)
|
|
2842
|
-
end
|
|
2843
|
-
|
|
2844
|
-
def test_io_set_nonblock
|
|
2845
|
-
r, _w = IO.pipe
|
|
2846
|
-
assert_equal true, UM.io_nonblock?(r)
|
|
2847
|
-
|
|
2848
|
-
UM.io_set_nonblock(r, false)
|
|
2849
|
-
assert_equal false, UM.io_nonblock?(r)
|
|
2850
|
-
|
|
2851
|
-
UM.io_set_nonblock(r, true)
|
|
2852
|
-
assert_equal true, UM.io_nonblock?(r)
|
|
2853
|
-
end
|
|
2854
|
-
end
|
|
2855
|
-
|
|
2856
2923
|
class MetricsTest < UMBaseTest
|
|
2857
2924
|
def test_metrics_empty
|
|
2858
2925
|
assert_equal({
|
|
@@ -3159,3 +3226,39 @@ class FileWatchTest < UMBaseTest
|
|
|
3159
3226
|
machine.join(f)
|
|
3160
3227
|
end
|
|
3161
3228
|
end
|
|
3229
|
+
|
|
3230
|
+
class SetChildSubreaperTest < Minitest::Test
|
|
3231
|
+
def test_pr_set_child_subreaper
|
|
3232
|
+
r, w = IO.pipe
|
|
3233
|
+
UM.pr_set_child_subreaper(true)
|
|
3234
|
+
|
|
3235
|
+
child_pid = fork {
|
|
3236
|
+
r2, w2 = IO.pipe
|
|
3237
|
+
pid = fork {
|
|
3238
|
+
r.close
|
|
3239
|
+
w.close
|
|
3240
|
+
w2.close
|
|
3241
|
+
r2.read
|
|
3242
|
+
r2.close
|
|
3243
|
+
sleep(0.01)
|
|
3244
|
+
}
|
|
3245
|
+
w << pid
|
|
3246
|
+
w.close
|
|
3247
|
+
r2.close
|
|
3248
|
+
w2 << 'done'
|
|
3249
|
+
w2.close
|
|
3250
|
+
}
|
|
3251
|
+
Process.wait(child_pid)
|
|
3252
|
+
|
|
3253
|
+
w.close
|
|
3254
|
+
msg = r.read
|
|
3255
|
+
r.close
|
|
3256
|
+
|
|
3257
|
+
refute msg.empty?
|
|
3258
|
+
grand_child_pid = msg.to_i
|
|
3259
|
+
refute_equal 0, grand_child_pid
|
|
3260
|
+
|
|
3261
|
+
res = Process.wait(grand_child_pid)
|
|
3262
|
+
assert_equal grand_child_pid, res
|
|
3263
|
+
end
|
|
3264
|
+
end
|