Skip to content

Commit

Permalink
Convert NIO::Selector objects to TypedData API
Browse files Browse the repository at this point in the history
The replacement API was introduced in Ruby 1.9.2 (2010),
and the old untyped data API was marked a deprecated in the documentation
as of Ruby 2.3.0 (2015)

Ref: https://bugs.ruby-lang.org/issues/19998
  • Loading branch information
byroot committed Nov 30, 2023
1 parent 4eafc59 commit 0ccefc7
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 19 deletions.
2 changes: 1 addition & 1 deletion ext/nio4r/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
rb_ivar_set(self, rb_intern("interests"), interests);
rb_ivar_set(self, rb_intern("selector"), selector_obj);

Data_Get_Struct(selector_obj, struct NIO_Selector, selector);
selector = NIO_Selector_unwrap(selector_obj);

RB_OBJ_WRITE(self, &monitor->self, self);
monitor->ev_io.data = (void *)monitor;
Expand Down
2 changes: 2 additions & 0 deletions ext/nio4r/nio4r.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ struct NIO_ByteBuffer {
int position, limit, capacity, mark;
};

struct NIO_Selector *NIO_Selector_unwrap(VALUE selector);

/* Thunk between libev callbacks in NIO::Monitors and NIO::Selectors */
void NIO_Selector_monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents);

Expand Down
61 changes: 43 additions & 18 deletions ext/nio4r/selector.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ static VALUE cNIO_Selector = Qnil;

/* Allocator/deallocator */
static VALUE NIO_Selector_allocate(VALUE klass);
static void NIO_Selector_mark(struct NIO_Selector *loop);
static void NIO_Selector_mark(void *data);
static void NIO_Selector_shutdown(struct NIO_Selector *selector);
static void NIO_Selector_free(struct NIO_Selector *loop);
static void NIO_Selector_free(void *data);
static size_t NIO_Selector_memsize(const void *data);

/* Class methods */
static VALUE NIO_Selector_supported_backends(VALUE klass);
Expand Down Expand Up @@ -83,6 +84,18 @@ void Init_NIO_Selector(void)
cNIO_Monitor = rb_define_class_under(mNIO, "Monitor", rb_cObject);
}

static const rb_data_type_t NIO_Selector_type = {
"NIO::Selector",
{
NIO_Selector_mark,
NIO_Selector_free,
NIO_Selector_memsize,
},
0,
0,
RUBY_TYPED_WB_PROTECTED // Don't free immediately because of shutdown
};

/* Create the libev event loop and incoming event buffer */
static VALUE NIO_Selector_allocate(VALUE klass)
{
Expand All @@ -104,8 +117,7 @@ static VALUE NIO_Selector_allocate(VALUE klass)
rb_sys_fail("fcntl");
}

selector = (struct NIO_Selector *)xmalloc(sizeof(struct NIO_Selector));

VALUE obj = TypedData_Make_Struct(klass, struct NIO_Selector, &NIO_Selector_type, selector);
/* Defer initializing the loop to #initialize */
selector->ev_loop = 0;

Expand All @@ -118,14 +130,21 @@ static VALUE NIO_Selector_allocate(VALUE klass)
selector->wakeup.data = (void *)selector;

selector->closed = selector->selecting = selector->wakeup_fired = selector->ready_count = 0;
selector->ready_array = Qnil;
RB_OBJ_WRITE(obj, &selector->ready_array, Qnil);
return obj;
}

return Data_Wrap_Struct(klass, NIO_Selector_mark, NIO_Selector_free, selector);
struct NIO_Selector *NIO_Selector_unwrap(VALUE self)
{
struct NIO_Selector *selector;
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
return selector;
}

/* NIO selectors store all Ruby objects in instance variables so mark is a stub */
static void NIO_Selector_mark(struct NIO_Selector *selector)
static void NIO_Selector_mark(void *data)
{
struct NIO_Selector *selector = (struct NIO_Selector *)data;
if (selector->ready_array != Qnil) {
rb_gc_mark(selector->ready_array);
}
Expand All @@ -151,12 +170,18 @@ static void NIO_Selector_shutdown(struct NIO_Selector *selector)
}

