uringmachine 0.25.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.
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,
@@ -73,20 +75,31 @@ enum um_op_kind {
73
75
  OP_READ_MULTISHOT,
74
76
  OP_RECV_MULTISHOT,
75
77
  OP_TIMEOUT_MULTISHOT,
76
- OP_SLEEP_MULTISHOT
77
78
  };
78
79
 
79
- #define OP_F_COMPLETED (1U << 0) // op is completed (set on each CQE for multishot ops)
80
- #define OP_F_TRANSIENT (1U << 1) // op is heap allocated
81
- #define OP_F_ASYNC (1U << 2) // op belongs to an AsyncOp
82
- #define OP_F_CANCELED (1U << 3) // op is cancelled
83
- #define OP_F_IGNORE_CANCELED (1U << 4) // CQE with -ECANCEL should be ignored
84
- #define OP_F_MULTISHOT (1U << 5) // op is multishot
85
- #define OP_F_FREE_ON_COMPLETE (1U << 6) // op should be freed on receiving CQE
86
- #define OP_F_RUNQUEUE_SKIP (1U << 7) // runqueue entry should be skipped
87
- #define OP_F_SELECT_POLLIN (1U << 8) // select POLLIN
88
- #define OP_F_SELECT_POLLOUT (1U << 9) // select POLLOUT
89
- #define OP_F_SELECT_POLLPRI (1U << 10) // select POLLPRI
80
+
81
+ #define OP_F_CQE_SEEN (1U << 0) // CQE has been seen
82
+ #define OP_F_CQE_DONE (1U << 1) // CQE has been seen and operation is done
83
+ #define OP_F_SCHEDULED (1U << 2) // op is on runqueue
84
+ #define OP_F_CANCELED (1U << 3) // op is cancelled (disregard CQE results)
85
+ #define OP_F_MULTISHOT (1U << 4) // op is multishot
86
+ #define OP_F_ASYNC (1U << 5) // op is async (no fiber is scheduled to be resumed on completion)
87
+ #define OP_F_TRANSIENT (1U << 6) // op is on transient list (for GC purposes)
88
+ #define OP_F_FREE_IOVECS (1U << 7) // op->iovecs should be freed on release
89
+ #define OP_F_SKIP (1U << 8) // op should be skipped when pulled from runqueue
90
+
91
+ #define OP_F_SELECT_POLLIN (1U << 13) // select POLLIN
92
+ #define OP_F_SELECT_POLLOUT (1U << 14) // select POLLOUT
93
+ #define OP_F_SELECT_POLLPRI (1U << 15) // select POLLPRI
94
+
95
+ #define OP_CQE_SEEN_P(op) ((op)->flags & OP_F_CQE_SEEN)
96
+ #define OP_CQE_DONE_P(op) ((op)->flags & OP_F_CQE_DONE)
97
+ #define OP_SCHEDULED_P(op) ((op)->flags & OP_F_SCHEDULED)
98
+ #define OP_CANCELED_P(op) ((op)->flags & OP_F_CANCELED)
99
+ #define OP_MULTISHOT_P(op) ((op)->flags & OP_F_MULTISHOT)
100
+ #define OP_ASYNC_P(op) ((op)->flags & OP_F_ASYNC)
101
+ #define OP_TRANSIENT_P(op) ((op)->flags & OP_F_TRANSIENT)
102
+ #define OP_SKIP_P(op) ((op)->flags & OP_F_SKIP)
90
103
 
