uringmachine 0.5 → 0.6
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/.github/workflows/test.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/TODO.md +4 -0
- data/examples/bm_http_parse.rb +149 -0
- data/examples/bm_queue.rb +111 -0
- data/examples/bm_sqlite.rb +89 -0
- data/examples/http_server.rb +1 -1
- data/examples/pg.rb +85 -0
- data/examples/stream.rb +85 -0
- data/ext/um/extconf.rb +57 -0
- data/ext/um/um.c +75 -4
- data/ext/um/um.h +29 -7
- data/ext/um/um_async_op.c +40 -0
- data/ext/um/um_async_op_class.c +136 -0
- data/ext/um/um_class.c +45 -31
- data/ext/um/um_const.c +145 -9
- data/ext/um/um_ext.c +4 -0
- data/ext/um/um_op.c +5 -2
- data/ext/um/um_ssl.c +850 -0
- data/ext/um/um_ssl.h +22 -0
- data/ext/um/um_ssl_class.c +138 -0
- data/lib/uringmachine/actor.rb +52 -0
- data/lib/uringmachine/ssl/context_builder.rb +96 -0
- data/lib/uringmachine/ssl.rb +394 -0
- data/lib/uringmachine/version.rb +1 -1
- data/lib/uringmachine.rb +10 -2
- data/test/helper.rb +6 -0
- data/test/test_actor.rb +63 -0
- data/test/test_async_op.rb +119 -0
- data/test/test_ssl.rb +155 -0
- data/test/test_um.rb +71 -2
- data/uringmachine.gemspec +4 -3
- metadata +39 -13
    
        data/ext/um/um.c
    CHANGED
    
    | @@ -5,7 +5,6 @@ void um_setup(VALUE self, struct um *machine) { | |
| 5 5 | 
             
              memset(machine, 0, sizeof(struct um));
         | 
| 6 6 |  | 
| 7 7 | 
             
              RB_OBJ_WRITE(self, &machine->self, self);
         | 
| 8 | 
            -
              RB_OBJ_WRITE(self, &machine->poll_fiber, Qnil);
         | 
| 9 8 |  | 
| 10 9 | 
             
              unsigned prepared_limit = 4096;
         | 
| 11 10 | 
             
              unsigned flags = IORING_SETUP_SUBMIT_ALL | IORING_SETUP_COOP_TASKRUN;
         | 
| @@ -76,7 +75,7 @@ static inline void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe) | |
| 76 75 | 
             
              if (unlikely((cqe->res == -ECANCELED) && (op->flags & OP_F_IGNORE_CANCELED))) return;
         | 
| 77 76 |  | 
| 78 77 | 
             
              op->flags |= OP_F_COMPLETED;
         | 
| 79 | 
            -
              if ( | 
| 78 | 
            +
              if (op->flags & OP_F_TRANSIENT)
         | 
| 80 79 | 
             
                um_op_transient_remove(machine, op);
         | 
| 81 80 |  | 
| 82 81 | 
             
              if (op->flags & OP_F_MULTISHOT) {
         | 
| @@ -89,6 +88,8 @@ static inline void um_process_cqe(struct um *machine, struct io_uring_cqe *cqe) | |
| 89 88 | 
             
                op->result.flags  = cqe->flags;
         | 
| 90 89 | 
             
              }
         | 
| 91 90 |  | 
| 91 | 
            +
              if (op->flags & OP_F_ASYNC) return;
         | 
| 92 | 
            +
              
         | 
| 92 93 | 
             
              um_runqueue_push(machine, op);
         | 
| 93 94 | 
             
            }
         | 
| 94 95 |  | 
| @@ -181,7 +182,7 @@ inline VALUE um_fiber_switch(struct um *machine) { | |
| 181 182 | 
             
              }
         | 
| 182 183 | 
             
            }
         | 
| 183 184 |  | 
| 184 | 
            -
             | 
| 185 | 
            +
            void um_submit_cancel_op(struct um *machine, struct um_op *op) {
         | 
| 185 186 | 
             
              struct io_uring_sqe *sqe = um_get_sqe(machine, NULL);
         | 
| 186 187 | 
             
              io_uring_prep_cancel64(sqe, (long long)op, 0);
         | 
| 187 188 | 
             
            }
         | 
| @@ -216,6 +217,8 @@ inline void um_prep_op(struct um *machine, struct um_op *op, enum op_kind kind) | |
| 216 217 | 
             
                case OP_ACCEPT_MULTISHOT:
         | 
| 217 218 | 
             
                case OP_READ_MULTISHOT:
         | 
| 218 219 | 
             
                case OP_RECV_MULTISHOT:
         | 
| 220 | 
            +
                case OP_TIMEOUT_MULTISHOT:
         | 
| 221 | 
            +
                case OP_SLEEP_MULTISHOT:
         | 
| 219 222 | 
             
                  op->flags |= OP_F_MULTISHOT;
         | 
| 220 223 | 
             
                default:
         | 
| 221 224 | 
             
              }
         | 