/* Ruby finalizer for selector objects */
static void NIO_Selector_free(struct NIO_Selector *selector)
static void NIO_Selector_free(void *data)
{
struct NIO_Selector *selector = (struct NIO_Selector *)data;
NIO_Selector_shutdown(selector);
xfree(selector);
}

static size_t NIO_Selector_memsize(const void *data)
{
return sizeof(struct NIO_Selector);
}

/* Return an array of symbols for supported backends */
static VALUE NIO_Selector_supported_backends(VALUE klass)
{
Expand Down Expand Up @@ -205,7 +230,7 @@ static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self)
struct NIO_Selector *selector;
unsigned int flags = 0;

Data_Get_Struct(self, struct NIO_Selector, selector);
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);

rb_scan_args(argc, argv, "01", &backend);

Expand Down Expand Up @@ -259,7 +284,7 @@ static VALUE NIO_Selector_backend(VALUE self)
{
struct NIO_Selector *selector;

Data_Get_Struct(self, struct NIO_Selector, selector);
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
if (selector->closed) {
rb_raise(rb_eIOError, "selector is closed");
}
Expand Down Expand Up @@ -337,7 +362,7 @@ static VALUE NIO_Selector_register_synchronized(VALUE _args)
io = args[1];
interests = args[2];

Data_Get_Struct(self, struct NIO_Selector, selector);
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);
if (selector->closed) {
rb_raise(rb_eIOError, "selector is closed");
}
Expand Down Expand Up @@ -418,22 +443,22 @@ static VALUE NIO_Selector_select_synchronized(VALUE _args)

VALUE *args = (VALUE *)_args;

Data_Get_Struct(args[0], struct NIO_Selector, selector);
TypedData_Get_Struct(args[0], struct NIO_Selector, &NIO_Selector_type, selector);

if (selector->closed) {
rb_raise(rb_eIOError, "selector is closed");
}

if (!rb_block_given_p()) {
selector->ready_array = rb_ary_new();
RB_OBJ_WRITE(args[0], &selector->ready_array, rb_ary_new());
}

ready = NIO_Selector_run(selector, args[1]);

/* Timeout */
if (ready < 0) {
if (!rb_block_given_p()) {
selector->ready_array = Qnil;
RB_OBJ_WRITE(args[0], &selector->ready_array, Qnil);
}

return Qnil;
Expand All @@ -443,7 +468,7 @@ static VALUE NIO_Selector_select_synchronized(VALUE _args)
return INT2NUM(ready);
} else {
ready_array = selector->ready_array;
selector->ready_array = Qnil;
RB_OBJ_WRITE(args[0], &selector->ready_array, Qnil);
return ready_array;
}
}
Expand Down Expand Up @@ -490,7 +515,7 @@ static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout)
static VALUE NIO_Selector_wakeup(VALUE self)
{
struct NIO_Selector *selector;
Data_Get_Struct(self, struct NIO_Selector, selector);
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);

if (selector->closed) {
rb_raise(rb_eIOError, "selector is closed");
Expand All @@ -512,7 +537,7 @@ static VALUE NIO_Selector_close_synchronized(VALUE self)
{
struct NIO_Selector *selector;

Data_Get_Struct(self, struct NIO_Selector, selector);
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);

NIO_Selector_shutdown(selector);

Expand All @@ -529,7 +554,7 @@ static VALUE NIO_Selector_closed_synchronized(VALUE self)
{
struct NIO_Selector *selector;

Data_Get_Struct(self, struct NIO_Selector, selector);
TypedData_Get_Struct(self, struct NIO_Selector, &NIO_Selector_type, selector);

return selector->closed ? Qtrue : Qfalse;
}
Expand Down

0 comments on commit 0ccefc7

Please sign in to comment.