Skip to content

Commit

Permalink
Convert NIO objects to TypedData API (#310)
Browse files Browse the repository at this point in the history
* Convert NIO::ByteBuffer objects to TypedData API

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

* Convert NIO::Monitor objects to TypedData API

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

* Convert NIO::Selector objects to TypedData API

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
casperisfine committed Dec 1, 2023
1 parent aeb9ef6 commit e471d2e
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 63 deletions.
74 changes: 46 additions & 28 deletions ext/nio4r/bytebuffer.c
Expand Up @@ -8,8 +8,8 @@ static VALUE cNIO_ByteBuffer_MarkUnsetError = Qnil;

/* Allocator/deallocator */
static VALUE NIO_ByteBuffer_allocate(VALUE klass);
static void NIO_ByteBuffer_gc_mark(struct NIO_ByteBuffer *byteBuffer);
static void NIO_ByteBuffer_free(struct NIO_ByteBuffer *byteBuffer);
static void NIO_ByteBuffer_free(void *data);
static size_t NIO_ByteBuffer_memsize(const void *data);

/* Methods */
static VALUE NIO_ByteBuffer_initialize(VALUE self, VALUE capacity);
Expand Down Expand Up @@ -92,28 +92,46 @@ void Init_NIO_ByteBuffer()
rb_define_method(cNIO_ByteBuffer, "inspect", NIO_ByteBuffer_inspect, 0);
}

static const rb_data_type_t NIO_ByteBuffer_type = {
"NIO::ByteBuffer",
{
NULL, // Nothing to mark
NIO_ByteBuffer_free,
NIO_ByteBuffer_memsize,
},
0,
0,
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};

static VALUE NIO_ByteBuffer_allocate(VALUE klass)
{
struct NIO_ByteBuffer *bytebuffer = (struct NIO_ByteBuffer *)xmalloc(sizeof(struct NIO_ByteBuffer));
bytebuffer->buffer = NULL;
return Data_Wrap_Struct(klass, NIO_ByteBuffer_gc_mark, NIO_ByteBuffer_free, bytebuffer);
return TypedData_Wrap_Struct(klass, &NIO_ByteBuffer_type, bytebuffer);
}

static void NIO_ByteBuffer_gc_mark(struct NIO_ByteBuffer *buffer)
static void NIO_ByteBuffer_free(void *data)
{
struct NIO_ByteBuffer *buffer = (struct NIO_ByteBuffer *)data;
if (buffer->buffer)
xfree(buffer->buffer);
xfree(buffer);
}

static void NIO_ByteBuffer_free(struct NIO_ByteBuffer *buffer)
static size_t NIO_ByteBuffer_memsize(const void *data)
{
const struct NIO_ByteBuffer *buffer = (const struct NIO_ByteBuffer *)data;
size_t memsize = sizeof(struct NIO_ByteBuffer);
if (buffer->buffer)
xfree(buffer->buffer);
xfree(buffer);
memsize += buffer->capacity;
return memsize;
}

static VALUE NIO_ByteBuffer_initialize(VALUE self, VALUE capacity)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