91
104
  struct um_op_result {
92
105
  __s32 res;
@@ -100,6 +113,7 @@ struct um_op {
100
113
 
101
114
  enum um_op_kind kind;
102
115
  uint flags;
116
+ uint ref_count;
103
117
 
104
118
  VALUE fiber;
105
119
  VALUE value;
@@ -109,7 +123,12 @@ struct um_op {
109
123
  struct um_op_result *multishot_result_tail;
110
124
  uint multishot_result_count;
111
125
 
112
- struct __kernel_timespec ts; // used for timeout operation
126
+ union {
127
+ struct __kernel_timespec ts; // used for timeout operation
128
+ struct iovec *iovecs; // used for vectorized write/send
129
+ siginfo_t siginfo; // used for waitid
130
+ int int_value; // used for getsockopt
131
+ };
113
132
  };
114
133
 
115
134
  struct um_buffer {
@@ -237,8 +256,12 @@ void um_teardown(struct um *machine);
237
256
  VALUE um_metrics(struct um *machine, struct um_metrics *metrics);
238
257
 
239
258
  const char * um_op_kind_name(enum um_op_kind kind);
240
- struct um_op *um_op_alloc(struct um *machine);
241
- void um_op_free(struct um *machine, struct um_op *op);
259
+
260
+ struct um_op *um_op_acquire(struct um *machine);
261
+ void um_op_release(struct um *machine, struct um_op *op);
262
+
263
+ // struct um_op *um_op_alloc(struct um *machine);
264
+ // void um_op_free(struct um *machine, struct um_op *op);
242
265
  void um_op_clear(struct um *machine, struct um_op *op);
243
266
  void um_op_transient_add(struct um *machine, struct um_op *op);
244
267
  void um_op_transient_remove(struct um *machine, struct um_op *op);
@@ -264,9 +287,9 @@ VALUE um_raise_exception(VALUE v);
264
287
 
265
288
  #define RAISE_IF_EXCEPTION(v) if (unlikely(um_value_is_exception_p(v))) { um_raise_exception(v); }
266
289
 
267
- void um_prep_op(struct um *machine, struct um_op *op, enum um_op_kind kind, unsigned flags);
290
+ void um_prep_op(struct um *machine, struct um_op *op, enum um_op_kind kind, uint ref_count, unsigned flags);
268
291
  void um_raise_on_error_result(int result);
269
- void um_get_buffer_bytes_for_writing(VALUE buffer, const void **base, size_t *size);
292
+ int um_get_buffer_bytes_for_writing(VALUE buffer, const void **base, size_t *size, int raise_on_bad_buffer);
270
293
  void * um_prepare_read_buffer(VALUE buffer, ssize_t len, ssize_t ofs);
271
294
  void um_update_read_buffer(VALUE buffer, ssize_t buffer_offset, __s32 result);
272
295
  int um_setup_buffer_ring(struct um *machine, unsigned size, unsigned count);
@@ -283,10 +306,9 @@ VALUE um_yield(struct um *machine);
283
306
  VALUE um_switch(struct um *machine);
284
307
  VALUE um_wakeup(struct um *machine);
285
308
  void um_cancel_op(struct um *machine, struct um_op *op);
286
- void um_cancel_and_wait(struct um *machine, struct um_op *op);
287
- int um_check_completion(struct um *machine, struct um_op *op);
288
-
289
- #define um_op_completed_p(op) ((op)->flags & OP_F_COMPLETED)
309
+ void um_cancel_op_and_discard_cqe(struct um *machine, struct um_op *op);
310
+ void um_cancel_op_and_await_cqe(struct um *machine, struct um_op *op);
311
+ int um_verify_op_completion(struct um *machine, struct um_op *op, int await_cancelled);
290
312
 
291
313
  void um_schedule(struct um *machine, VALUE fiber, VALUE value);
292
314
  VALUE um_timeout(struct um *machine, VALUE interval, VALUE class);
@@ -329,6 +351,8 @@ VALUE um_getsockopt(struct um *machine, int fd, int level, int opt);
329
351
  VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value);
330
352
  VALUE um_shutdown(struct um *machine, int fd, int how);
331
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);
332
356
 
333
357
  void um_async_op_set(VALUE self, struct um *machine, struct um_op *op);
334
358
  VALUE um_async_op_await(struct um_async_op *async_op);
data/ext/um/um_async_op.c CHANGED
@@ -5,11 +5,11 @@ VALUE um_prep_timeout(struct um *machine, double interval) {
5
5
  static ID ID_new = 0;
6
6
  if (!ID_new) ID_new = rb_intern("new");
7
7
 
8
- struct um_op *op = malloc(sizeof(struct um_op));
9
- um_prep_op(machine, op, OP_TIMEOUT, OP_F_TRANSIENT | OP_F_ASYNC);
8
+ struct um_op *op = um_op_acquire(machine);
9
+ um_prep_op(machine, op, OP_TIMEOUT, 2, OP_F_ASYNC | OP_F_TRANSIENT);
10
10
  op->ts = um_double_to_timespec(interval);
11
11
 
12
- VALUE obj = rb_funcall(cAsyncOp, rb_intern_const("new"), 0);
12
+ VALUE obj = rb_funcall(cAsyncOp, ID_new, 0);
13
13
  um_async_op_set(obj, machine, op);
14
14
 
15
15
  RB_OBJ_WRITE(machine->self, &op->async_op, obj);
@@ -17,18 +17,19 @@ VALUE um_prep_timeout(struct um *machine, double interval) {
17
17
  struct io_uring_sqe *sqe = um_get_sqe(machine, op);
18
18
  io_uring_prep_timeout(sqe, &op->ts, 0, 0);
19
19
 
20
- um_op_transient_add(machine, op);
21
-
22
20
  return obj;
23
21
  }
24
22
 
25
23
  VALUE um_async_op_await(struct um_async_op *async_op) {
24
+ if (OP_CQE_DONE_P(async_op->op)) return async_op->op->value;
25
+
26
26
  RB_OBJ_WRITE(async_op->machine->self, &async_op->op->fiber, rb_fiber_current());
27
- async_op->op->flags &= ~OP_F_ASYNC;
27
+ um_op_transient_remove(async_op->machine, async_op->op);
28
+ async_op->op->flags &= ~(OP_F_ASYNC | OP_F_TRANSIENT);
28
29
 
29
30
  VALUE ret = um_switch(async_op->machine);
30
- if (!um_op_completed_p(async_op->op))
31
- um_cancel_and_wait(async_op->machine, async_op->op);
31
+
32
+ um_verify_op_completion(async_op->machine, async_op->op, true);
32
33
 
33
34
  RAISE_IF_EXCEPTION(ret);
34
35
  RB_GC_GUARD(ret);
@@ -19,8 +19,8 @@ static void AsyncOp_mark(void *ptr) {
19
19
 
20
20
  static void AsyncOp_free(void *ptr) {
21
21
  struct um_async_op *async_op = ptr;
22
- if (async_op->op)
23
- um_op_free(async_op->machine, async_op->op);
22
+ if (likely(async_op->op))
23
+ um_op_release(async_op->machine, async_op->op);
24
24
  }
25
25
 
26
26
  static const rb_data_type_t AsyncOp_type = {
@@ -63,7 +63,7 @@ inline void raise_on_missing_op(struct um_async_op *async_op) {
63
63
  }
64
64
 
65
65
  inline int async_op_is_done(struct um_async_op *async_op) {
66
- return (async_op->op->flags & OP_F_COMPLETED);
66
+ return OP_CQE_DONE_P(async_op->op);
67
67
  }
68
68
 
69
69
  /* Returns the kind of asynchronous operation.