| @@ -261,7 +264,7 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) { | |
| 261 264 | 
             
              static ID ID_new = 0;
         | 
| 262 265 | 
             
              if (!ID_new) ID_new = rb_intern("new");
         | 
| 263 266 |  | 
| 264 | 
            -
              struct um_op *op =  | 
| 267 | 
            +
              struct um_op *op = um_op_alloc(machine);
         | 
| 265 268 | 
             
              um_prep_op(machine, op, OP_TIMEOUT);
         | 
| 266 269 | 
             
              op->ts = um_double_to_timespec(NUM2DBL(interval));
         | 
| 267 270 | 
             
              RB_OBJ_WRITE(machine->self, &op->fiber, rb_fiber_current());
         | 
| @@ -297,6 +300,33 @@ VALUE um_sleep(struct um *machine, double duration) { | |
| 297 300 | 
             
              return raise_if_exception(ret);
         | 
| 298 301 | 
             
            }
         | 
| 299 302 |  | 
| 303 | 
            +
            // VALUE um_periodically(struct um *machine, double interval) {
         | 
| 304 | 
            +
            //   struct um_op op;
         | 
| 305 | 
            +
            //   VALUE ret = Qnil;
         | 
| 306 | 
            +
            //   um_prep_op(machine, &op, OP_SLEEP_MULTISHOT);
         | 
| 307 | 
            +
            //   op.ts = um_double_to_timespec(interval);
         | 
| 308 | 
            +
            //   op.flags |= OP_F_MULTISHOT;
         | 
| 309 | 
            +
            //   struct io_uring_sqe *sqe = um_get_sqe(machine, &op);
         | 
| 310 | 
            +
            //   io_uring_prep_timeout(sqe, &op.ts, 0, IORING_TIMEOUT_MULTISHOT);
         | 
| 311 | 
            +
             | 
| 312 | 
            +
            //   while (true) {
         | 
| 313 | 
            +
            //     ret = um_fiber_switch(machine);
         | 
| 314 | 
            +
             | 
| 315 | 
            +
            //     if (!um_op_completed_p(&op)) {
         | 
| 316 | 
            +
            //       um_cancel_and_wait(machine, &op);
         | 
| 317 | 
            +
            //       break;
         | 
| 318 | 
            +
            //     }
         | 
| 319 | 
            +
            //     else {
         | 
| 320 | 
            +
            //       if (op.result.res != -ETIME) um_raise_on_error_result(op.result.res);
         | 
| 321 | 
            +
            //       ret = DBL2NUM(interval);
         | 
| 322 | 
            +
            //     }
         | 
| 323 | 
            +
            //   }
         | 
| 324 | 
            +
             | 
| 325 | 
            +
            //   RB_GC_GUARD(ret);
         | 
| 326 | 
            +
            //   return raise_if_exception(ret);
         | 
| 327 | 
            +
             | 
| 328 | 
            +
            // }
         | 
| 329 | 
            +
             | 
| 300 330 | 
             
            inline VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset) {
         | 
| 301 331 | 
             
              struct um_op op;
         | 
| 302 332 | 
             
              um_prep_op(machine, &op, OP_READ);
         | 
| @@ -701,3 +731,44 @@ VALUE um_recv_each(struct um *machine, int fd, int bgid, int flags) { | |
| 701 731 | 
             
              struct op_ctx ctx = { .machine = machine, .op = &op, .fd = fd, .bgid = bgid, .read_buf = NULL, .flags = flags };
         | 
| 702 732 | 
             
              return rb_ensure(read_recv_each_begin, (VALUE)&ctx, multishot_ensure, (VALUE)&ctx);
         | 
| 703 733 | 
             
            }
         | 
| 734 | 
            +
             | 
| 735 | 
            +
            VALUE periodically_begin(VALUE arg) {
         | 
| 736 | 
            +
              struct op_ctx *ctx = (struct op_ctx *)arg;
         | 
| 737 | 
            +
              struct io_uring_sqe *sqe = um_get_sqe(ctx->machine, ctx->op);
         | 
| 738 | 
            +
              io_uring_prep_timeout(sqe, &ctx->ts, 0, IORING_TIMEOUT_MULTISHOT);
         | 
| 739 | 
            +
             | 
| 740 | 
            +
              while (true) {
         | 
| 741 | 
            +
                VALUE ret = um_fiber_switch(ctx->machine);
         | 
| 742 | 
            +
                if (!um_op_completed_p(ctx->op))
         | 
| 743 | 
            +
                  return raise_if_exception(ret);
         | 
| 744 | 
            +
             | 
| 745 | 
            +
                int more = false;
         | 
| 746 | 
            +
                struct um_op_result *result = &ctx->op->result;
         | 
| 747 | 
            +
                while (result) {
         | 
| 748 | 
            +
                  more = (result->flags & IORING_CQE_F_MORE);
         | 
| 749 | 
            +
                  if (result->res < 0 && result->res != -ETIME) {
         | 
| 750 | 
            +
                    um_op_multishot_results_clear(ctx->machine, ctx->op);
         | 
| 751 | 
            +
                    return Qnil;
         | 
| 752 | 
            +
                  }
         | 
| 753 | 
            +
                  rb_yield(Qnil);
         | 
| 754 | 
            +
                  result = result->next;
         | 
| 755 | 
            +
                }
         | 
| 756 | 
            +
                um_op_multishot_results_clear(ctx->machine, ctx->op);
         | 
| 757 | 
            +
                if (more)
         | 
| 758 | 
            +
                  ctx->op->flags &= ~OP_F_COMPLETED;
         | 
| 759 | 
            +
                else
         | 
| 760 | 
            +
                  break;
         | 
| 761 | 
            +
              }
         | 
| 762 | 
            +
             | 
| 763 | 
            +
              return Qnil;
         | 
| 764 | 
            +
            }
         | 
| 765 | 
            +
             | 
| 766 | 
            +
            VALUE um_periodically(struct um *machine, double interval) {
         | 
| 767 | 
            +
              struct um_op op;
         | 
| 768 | 
            +
              um_prep_op(machine, &op, OP_SLEEP_MULTISHOT);
         | 
| 769 | 
            +
              op.ts = um_double_to_timespec(interval);
         | 
| 770 | 
            +
              
         | 
| 771 | 
            +
              struct op_ctx ctx = { .machine = machine, .op = &op, .ts = op.ts, .read_buf = NULL };
         | 
| 772 | 
            +
              return rb_ensure(periodically_begin, (VALUE)&ctx, multishot_ensure, (VALUE)&ctx);
         | 
| 773 | 
            +
            }
         | 
| 774 | 
            +
             | 
    
        data/ext/um/um.h
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            #ifndef UM_H
         | 
| 2 2 | 
             
            #define UM_H
         | 
| 3 3 |  | 
| 4 | 
            -
            #include  | 
| 4 | 
            +
            #include <ruby.h>
         | 
| 5 5 | 
             
            #include <liburing.h>
         | 
| 6 6 |  | 
| 7 7 | 
             
            // debugging
         | 
| @@ -43,13 +43,16 @@ enum op_kind { | |
| 43 43 |  | 
| 44 44 | 
             
              OP_ACCEPT_MULTISHOT,
         | 
| 45 45 | 
             
              OP_READ_MULTISHOT,
         | 
| 46 | 
            -
              OP_RECV_MULTISHOT
         | 
| 46 | 
            +
              OP_RECV_MULTISHOT,
         | 
| 47 | 
            +
              OP_TIMEOUT_MULTISHOT,
         | 
| 48 | 
            +
              OP_SLEEP_MULTISHOT
         | 
| 47 49 | 
             
            };
         | 
| 48 50 |  | 
| 49 | 
            -
            #define OP_F_COMPLETED        (1U << 0)
         | 
| 50 | 
            -
            #define OP_F_TRANSIENT        (1U << 1)
         | 
| 51 | 
            -
            #define  | 
| 52 | 
            -
            #define  | 
| 51 | 
            +
            #define OP_F_COMPLETED        (1U << 0) // op is completed (set on each CQE for multishot ops)
         | 
| 52 | 
            +
            #define OP_F_TRANSIENT        (1U << 1) // op is heap allocated
         | 
| 53 | 
            +
            #define OP_F_ASYNC            (1U << 2) // op belongs to an AsyncOp
         | 
| 54 | 
            +
            #define OP_F_IGNORE_CANCELED  (1U << 3) // CQE with -ECANCEL should be ignored
         | 
| 55 | 
            +
            #define OP_F_MULTISHOT        (1U << 4) // op is multishot
         | 
| 53 56 |  | 
| 54 57 | 
             
            struct um_op_result {
         | 
| 55 58 | 
             
              __s32 res;
         | 
| @@ -66,6 +69,7 @@ struct um_op { | |
| 66 69 |  | 
| 67 70 | 
             
              VALUE fiber;
         | 
| 68 71 | 
             
              VALUE value;
         | 
| 72 | 
            +
              VALUE async_op;
         | 
| 69 73 |  | 
| 70 74 | 
             
              struct um_op_result result;
         | 
| 71 75 | 
             
              struct um_op_result *multishot_result_tail;
         | 
| @@ -93,7 +97,6 @@ struct buf_ring_descriptor { | |
| 93 97 |  | 
| 94 98 | 
             
            struct um {
         | 
| 95 99 | 
             
              VALUE self;
         | 
| 96 | 
            -
              VALUE poll_fiber;
         | 
| 97 100 |  | 
| 98 101 | 
             
              struct um_buffer *buffer_freelist;
         | 
| 99 102 |  | 
| @@ -137,10 +140,19 @@ struct um_queue { | |
| 137 140 | 
             
              uint32_t count;
         | 
| 138 141 | 
             
            };
         | 
| 139 142 |  | 
| 143 | 
            +
            struct um_async_op {
         | 
| 144 | 
            +
              VALUE self;
         | 
| 145 | 
            +
             | 
| 146 | 
            +
              struct um *machine;
         | 
| 147 | 
            +
              struct um_op *op;
         | 
| 148 | 
            +
            };
         | 
| 149 | 
            +
             | 
| 140 150 | 
             
            extern VALUE cUM;
         | 
| 141 151 | 
             
            extern VALUE cMutex;
         | 
| 142 152 | 
             
            extern VALUE cQueue;
         | 
| 153 | 
            +
            extern VALUE cAsyncOp;
         | 
| 143 154 |  | 
| 155 | 
            +
            struct um *um_get_machine(VALUE self);
         | 
| 144 156 | 
             
            void um_setup(VALUE self, struct um *machine);
         | 
| 145 157 | 
             
            void um_teardown(struct um *machine);
         | 
| 146 158 |  | 
| @@ -179,6 +191,7 @@ struct io_uring_sqe *um_get_sqe(struct um *machine, struct um_op *op); | |
| 179 191 |  | 
| 180 192 | 
             
            VALUE um_fiber_switch(struct um *machine);
         | 
| 181 193 | 
             
            VALUE um_await(struct um *machine);
         | 
| 194 | 
            +
            void um_submit_cancel_op(struct um *machine, struct um_op *op);
         | 
| 182 195 | 
             
            void um_cancel_and_wait(struct um *machine, struct um_op *op);
         | 
| 183 196 | 
             
            int um_check_completion(struct um *machine, struct um_op *op);
         | 
| 184 197 |  | 
| @@ -188,6 +201,7 @@ void um_schedule(struct um *machine, VALUE fiber, VALUE value); | |
| 188 201 | 
             
            VALUE um_timeout(struct um *machine, VALUE interval, VALUE class);
         | 
| 189 202 |  | 
| 190 203 | 
             
            VALUE um_sleep(struct um *machine, double duration);
         | 
| 204 | 
            +
            VALUE um_periodically(struct um *machine, double interval);
         | 
| 191 205 | 
             
            VALUE um_read(struct um *machine, int fd, VALUE buffer, int maxlen, int buffer_offset);
         | 
| 192 206 | 
             
            VALUE um_read_each(struct um *machine, int fd, int bgid);
         | 
| 193 207 | 
             
            VALUE um_write(struct um *machine, int fd, VALUE str, int len);
         | 
| @@ -207,6 +221,12 @@ VALUE um_listen(struct um *machine, int fd, int backlog); | |
| 207 221 | 
             
            VALUE um_getsockopt(struct um *machine, int fd, int level, int opt);
         | 
| 208 222 | 
             
            VALUE um_setsockopt(struct um *machine, int fd, int level, int opt, int value);
         | 
| 209 223 |  | 
| 224 | 
            +
            void um_async_op_set(VALUE self, struct um *machine, struct um_op *op);
         | 
| 225 | 
            +
            VALUE um_async_op_await(struct um_async_op *async_op);
         | 
| 226 | 
            +
            void um_async_op_cancel(struct um_async_op *async_op);
         | 
| 227 | 
            +
             | 
| 228 | 
            +
            VALUE um_prep_timeout(struct um *machine, double interval);
         | 
| 229 | 
            +
             | 
| 210 230 | 
             
            struct um_mutex *Mutex_data(VALUE self);
         | 
| 211 231 | 
             
            struct um_queue *Queue_data(VALUE self);
         | 
| 212 232 |  | 
| @@ -224,4 +244,6 @@ VALUE um_queue_shift(struct um *machine, struct um_queue *queue); | |
| 224 244 |  | 
| 225 245 | 
             
            void um_define_net_constants(VALUE mod);
         | 
| 226 246 |  | 
| 247 | 
            +
            // void Init_micro_ssl(VALUE mod);
         | 
| 248 | 
            +
             | 
| 227 249 | 
             
            #endif // UM_H
         | 
| @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            #include "um.h"
         | 
| 2 | 
            +
            #include <stdlib.h>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            VALUE um_prep_timeout(struct um *machine, double interval) {
         | 
| 5 | 
            +
              static ID ID_new = 0;
         | 
| 6 | 
            +
              if (!ID_new) ID_new = rb_intern("new");
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              struct um_op *op = malloc(sizeof(struct um_op));
         | 
| 9 | 
            +
              um_prep_op(machine, op, OP_TIMEOUT);
         | 
| 10 | 
            +
              op->ts = um_double_to_timespec(interval);
         | 
| 11 | 
            +
              op->flags = OP_F_TRANSIENT | OP_F_ASYNC;
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              VALUE obj = rb_funcall(cAsyncOp, rb_intern_const("new"), 0);
         | 
| 14 | 
            +
              um_async_op_set(obj, machine, op);
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              RB_OBJ_WRITE(machine->self, &op->async_op, obj);
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              struct io_uring_sqe *sqe = um_get_sqe(machine, op);
         | 
| 19 | 
            +
              io_uring_prep_timeout(sqe, &op->ts, 0, 0);
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              um_op_transient_add(machine, op);
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              return obj;
         | 
| 24 | 
            +
            }
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            VALUE um_async_op_await(struct um_async_op *async_op) {
         | 
| 27 | 
            +
              RB_OBJ_WRITE(async_op->machine->self, &async_op->op->fiber, rb_fiber_current());
         | 
| 28 | 
            +
              async_op->op->flags &= ~OP_F_ASYNC;
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              VALUE ret = um_fiber_switch(async_op->machine);
         | 
| 31 | 
            +
              if (!um_op_completed_p(async_op->op))
         | 
| 32 | 
            +
                um_cancel_and_wait(async_op->machine, async_op->op);
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              raise_if_exception(ret);
         | 
| 35 | 
            +
              return INT2NUM(async_op->op->result.res);
         | 
| 36 | 
            +
            }
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            void um_async_op_cancel(struct um_async_op *async_op) {
         | 
| 39 | 
            +
              um_submit_cancel_op(async_op->machine, async_op->op);
         | 
| 40 | 
            +
            }
         | 
| @@ -0,0 +1,136 @@ | |
| 1 | 
            +
            #include "um.h"
         | 
| 2 | 
            +
            #include <stdlib.h>
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            VALUE cAsyncOp;
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            VALUE SYM_timeout;
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            static void AsyncOp_mark(void *ptr) {
         | 
| 9 | 
            +
              struct um_async_op *async_op = ptr;
         | 
| 10 | 
            +
              rb_gc_mark_movable(async_op->self);
         | 
| 11 | 
            +
              rb_gc_mark_movable(async_op->machine->self);
         | 
| 12 | 
            +
            }
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            static void AsyncOp_compact(void *ptr) {
         | 
| 15 | 
            +
              struct um_async_op *async_op = ptr;
         | 
| 16 | 
            +
              async_op->self = rb_gc_location(async_op->self);
         | 
| 17 | 
            +
            }
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            static size_t AsyncOp_size(const void *ptr) {
         | 
| 20 | 
            +
              return sizeof(struct um_async_op);
         | 
| 21 | 
            +
            }
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            static void AsyncOp_free(void *ptr) {
         | 
| 24 | 
            +
              struct um_async_op *async_op = ptr;
         | 
| 25 | 
            +
              um_op_free(async_op->machine, async_op->op);
         | 
| 26 | 
            +
              free(ptr);
         | 
| 27 | 
            +
            }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            static const rb_data_type_t AsyncOp_type = {
         | 
| 30 | 
            +
                "UringMachine::AsyncOp",
         | 
| 31 | 
            +
                {AsyncOp_mark, AsyncOp_free, AsyncOp_size, AsyncOp_compact},
         | 
| 32 | 
            +
                0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
         | 
| 33 | 
            +
            };
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            static VALUE AsyncOp_allocate(VALUE klass) {
         | 
| 36 | 
            +
              struct um_async_op *async_op = malloc(sizeof(struct um_async_op));
         | 
| 37 | 
            +
              return TypedData_Wrap_Struct(klass, &AsyncOp_type, async_op);
         | 
| 38 | 
            +
            }
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            inline struct um_async_op *AsyncOp_data(VALUE self) {
         | 
| 41 | 
            +
              return RTYPEDDATA_DATA(self);
         | 
| 42 | 
            +
            }
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            VALUE AsyncOp_initialize(VALUE self) {
         | 
| 45 | 
            +
              struct um_async_op *async_op = AsyncOp_data(self);
         | 
| 46 | 
            +
              memset(async_op, 0, sizeof(struct um_async_op));
         | 
| 47 | 
            +
              async_op->self = self;
         | 
| 48 | 
            +
              return self;
         | 
| 49 | 
            +
            }
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            void um_async_op_set(VALUE self, struct um *machine, struct um_op *op) {
         | 
| 52 | 
            +
              struct um_async_op *async_op = AsyncOp_data(self);
         | 
| 53 | 
            +
              async_op->machine = machine;
         | 
| 54 | 
            +
              async_op->op = op;
         | 
| 55 | 
            +
            }
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            inline void raise_on_missing_op(struct um_async_op *async_op) {
         | 
| 58 | 
            +
              if (!async_op->op)
         | 
| 59 | 
            +
                rb_raise(rb_eRuntimeError, "Missing op");
         | 
| 60 | 
            +
            }
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            inline int async_op_is_done(struct um_async_op *async_op) {
         | 
| 63 | 
            +
              return (async_op->op->flags & OP_F_COMPLETED);
         | 
| 64 | 
            +
            }
         | 
| 65 | 
            +
             | 
| 66 | 
            +
            VALUE AsyncOp_kind(VALUE self) {
         | 
| 67 | 
            +
              struct um_async_op *async_op = AsyncOp_data(self);
         | 
| 68 | 
            +
              raise_on_missing_op(async_op);
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              switch(async_op->op->kind) {
         | 
| 71 | 
            +
                case OP_TIMEOUT:
         | 
| 72 | 
            +
                  return SYM_timeout;
         | 
| 73 | 
            +
                default:
         | 
| 74 | 
            +
                  rb_raise(rb_eRuntimeError, "Invalid op kind");
         | 
| 75 | 
            +
              }
         | 
| 76 | 
            +
            }
         | 
| 77 | 
            +
             | 
| 78 | 
            +
            VALUE AsyncOp_done_p(VALUE self) {
         | 
| 79 | 
            +
              struct um_async_op *async_op = AsyncOp_data(self);
         | 
| 80 | 
            +
              raise_on_missing_op(async_op);
         | 
| 81 | 
            +
             | 
| 82 | 
            +
              return async_op_is_done(async_op) ? Qtrue : Qfalse;
         | 
| 83 | 
            +
            }
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            VALUE AsyncOp_result(VALUE self) {
         | 
| 86 | 
            +
              struct um_async_op *async_op = AsyncOp_data(self);
         | 
| 87 | 
            +
              raise_on_missing_op(async_op);
         | 
| 88 | 
            +
             | 
| 89 | 
            +
              return async_op_is_done(async_op) ? INT2NUM(async_op->op->result.res) : Qnil;
         | 
| 90 | 
            +
            }
         | 
| 91 | 
            +
             | 
| 92 | 
            +
            VALUE AsyncOp_cancelled_p(VALUE self) {
         | 
| 93 | 
            +
              struct um_async_op *async_op = AsyncOp_data(self);
         | 
| 94 | 
            +
              raise_on_missing_op(async_op);
         | 
| 95 | 
            +
             | 
| 96 | 
            +
              if (!async_op_is_done(async_op)) return Qnil;
         | 
| 97 | 
            +
             | 
| 98 | 
            +
              return (async_op->op->result.res == -ECANCELED) ? Qtrue : Qfalse;
         | 
| 99 | 
            +
            }
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            VALUE AsyncOp_await(VALUE self) {
         | 
| 102 | 
            +
              struct um_async_op *async_op = AsyncOp_data(self);
         | 
| 103 | 
            +
              raise_on_missing_op(async_op);
         | 
| 104 | 
            +
             | 
| 105 | 
            +
              if (async_op_is_done(async_op))
         | 
| 106 | 
            +
                return INT2NUM(async_op->op->result.res);
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              return um_async_op_await(async_op);
         | 
| 109 | 
            +
            }
         | 
| 110 | 
            +
             | 
| 111 | 
            +
            VALUE AsyncOp_cancel(VALUE self) {
         | 
| 112 | 
            +
              struct um_async_op *async_op = AsyncOp_data(self);
         | 
| 113 | 
            +
              raise_on_missing_op(async_op);
         | 
| 114 | 
            +
             | 
| 115 | 
            +
              if (!async_op_is_done(async_op))
         | 
| 116 | 
            +
                um_async_op_cancel(async_op);
         | 
| 117 | 
            +
             | 
| 118 | 
            +
              return self;
         | 
| 119 | 
            +
            }
         | 
| 120 | 
            +
             | 
| 121 | 
            +
            void Init_AsyncOp(void) {
         | 
| 122 | 
            +
              cAsyncOp = rb_define_class_under(cUM, "AsyncOp", rb_cObject);
         | 
| 123 | 
            +
              rb_define_alloc_func(cAsyncOp, AsyncOp_allocate);
         | 
| 124 | 
            +
             | 
| 125 | 
            +
              rb_define_method(cAsyncOp, "initialize", AsyncOp_initialize, 0);
         | 
| 126 | 
            +
              rb_define_method(cAsyncOp, "kind", AsyncOp_kind, 0);
         | 
| 127 | 
            +
              rb_define_method(cAsyncOp, "done?", AsyncOp_done_p, 0);
         | 
| 128 | 
            +
              rb_define_method(cAsyncOp, "result", AsyncOp_result, 0);
         | 
| 129 | 
            +
              rb_define_method(cAsyncOp, "cancelled?", AsyncOp_cancelled_p, 0);
         | 
| 130 | 
            +
             | 
| 131 | 
            +
              rb_define_method(cAsyncOp, "await", AsyncOp_await, 0);
         | 
| 132 | 
            +
              rb_define_method(cAsyncOp, "join", AsyncOp_await, 0);
         | 
| 133 | 
            +
              rb_define_method(cAsyncOp, "cancel", AsyncOp_cancel, 0);
         | 
| 134 | 
            +
             | 
| 135 | 
            +
              SYM_timeout = ID2SYM(rb_intern("timeout"));
         | 
| 136 | 
            +
            }
         | 
    
        data/ext/um/um_class.c
    CHANGED
    
    | @@ -14,7 +14,6 @@ static void UM_mark(void *ptr) { | |
| 14 14 | 
             
            static void UM_compact(void *ptr) {
         | 
| 15 15 | 
             
              struct um *machine = ptr;
         | 
| 16 16 | 
             
              machine->self = rb_gc_location(machine->self);
         | 
| 17 | 
            -
              machine->poll_fiber = rb_gc_location(machine->poll_fiber);
         | 
| 18 17 |  | 
| 19 18 | 
             
              um_op_list_compact(machine, machine->transient_head);
         | 
| 20 19 | 
             
              um_op_list_compact(machine, machine->runqueue_head);
         | 
| @@ -41,7 +40,7 @@ static VALUE UM_allocate(VALUE klass) { | |
| 41 40 | 
             
              return TypedData_Wrap_Struct(klass, &UM_type, machine);
         | 
| 42 41 | 
             
            }
         | 
| 43 42 |  | 
| 44 | 
            -
            inline struct um * | 
| 43 | 
            +
            inline struct um *um_get_machine(VALUE self) {
         | 
| 45 44 | 
             
              struct um *machine = RTYPEDDATA_DATA(self);
         | 
| 46 45 | 
             
              if (!machine->ring_initialized)
         | 
| 47 46 | 
             
                rb_raise(rb_eRuntimeError, "Machine not initialized");
         | 
| @@ -55,45 +54,50 @@ VALUE UM_initialize(VALUE self) { | |
| 55 54 | 
             
            }
         | 
| 56 55 |  | 
| 57 56 | 
             
            VALUE UM_setup_buffer_ring(VALUE self, VALUE size, VALUE count) {
         | 
| 58 | 
            -
              struct um *machine =  | 
| 57 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 59 58 | 
             
              int bgid = um_setup_buffer_ring(machine, NUM2UINT(size), NUM2UINT(count));
         | 
| 60 59 | 
             
              return INT2NUM(bgid);
         | 
| 61 60 | 
             
            }
         | 
| 62 61 |  | 
| 63 62 | 
             
            VALUE UM_pending_count(VALUE self) {
         | 
| 64 | 
            -
              struct um *machine =  | 
| 63 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 65 64 | 
             
              return INT2NUM(machine->pending_count);
         | 
| 66 65 | 
             
            }
         | 
| 67 66 |  | 
| 68 67 | 
             
            VALUE UM_snooze(VALUE self) {
         | 
| 69 | 
            -
              struct um *machine =  | 
| 68 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 70 69 | 
             
              um_schedule(machine, rb_fiber_current(), Qnil);
         | 
| 71 70 | 
             
              return um_await(machine);
         | 
| 72 71 | 
             
            }
         | 
| 73 72 |  | 
| 74 73 | 
             
            VALUE UM_yield(VALUE self) {
         | 
| 75 | 
            -
              struct um *machine =  | 
| 74 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 76 75 | 
             
              return um_await(machine);
         | 
| 77 76 | 
             
            }
         | 
| 78 77 |  | 
| 79 78 | 
             
            VALUE UM_schedule(VALUE self, VALUE fiber, VALUE value) {
         | 
| 80 | 
            -
              struct um *machine =  | 
| 79 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 81 80 | 
             
              um_schedule(machine, fiber, value);
         | 
| 82 81 | 
             
              return self;
         | 
| 83 82 | 
             
            }
         | 
| 84 83 |  | 
| 85 84 | 
             
            VALUE UM_timeout(VALUE self, VALUE interval, VALUE class) {
         | 
| 86 | 
            -
              struct um *machine =  | 
| 85 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 87 86 | 
             
              return um_timeout(machine, interval, class);
         | 
| 88 87 | 
             
            }
         | 
| 89 88 |  | 
| 90 89 | 
             
            VALUE UM_sleep(VALUE self, VALUE duration) {
         | 
| 91 | 
            -
              struct um *machine =  | 
| 90 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 92 91 | 
             
              return um_sleep(machine, NUM2DBL(duration));
         | 
| 93 92 | 
             
            }
         | 
| 94 93 |  | 
| 94 | 
            +
            VALUE UM_periodically(VALUE self, VALUE interval) {
         | 
| 95 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 96 | 
            +
              return um_periodically(machine, NUM2DBL(interval));
         | 
| 97 | 
            +
            }
         | 
| 98 | 
            +
             | 
| 95 99 | 
             
            VALUE UM_read(int argc, VALUE *argv, VALUE self) {
         | 
| 96 | 
            -
              struct um *machine =  | 
| 100 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 97 101 | 
             
              VALUE fd;
         | 
| 98 102 | 
             
              VALUE buffer;
         | 
| 99 103 | 
             
              VALUE maxlen;
         | 
| @@ -108,7 +112,7 @@ VALUE UM_read(int argc, VALUE *argv, VALUE self) { | |
| 108 112 |  | 
| 109 113 | 
             
            VALUE UM_read_each(VALUE self, VALUE fd, VALUE bgid) {
         | 
| 110 114 | 
             
            #ifdef HAVE_IO_URING_PREP_READ_MULTISHOT
         | 
| 111 | 
            -
              struct um *machine =  | 
| 115 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 112 116 | 
             
              return um_read_each(machine, NUM2INT(fd), NUM2INT(bgid));
         | 
| 113 117 | 
             
            #else
         | 
| 114 118 | 
             
              rb_raise(rb_eRuntimeError, "Not supported by kernel");
         | 
| @@ -116,7 +120,7 @@ VALUE UM_read_each(VALUE self, VALUE fd, VALUE bgid) { | |
| 116 120 | 
             
            }
         | 
| 117 121 |  | 
| 118 122 | 
             
            VALUE UM_write(int argc, VALUE *argv, VALUE self) {
         | 
| 119 | 
            -
              struct um *machine =  | 
| 123 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 120 124 | 
             
              VALUE fd;
         | 
| 121 125 | 
             
              VALUE buffer;
         | 
| 122 126 | 
             
              VALUE len;
         | 
| @@ -127,27 +131,27 @@ VALUE UM_write(int argc, VALUE *argv, VALUE self) { | |
| 127 131 | 
             
            }
         | 
| 128 132 |  | 
| 129 133 | 
             
            VALUE UM_close(VALUE self, VALUE fd) {
         | 
| 130 | 
            -
              struct um *machine =  | 
| 134 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 131 135 | 
             
              return um_close(machine, NUM2INT(fd));
         | 
| 132 136 | 
             
            }
         | 
| 133 137 |  | 
| 134 138 | 
             
            VALUE UM_accept(VALUE self, VALUE fd) {
         | 
| 135 | 
            -
              struct um *machine =  | 
| 139 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 136 140 | 
             
              return um_accept(machine, NUM2INT(fd));
         | 
| 137 141 | 
             
            }
         | 
| 138 142 |  | 
| 139 143 | 
             
            VALUE UM_accept_each(VALUE self, VALUE fd) {
         | 
| 140 | 
            -
              struct um *machine =  | 
| 144 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 141 145 | 
             
              return um_accept_each(machine, NUM2INT(fd));
         | 
| 142 146 | 
             
            }
         | 
| 143 147 |  | 
| 144 148 | 
             
            VALUE UM_socket(VALUE self, VALUE domain, VALUE type, VALUE protocol, VALUE flags) {
         | 
| 145 | 
            -
              struct um *machine =  | 
| 149 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 146 150 | 
             
              return um_socket(machine, NUM2INT(domain), NUM2INT(type), NUM2INT(protocol), NUM2UINT(flags));
         | 
| 147 151 | 
             
            }
         | 
| 148 152 |  | 
| 149 153 | 
             
            VALUE UM_connect(VALUE self, VALUE fd, VALUE host, VALUE port) {
         | 
| 150 | 
            -
              struct um *machine =  | 
| 154 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 151 155 |  | 
| 152 156 | 
             
              struct sockaddr_in addr;
         | 
| 153 157 | 
             
              memset(&addr, 0, sizeof(addr));
         | 
| @@ -159,17 +163,17 @@ VALUE UM_connect(VALUE self, VALUE fd, VALUE host, VALUE port) { | |
| 159 163 | 
             
            }
         | 
| 160 164 |  | 
| 161 165 | 
             
            VALUE UM_send(VALUE self, VALUE fd, VALUE buffer, VALUE len, VALUE flags) {
         | 
| 162 | 
            -
              struct um *machine =  | 
| 166 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 163 167 | 
             
              return um_send(machine, NUM2INT(fd), buffer, NUM2INT(len), NUM2INT(flags));
         | 
| 164 168 | 
             
            }
         | 
| 165 169 |  | 
| 166 170 | 
             
            VALUE UM_recv(VALUE self, VALUE fd, VALUE buffer, VALUE maxlen, VALUE flags) {
         | 
| 167 | 
            -
              struct um *machine =  | 
| 171 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 168 172 | 
             
              return um_recv(machine, NUM2INT(fd), buffer, NUM2INT(maxlen), NUM2INT(flags));
         | 
| 169 173 | 
             
            }
         | 
| 170 174 |  | 
| 171 175 | 
             
            VALUE UM_recv_each(VALUE self, VALUE fd, VALUE bgid, VALUE flags) {
         | 
| 172 | 
            -
              struct um *machine =  | 
| 176 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 173 177 | 
             
              return um_recv_each(machine, NUM2INT(fd), NUM2INT(bgid), NUM2INT(flags));
         | 
| 174 178 | 
             
            }
         | 
| 175 179 |  | 
| @@ -181,7 +185,7 @@ VALUE UM_bind(VALUE self, VALUE fd, VALUE host, VALUE port) { | |
| 181 185 | 
             
              addr.sin_port = htons(NUM2INT(port));
         | 
| 182 186 |  | 
| 183 187 | 
             
            #ifdef HAVE_IO_URING_PREP_BIND
         | 
| 184 | 
            -
              struct um *machine =  | 
| 188 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 185 189 | 
             
              return um_bind(machine, NUM2INT(fd), (struct sockaddr *)&addr, sizeof(addr));
         | 
| 186 190 | 
             
            #else
         | 
| 187 191 | 
             
              int res = bind(NUM2INT(fd), (struct sockaddr *)&addr, sizeof(addr));
         | 
| @@ -193,7 +197,7 @@ VALUE UM_bind(VALUE self, VALUE fd, VALUE host, VALUE port) { | |
| 193 197 |  | 
| 194 198 | 
             
            VALUE UM_listen(VALUE self, VALUE fd, VALUE backlog) {
         | 
| 195 199 | 
             
            #ifdef HAVE_IO_URING_PREP_LISTEN
         | 
| 196 | 
            -
              struct um *machine =  | 
| 200 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 197 201 | 
             
              return um_listen(machine, NUM2INT(fd), NUM2INT(backlog));
         | 
| 198 202 | 
             
            #else
         | 
| 199 203 | 
             
              int res = listen(NUM2INT(fd), NUM2INT(backlog));
         | 
| @@ -215,43 +219,43 @@ static inline int numeric_value(VALUE value) { | |
| 215 219 | 
             
            }
         | 
| 216 220 |  | 
| 217 221 | 
             
            VALUE UM_getsockopt(VALUE self, VALUE fd, VALUE level, VALUE opt) {
         | 
| 218 | 
            -
              struct um *machine =  | 
| 222 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 219 223 | 
             
              return um_getsockopt(machine, NUM2INT(fd), NUM2INT(level), NUM2INT(opt));
         | 
| 220 224 | 
             
            }
         | 
| 221 225 |  | 
| 222 226 | 
             
            VALUE UM_setsockopt(VALUE self, VALUE fd, VALUE level, VALUE opt, VALUE value) {
         | 
| 223 | 
            -
              struct um *machine =  | 
| 227 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 224 228 | 
             
              return um_setsockopt(machine, NUM2INT(fd), NUM2INT(level), NUM2INT(opt), numeric_value(value));
         | 
| 225 229 | 
             
            }
         | 
| 226 230 |  | 
| 227 231 | 
             
            #ifdef HAVE_IO_URING_PREP_FUTEX
         | 
| 228 232 |  | 
| 229 233 | 
             
            VALUE UM_mutex_synchronize(VALUE self, VALUE mutex) {
         | 
| 230 | 
            -
              struct um *machine =  | 
| 234 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 231 235 | 
             
              struct um_mutex *mutex_data = Mutex_data(mutex);
         | 
| 232 236 | 
             
              return um_mutex_synchronize(machine, &mutex_data->state);
         | 
| 233 237 | 
             
            }
         | 
| 234 238 |  | 
| 235 239 | 
             
            VALUE UM_queue_push(VALUE self, VALUE queue, VALUE value) {
         | 
| 236 | 
            -
              struct um *machine =  | 
| 240 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 237 241 | 
             
              struct um_queue *que = Queue_data(queue);
         | 
| 238 242 | 
             
              return um_queue_push(machine, que, value);
         | 
| 239 243 | 
             
            }
         | 
| 240 244 |  | 
| 241 245 | 
             
            VALUE UM_queue_pop(VALUE self, VALUE queue) {
         | 
| 242 | 
            -
              struct um *machine =  | 
| 246 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 243 247 | 
             
              struct um_queue *que = Queue_data(queue);
         | 
| 244 248 | 
             
              return um_queue_pop(machine, que);
         | 
| 245 249 | 
             
            }
         | 
| 246 250 |  | 
| 247 251 | 
             
            VALUE UM_queue_unshift(VALUE self, VALUE queue, VALUE value) {
         | 
| 248 | 
            -
              struct um *machine =  | 
| 252 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 249 253 | 
             
              struct um_queue *que = Queue_data(queue);
         | 
| 250 254 | 
             
              return um_queue_unshift(machine, que, value);
         | 
| 251 255 | 
             
            }
         | 
| 252 256 |  | 
| 253 257 | 
             
            VALUE UM_queue_shift(VALUE self, VALUE queue) {
         | 
| 254 | 
            -
              struct um *machine =  | 
| 258 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 255 259 | 
             
              struct um_queue *que = Queue_data(queue);
         | 
| 256 260 | 
             
              return um_queue_shift(machine, que);
         | 
| 257 261 | 
             
            }
         | 
| @@ -270,7 +274,7 @@ VALUE UM_open_ensure(VALUE arg) { | |
| 270 274 | 
             
            }
         | 
| 271 275 |  | 
| 272 276 | 
             
            VALUE UM_open(VALUE self, VALUE pathname, VALUE flags) {
         | 
| 273 | 
            -
              struct um *machine =  | 
| 277 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 274 278 | 
             
              // TODO: take optional perm (mode) arg
         | 
| 275 279 | 
             
              VALUE fd = um_open(machine, pathname, NUM2INT(flags), 0666);
         | 
| 276 280 | 
             
              if (rb_block_given_p()) {
         | 
| @@ -282,10 +286,15 @@ VALUE UM_open(VALUE self, VALUE pathname, VALUE flags) { | |
| 282 286 | 
             
            }
         | 
| 283 287 |  | 
| 284 288 | 
             
            VALUE UM_waitpid(VALUE self, VALUE pid, VALUE options) {
         | 
| 285 | 
            -
              struct um *machine =  | 
| 289 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 286 290 | 
             
              return um_waitpid(machine, NUM2INT(pid), NUM2INT(options));
         | 
| 287 291 | 
             
            }
         | 
| 288 292 |  | 
| 293 | 
            +
            VALUE UM_prep_timeout(VALUE self, VALUE interval) {
         | 
| 294 | 
            +
              struct um *machine = um_get_machine(self);
         | 
| 295 | 
            +
              return um_prep_timeout(machine, NUM2DBL(interval));
         | 
| 296 | 
            +
            }
         | 
| 297 | 
            +
             | 
| 289 298 | 
             
            VALUE UM_pipe(VALUE self) {
         | 
| 290 299 | 
             
              int fds[2];
         | 
| 291 300 | 
             
              int ret = pipe(fds);
         | 
| @@ -325,6 +334,7 @@ void Init_UM(void) { | |
| 325 334 | 
             
              rb_define_method(cUM, "read", UM_read, -1);
         | 
| 326 335 | 
             
              rb_define_method(cUM, "read_each", UM_read_each, 2);
         | 
| 327 336 | 
             
              rb_define_method(cUM, "sleep", UM_sleep, 1);
         | 
| 337 | 
            +
              rb_define_method(cUM, "periodically", UM_periodically, 1);
         | 
| 328 338 | 
             
              rb_define_method(cUM, "write", UM_write, -1);
         | 
| 329 339 |  | 
| 330 340 | 
             
              rb_define_method(cUM, "waitpid", UM_waitpid, 2);
         | 
| @@ -341,6 +351,8 @@ void Init_UM(void) { | |
| 341 351 | 
             
              rb_define_method(cUM, "setsockopt", UM_setsockopt, 4);
         | 
| 342 352 | 
             
              rb_define_method(cUM, "socket", UM_socket, 4);
         | 
| 343 353 |  | 
| 354 | 
            +
              rb_define_method(cUM, "prep_timeout", UM_prep_timeout, 1);
         | 
| 355 | 
            +
             | 
| 344 356 | 
             
              #ifdef HAVE_IO_URING_PREP_FUTEX
         | 
| 345 357 | 
             
              rb_define_method(cUM, "pop", UM_queue_pop, 1);
         | 
| 346 358 | 
             
              rb_define_method(cUM, "push", UM_queue_push, 2);
         | 
| @@ -349,5 +361,7 @@ void Init_UM(void) { | |
| 349 361 | 
             
              rb_define_method(cUM, "unshift", UM_queue_unshift, 2);
         | 
| 350 362 | 
             
              #endif
         | 
| 351 363 |  | 
| 364 | 
            +
              // Init_micro_ssl(cUM);
         | 
| 365 | 
            +
             | 
| 352 366 | 
             
              um_define_net_constants(cUM);
         | 
| 353 367 | 
             
            }
         |