buffer->capacity = NUM2INT(capacity);
buffer->buffer = xmalloc(buffer->capacity);
Expand All @@ -126,7 +144,7 @@ static VALUE NIO_ByteBuffer_initialize(VALUE self, VALUE capacity)
static VALUE NIO_ByteBuffer_clear(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

memset(buffer->buffer, 0, buffer->capacity);

Expand All @@ -140,7 +158,7 @@ static VALUE NIO_ByteBuffer_clear(VALUE self)
static VALUE NIO_ByteBuffer_get_position(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

return INT2NUM(buffer->position);
}
Expand All @@ -149,7 +167,7 @@ static VALUE NIO_ByteBuffer_set_position(VALUE self, VALUE new_position)
{
int pos;
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

pos = NUM2INT(new_position);

Expand All @@ -173,7 +191,7 @@ static VALUE NIO_ByteBuffer_set_position(VALUE self, VALUE new_position)
static VALUE NIO_ByteBuffer_get_limit(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

return INT2NUM(buffer->limit);
}
Expand All @@ -182,7 +200,7 @@ static VALUE NIO_ByteBuffer_set_limit(VALUE self, VALUE new_limit)
{
int lim;
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

lim = NUM2INT(new_limit);

Expand Down Expand Up @@ -210,23 +228,23 @@ static VALUE NIO_ByteBuffer_set_limit(VALUE self, VALUE new_limit)
static VALUE NIO_ByteBuffer_capacity(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

return INT2NUM(buffer->capacity);
}

static VALUE NIO_ByteBuffer_remaining(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

return INT2NUM(buffer->limit - buffer->position);
}

static VALUE NIO_ByteBuffer_full(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

return buffer->position == buffer->limit ? Qtrue : Qfalse;
}
Expand All @@ -236,7 +254,7 @@ static VALUE NIO_ByteBuffer_get(int argc, VALUE *argv, VALUE self)
int len;
VALUE length, result;
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

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

Expand Down Expand Up @@ -264,7 +282,7 @@ static VALUE NIO_ByteBuffer_fetch(VALUE self, VALUE index)
{
int i;
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

i = NUM2INT(index);

Expand All @@ -283,7 +301,7 @@ static VALUE NIO_ByteBuffer_put(VALUE self, VALUE string)
{
long length;
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

StringValue(string);
length = RSTRING_LEN(string);
Expand All @@ -303,7 +321,7 @@ static VALUE NIO_ByteBuffer_read_from(VALUE self, VALUE io)
struct NIO_ByteBuffer *buffer;
ssize_t nbytes, bytes_read;

Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

io = rb_convert_type(io, T_FILE, "IO", "to_io");
io_set_nonblock(io);
Expand Down Expand Up @@ -333,7 +351,7 @@ static VALUE NIO_ByteBuffer_write_to(VALUE self, VALUE io)
struct NIO_ByteBuffer *buffer;
ssize_t nbytes, bytes_written;

Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);
io = rb_convert_type(io, T_FILE, "IO", "to_io");
io_set_nonblock(io);

Expand All @@ -360,7 +378,7 @@ static VALUE NIO_ByteBuffer_write_to(VALUE self, VALUE io)
static VALUE NIO_ByteBuffer_flip(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

buffer->limit = buffer->position;
buffer->position = 0;
Expand All @@ -372,7 +390,7 @@ static VALUE NIO_ByteBuffer_flip(VALUE self)
static VALUE NIO_ByteBuffer_rewind(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

buffer->position = 0;
buffer->mark = MARK_UNSET;
Expand All @@ -383,7 +401,7 @@ static VALUE NIO_ByteBuffer_rewind(VALUE self)
static VALUE NIO_ByteBuffer_mark(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

buffer->mark = buffer->position;
return self;
Expand All @@ -392,7 +410,7 @@ static VALUE NIO_ByteBuffer_mark(VALUE self)
static VALUE NIO_ByteBuffer_reset(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

if (buffer->mark < 0) {
rb_raise(cNIO_ByteBuffer_MarkUnsetError, "mark has not been set");
Expand All @@ -406,7 +424,7 @@ static VALUE NIO_ByteBuffer_reset(VALUE self)
static VALUE NIO_ByteBuffer_compact(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

memmove(buffer->buffer, buffer->buffer + buffer->position, buffer->limit - buffer->position);
buffer->position = buffer->limit - buffer->position;
Expand All @@ -419,7 +437,7 @@ static VALUE NIO_ByteBuffer_each(VALUE self)
{
int i;
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

if (rb_block_given_p()) {
for (i = 0; i < buffer->limit; i++) {
Expand All @@ -435,7 +453,7 @@ static VALUE NIO_ByteBuffer_each(VALUE self)
static VALUE NIO_ByteBuffer_inspect(VALUE self)
{
struct NIO_ByteBuffer *buffer;
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
TypedData_Get_Struct(self, struct NIO_ByteBuffer, &NIO_ByteBuffer_type, buffer);

return rb_sprintf(
"#<%s:%p @position=%d @limit=%d @capacity=%d>",
Expand Down
48 changes: 31 additions & 17 deletions ext/nio4r/monitor.c
Expand Up @@ -11,8 +11,8 @@ static VALUE cNIO_Monitor = Qnil;

/* Allocator/deallocator */
static VALUE NIO_Monitor_allocate(VALUE klass);
static void NIO_Monitor_mark(struct NIO_Monitor *monitor);
static void NIO_Monitor_free(struct NIO_Monitor *monitor);
static void NIO_Monitor_mark(void *data);
static size_t NIO_Monitor_memsize(const void *data);

/* Methods */
static VALUE NIO_Monitor_initialize(VALUE self, VALUE selector, VALUE io, VALUE interests);
Expand Down Expand Up @@ -70,22 +70,36 @@ void Init_NIO_Monitor()
rb_define_method(cNIO_Monitor, "writeable?", NIO_Monitor_is_writable, 0);
}

static const rb_data_type_t NIO_Monitor_type = {
"NIO::Monitor",
{
NIO_Monitor_mark,
RUBY_TYPED_DEFAULT_FREE,
NIO_Monitor_memsize,
},
0,
0,
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
};

static VALUE NIO_Monitor_allocate(VALUE klass)
{
struct NIO_Monitor *monitor = (struct NIO_Monitor *)xmalloc(sizeof(struct NIO_Monitor));
assert(monitor);
*monitor = (struct NIO_Monitor){.self = Qnil};
return Data_Wrap_Struct(klass, NIO_Monitor_mark, NIO_Monitor_free, monitor);
return TypedData_Wrap_Struct(klass, &NIO_Monitor_type, monitor);
}

static void NIO_Monitor_mark(struct NIO_Monitor *monitor)
static void NIO_Monitor_mark(void *data)
{
struct NIO_Monitor *monitor = (struct NIO_Monitor *)data;
rb_gc_mark(monitor->self);
}

static void NIO_Monitor_free(struct NIO_Monitor *monitor)
static size_t NIO_Monitor_memsize(const void *data)
{
xfree(monitor);
const struct NIO_Monitor *monitor = (const struct NIO_Monitor *)data;
return sizeof(*monitor);
}

static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE selector_obj)
Expand All @@ -96,7 +110,7 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE

interests_id = SYM2ID(interests);

Data_Get_Struct(self, struct NIO_Monitor, monitor);
TypedData_Get_Struct(self, struct NIO_Monitor, &NIO_Monitor_type, monitor);

if (interests_id == rb_intern("r")) {
monitor->interests = EV_READ;
Expand All @@ -115,9 +129,9 @@ 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);

monitor->self = self;
RB_OBJ_WRITE(self, &monitor->self, self);
monitor->ev_io.data = (void *)monitor;

/* We can safely hang onto this as we also hang onto a reference to the
Expand All @@ -135,7 +149,7 @@ static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self)
{
VALUE deregister, selector;
struct NIO_Monitor *monitor;
Data_Get_Struct(self, struct NIO_Monitor, monitor);
TypedData_Get_Struct(self, struct NIO_Monitor, &NIO_Monitor_type, monitor);

rb_scan_args(argc, argv, "01", &deregister);
selector = rb_ivar_get(self, rb_intern("selector"));
Expand All @@ -161,7 +175,7 @@ static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self)
static VALUE NIO_Monitor_is_closed(VALUE self)
{
struct NIO_Monitor *monitor;
Data_Get_Struct(self, struct NIO_Monitor, monitor);
TypedData_Get_Struct(self, struct NIO_Monitor, &NIO_Monitor_type, monitor);

return monitor->selector == 0 ? Qtrue : Qfalse;
}
Expand Down Expand Up @@ -190,7 +204,7 @@ static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests)
static VALUE NIO_Monitor_add_interest(VALUE self, VALUE interest)
{
struct NIO_Monitor *monitor;
Data_Get_Struct(self, struct NIO_Monitor, monitor);
TypedData_Get_Struct(self, struct NIO_Monitor, &NIO_Monitor_type, monitor);

interest = monitor->interests | NIO_Monitor_symbol2interest(interest);
NIO_Monitor_update_interests(self, (int)interest);
Expand All @@ -201,7 +215,7 @@ static VALUE NIO_Monitor_add_interest(VALUE self, VALUE interest)
static VALUE NIO_Monitor_remove_interest(VALUE self, VALUE interest)
{
struct NIO_Monitor *monitor;
Data_Get_Struct(self, struct NIO_Monitor, monitor);
TypedData_Get_Struct(self, struct NIO_Monitor, &NIO_Monitor_type, monitor);

interest = monitor->interests & ~NIO_Monitor_symbol2interest(interest);
NIO_Monitor_update_interests(self, (int)interest);
Expand All @@ -227,7 +241,7 @@ static VALUE NIO_Monitor_set_value(VALUE self, VALUE obj)
static VALUE NIO_Monitor_readiness(VALUE self)
{
struct NIO_Monitor *monitor;
Data_Get_Struct(self, struct NIO_Monitor, monitor);
TypedData_Get_Struct(self, struct NIO_Monitor, &NIO_Monitor_type, monitor);

if ((monitor->revents & (EV_READ | EV_WRITE)) == (EV_READ | EV_WRITE)) {
return ID2SYM(rb_intern("rw"));
Expand All @@ -243,7 +257,7 @@ static VALUE NIO_Monitor_readiness(VALUE self)
static VALUE NIO_Monitor_is_readable(VALUE self)
{
struct NIO_Monitor *monitor;
Data_Get_Struct(self, struct NIO_Monitor, monitor);
TypedData_Get_Struct(self, struct NIO_Monitor, &NIO_Monitor_type, monitor);

if (monitor->revents & EV_READ) {
return Qtrue;
Expand All @@ -255,7 +269,7 @@ static VALUE NIO_Monitor_is_readable(VALUE self)
static VALUE NIO_Monitor_is_writable(VALUE self)
{
struct NIO_Monitor *monitor;
Data_Get_Struct(self, struct NIO_Monitor, monitor);
TypedData_Get_Struct(self, struct NIO_Monitor, &NIO_Monitor_type, monitor);

if (monitor->revents & EV_WRITE) {
return Qtrue;
Expand Down Expand Up @@ -286,7 +300,7 @@ static void NIO_Monitor_update_interests(VALUE self, int interests)
{
ID interests_id;
struct NIO_Monitor *monitor;
Data_Get_Struct(self, struct NIO_Monitor, monitor);
TypedData_Get_Struct(self, struct NIO_Monitor, &NIO_Monitor_type, monitor);

if (NIO_Monitor_is_closed(self) == Qtrue) {
rb_raise(rb_eEOFError, "monitor is closed");
Expand Down
2 changes: 2 additions & 0 deletions ext/nio4r/nio4r.h
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

0 comments on commit e471d2e

Please sign in to comment.