ext/io/epoll/epoll.c in io-epoll-0.0.2 vs ext/io/epoll/epoll.c in io-epoll-0.1.0
- old
+ new
@@ -2,22 +2,29 @@
#include "ruby/io.h"
#include "ruby/thread.h"
#include <sys/epoll.h>
VALUE cIO_Epoll;
+VALUE cIO_Epoll_Event;
struct Epoll {
int epfd;
int ev_len;
};
static void
+epoll_fd_close(int epfd)
+{
+ rb_thread_fd_close(epfd);
+}
+
+static void
rb_epoll_free(void *p)
{
struct Epoll *ptr = p;
if (ptr) {
- if (0 <= ptr->epfd) close(ptr->epfd);
+ if (0 <= ptr->epfd) epoll_fd_close(ptr->epfd);
ruby_xfree(ptr);
}
}
static size_t
@@ -36,19 +43,34 @@
rb_epoll_memsize,
},
NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED
};
+void
+epoll_check_initialized(struct Epoll *ptr)
+{
+ if (!ptr) {
+ rb_raise(rb_eIOError, "uninitialized stream");
+ }
+}
+
+void
+epoll_check_closed(struct Epoll *ptr)
+{
+ epoll_check_initialized(ptr);
+ if (ptr->epfd < 0) {
+ rb_raise(rb_eIOError, "closed stream");
+ }
+}
+
static struct Epoll*
get_epoll(VALUE self)
{
struct Epoll *ptr;
rb_check_frozen(self);
TypedData_Get_Struct(self, struct Epoll, &epoll_data_type, ptr);
- if (!ptr) {
- rb_raise(rb_eIOError, "uninitialized stream");
- }
+ epoll_check_initialized(ptr);
return ptr;
}
static VALUE
rb_epoll_allocate(VALUE klass)
@@ -62,27 +84,52 @@
{
struct Epoll *ptr;
int epfd;
TypedData_Get_Struct(self, struct Epoll, &epoll_data_type, ptr);
- if (ptr->epfd < 0) close(ptr->epfd);
+ if (ptr->epfd < 0) epoll_fd_close(ptr->epfd);
epfd = epoll_create(1);
if (epfd == -1) {
rb_sys_fail("epoll_create was failed");
}
ptr->epfd = epfd;
ptr->ev_len = 0;
+
+ /**
+ * FIXME: I want to delete instance variable `evlist` !
+ * It's just only using for GC mark.
+ * So, I don't know how to GC guard io objects.
+ */
+ rb_ivar_set(self, rb_intern("evlist"), rb_ary_new());
+
return self;
}
static VALUE
rb_epoll_fileno(VALUE self)
{
struct Epoll *ptr = get_epoll(self);
+ epoll_check_closed(ptr);
return INT2FIX(ptr->epfd);
}
+inline static void
+rb_epoll_evlist_add(VALUE self, VALUE io)
+{
+ VALUE evlist = rb_ivar_get(self, rb_intern("evlist"));
+ rb_ary_push(evlist, io);
+ rb_ivar_set(self, rb_intern("evlist"), evlist);
+}
+
+inline static void
+rb_epoll_evlist_del(VALUE self, VALUE io)
+{
+ VALUE evlist = rb_ivar_get(self, rb_intern("evlist"));
+ rb_ary_delete(evlist, io);
+ rb_ivar_set(self, rb_intern("evlist"), evlist);
+}
+
static VALUE
rb_epoll_ctl(int argc, VALUE *argv, VALUE self)
{
struct Epoll *ptr = get_epoll(self);
struct epoll_event ev;
@@ -95,15 +142,25 @@
switch (rb_scan_args(argc, argv, "21", &flag, &io, &events)) {
case 2:
if (FIX2INT(flag) != EPOLL_CTL_DEL)
rb_raise(rb_eArgError, "too few argument for CTL_ADD or CTL_MOD");
break;
+ rb_epoll_evlist_del(self, io);
case 3:
- if (FIX2INT(flag) != EPOLL_CTL_ADD && FIX2INT(flag) != EPOLL_CTL_MOD)
+ if (FIX2INT(flag) == EPOLL_CTL_ADD) {
+ rb_epoll_evlist_add(self, io);
+ }
+ else if (FIX2INT(flag) == EPOLL_CTL_MOD) {
+ /* nothing */
+ }
+ else {
rb_raise(rb_eArgError, "too many argument for CTL_DEL");
+ }
+
if ((FIX2LONG(events) & (EPOLLIN|EPOLLPRI|EPOLLRDHUP|EPOLLOUT|EPOLLET|EPOLLONESHOT)) == 0)
rb_raise(rb_eIOError, "undefined events");
+
ev.events = FIX2LONG(events);
ev.data.ptr = (void*)io;
break;
}
@@ -148,19 +205,19 @@
static VALUE
rb_epoll_wait(int argc, VALUE *argv, VALUE self)
{
struct Epoll *ptr = get_epoll(self);
VALUE ready_evlist;
- VALUE cEvent;
VALUE event;
struct epoll_event *evlist;
int i, ready;
int timeout = -1;
struct epoll_wait_args data;
if (argc == 1)
timeout = FIX2INT(argv[0]);
+
if (ptr->ev_len <= 0)
rb_raise(rb_eIOError, "empty interest list");
evlist = ruby_xmalloc(ptr->ev_len * sizeof(struct epoll_event));
@@ -179,13 +236,12 @@
rb_sys_fail("epoll_wait() was failed");
}
}
ready_evlist = rb_ary_new_capa(ready);
- cEvent = rb_path2class("IO::Epoll::Event");
for (i = 0; i < ready; i++) {
- event = rb_obj_alloc(cEvent);
+ event = rb_obj_alloc(cIO_Epoll_Event);
RSTRUCT_SET(event, 0, (VALUE) evlist[i].data.ptr);
RSTRUCT_SET(event, 1, LONG2FIX(evlist[i].events));
rb_ary_store(ready_evlist, i, event);
}
ruby_xfree(evlist);
@@ -194,34 +250,42 @@
static VALUE
rb_epoll_close(VALUE self)
{
struct Epoll *ptr = get_epoll(self);
- if (close(ptr->epfd) == -1) {
- rb_raise(rb_eIOError, "file descriptor duplicate close %ld", INT2FIX(ptr->epfd));
- }
+ epoll_check_closed(ptr);
+ epoll_fd_close(ptr->epfd);
ptr->epfd = -1;
return Qnil;
}
static VALUE
+rb_epoll_closed_p(VALUE self)
+{
+ struct Epoll *ptr = get_epoll(self);
+ return 0 <= ptr->epfd ? Qfalse : Qtrue;
+}
+
+static VALUE
rb_epoll_length(VALUE self)
{
struct Epoll *ptr = get_epoll(self);
return INT2FIX(ptr->ev_len);
}
void
Init_epoll()
{
cIO_Epoll = rb_define_class_under(rb_cIO, "Epoll", rb_cObject);
+ cIO_Epoll_Event = rb_struct_define_under(cIO_Epoll, "Event", "data", "events", NULL);
rb_define_alloc_func(cIO_Epoll, rb_epoll_allocate);
rb_define_method(cIO_Epoll, "initialize", rb_epoll_initialize, 0);
- rb_define_method(cIO_Epoll, "fileno", rb_epoll_fileno, 0);
rb_define_method(cIO_Epoll, "ctl", rb_epoll_ctl, -1);
rb_define_method(cIO_Epoll, "wait", rb_epoll_wait, -1);
+ rb_define_method(cIO_Epoll, "fileno", rb_epoll_fileno, 0);
rb_define_method(cIO_Epoll, "close", rb_epoll_close, 0);
+ rb_define_method(cIO_Epoll, "closed?", rb_epoll_closed_p, 0);
rb_define_method(cIO_Epoll, "length", rb_epoll_length, 0);
rb_define_alias(cIO_Epoll, "size", "length");
rb_define_const(cIO_Epoll, "IN", INT2FIX(EPOLLIN));
rb_define_const(cIO_Epoll, "PRI", INT2FIX(EPOLLPRI));
rb_define_const(cIO_Epoll, "RDHUP", INT2FIX(EPOLLRDHUP));