Class: IO::Event::Selector::EPoll
- Inherits:
-
Object
- Object
- IO::Event::Selector::EPoll
- Defined in:
- ext/io/event/selector/epoll.c
Instance Method Summary collapse
- #close ⇒ Object
- #closed? ⇒ Boolean
- #idle_duration ⇒ Object
- #initialize(loop) ⇒ Object constructor
- #io_read(*args) ⇒ Object
- #io_wait(fiber, io, events) ⇒ Object
- #io_write(*args) ⇒ Object
- #loop ⇒ Object
-
#process_wait(fiber, _pid, _flags) ⇒ Object
rb_define_method(IO_Event_Selector_EPoll, "io_write", IO_Event_Selector_EPoll_io_write, 5);.
- #push(fiber) ⇒ Object
- #raise(*args) ⇒ Object
- #ready? ⇒ Boolean
- #resume(*args) ⇒ Object
-
#select(duration) ⇒ Object
TODO This function is not re-entrant and we should document and assert as such.
- #transfer ⇒ Object
- #wakeup ⇒ Object
- #yield ⇒ Object
Constructor Details
#initialize(loop) ⇒ Object
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 |
# File 'ext/io/event/selector/epoll.c', line 347
VALUE IO_Event_Selector_EPoll_initialize(VALUE self, VALUE loop) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
IO_Event_Selector_initialize(&selector->backend, self, loop);
int result = epoll_create1(EPOLL_CLOEXEC);
if (result == -1) {
rb_sys_fail("IO_Event_Selector_EPoll_initialize:epoll_create");
} else {
selector->descriptor = result;
selector->owner = getpid();
rb_update_max_fd(selector->descriptor);
}
IO_Event_Interrupt_open(&selector->interrupt);
IO_Event_Interrupt_add(&selector->interrupt, selector);
return self;
}
|
Instance Method Details
#close ⇒ Object
385 386 387 388 389 390 391 392 |
# File 'ext/io/event/selector/epoll.c', line 385
VALUE IO_Event_Selector_EPoll_close(VALUE self) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
close_internal(selector);
return Qnil;
}
|
#closed? ⇒ Boolean
394 395 396 397 398 399 |
# File 'ext/io/event/selector/epoll.c', line 394
VALUE IO_Event_Selector_EPoll_closed_p(VALUE self) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
return selector->descriptor < 0 || selector->owner != getpid() ? Qtrue : Qfalse;
}
|
#idle_duration ⇒ Object
376 377 378 379 380 381 382 383 |
# File 'ext/io/event/selector/epoll.c', line 376
VALUE IO_Event_Selector_EPoll_idle_duration(VALUE self) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
double duration = selector->idle_duration.tv_sec + (selector->idle_duration.tv_nsec / 1000000000.0);
return DBL2NUM(duration);
}
|
#io_read(*args) ⇒ Object
692 693 694 695 696 697 698 699 700 701 702 703 |
# File 'ext/io/event/selector/epoll.c', line 692
VALUE IO_Event_Selector_EPoll_io_read_compatible(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 4, 5);
VALUE _offset = SIZET2NUM(0);
if (argc == 5) {
_offset = argv[4];
}
return IO_Event_Selector_EPoll_io_read(self, argv[0], argv[1], argv[2], argv[3], _offset);
}
|
#io_wait(fiber, io, events) ⇒ Object
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
# File 'ext/io/event/selector/epoll.c', line 566
VALUE IO_Event_Selector_EPoll_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
int descriptor = IO_Event_Selector_io_descriptor(io);
struct IO_Event_Selector_EPoll_Waiting waiting = {
.list = {.type = &IO_Event_Selector_EPoll_io_wait_list_type},
.fiber = fiber,
.events = RB_NUM2INT(events),
};
RB_OBJ_WRITTEN(self, Qundef, fiber);
int result = IO_Event_Selector_EPoll_Waiting_register(selector, io, descriptor, &waiting);
if (result == -1) {
if (errno == EPERM) {
IO_Event_Selector_ready_push(&selector->backend, fiber);
IO_Event_Selector_yield(&selector->backend);
return events;
}
rb_sys_fail("IO_Event_Selector_EPoll_io_wait:IO_Event_Selector_EPoll_Waiting_register");
}
struct io_wait_arguments io_wait_arguments = {
.selector = selector,
.waiting = &waiting,
};
return rb_ensure(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_ensure, (VALUE)&io_wait_arguments);
}
|
#io_write(*args) ⇒ Object
799 800 801 802 803 804 805 806 807 808 809 810 |
# File 'ext/io/event/selector/epoll.c', line 799
VALUE IO_Event_Selector_EPoll_io_write_compatible(int argc, VALUE *argv, VALUE self)
{
rb_check_arity(argc, 4, 5);
VALUE _offset = SIZET2NUM(0);
if (argc == 5) {
_offset = argv[4];
}
return IO_Event_Selector_EPoll_io_write(self, argv[0], argv[1], argv[2], argv[3], _offset);
}
|
#loop ⇒ Object
369 370 371 372 373 374 |
# File 'ext/io/event/selector/epoll.c', line 369
VALUE IO_Event_Selector_EPoll_loop(VALUE self) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
return selector->backend.loop;
}
|
#process_wait(fiber, _pid, _flags) ⇒ Object
rb_define_method(IO_Event_Selector_EPoll, "io_write", IO_Event_Selector_EPoll_io_write, 5);
484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 |
# File 'ext/io/event/selector/epoll.c', line 484
VALUE IO_Event_Selector_EPoll_process_wait(VALUE self, VALUE fiber, VALUE _pid, VALUE _flags) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
pid_t pid = NUM2PIDT(_pid);
int flags = NUM2INT(_flags);
// `pidfd_open` can only refer to a specific process, so waiting for any child or a process group (pid <= 0) is delegated to the threaded fallback:
if (pid <= 0) {
return IO_Event_Selector_process_wait(pid, flags);
}
int descriptor = pidfd_open(pid, 0);
if (descriptor == -1) {
rb_sys_fail("IO_Event_Selector_EPoll_process_wait:pidfd_open");
}
rb_update_max_fd(descriptor);
// `pidfd_open` (above) may be edge triggered, so we need to check if the process is already exited, and if so, return immediately, otherwise we will block indefinitely.
VALUE status = IO_Event_Selector_process_status_reap(pid, flags);
if (status != Qnil) {
close(descriptor);
return status;
}
struct IO_Event_Selector_EPoll_Waiting waiting = {
.list = {.type = &IO_Event_Selector_EPoll_process_wait_list_type},
.fiber = fiber,
.events = IO_EVENT_READABLE,
};
RB_OBJ_WRITTEN(self, Qundef, fiber);
int result = IO_Event_Selector_EPoll_Waiting_register(selector, _pid, descriptor, &waiting);
if (result == -1) {
close(descriptor);
rb_sys_fail("IO_Event_Selector_EPoll_process_wait:IO_Event_Selector_EPoll_Waiting_register");
}
struct process_wait_arguments process_wait_arguments = {
.selector = selector,
.pid = pid,
.flags = flags,
.descriptor = descriptor,
.waiting = &waiting,
};
return rb_ensure(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_ensure, (VALUE)&process_wait_arguments);
}
|
#push(fiber) ⇒ Object
425 426 427 428 429 430 431 432 433 |
# File 'ext/io/event/selector/epoll.c', line 425
VALUE IO_Event_Selector_EPoll_push(VALUE self, VALUE fiber)
{
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
IO_Event_Selector_ready_push(&selector->backend, fiber);
return Qnil;
}
|
#raise(*args) ⇒ Object
435 436 437 438 439 440 441 |
# File 'ext/io/event/selector/epoll.c', line 435
VALUE IO_Event_Selector_EPoll_raise(int argc, VALUE *argv, VALUE self)
{
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
return IO_Event_Selector_raise(&selector->backend, argc, argv);
}
|
#ready? ⇒ Boolean
443 444 445 446 447 448 |
# File 'ext/io/event/selector/epoll.c', line 443
VALUE IO_Event_Selector_EPoll_ready_p(VALUE self) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
return selector->backend.ready ? Qtrue : Qfalse;
}
|
#resume(*args) ⇒ Object
409 410 411 412 413 414 415 |
# File 'ext/io/event/selector/epoll.c', line 409
VALUE IO_Event_Selector_EPoll_resume(int argc, VALUE *argv, VALUE self)
{
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
return IO_Event_Selector_resume(&selector->backend, argc, argv);
}
|
#select(duration) ⇒ Object
TODO This function is not re-entrant and we should document and assert as such.
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 |
# File 'ext/io/event/selector/epoll.c', line 1034
VALUE IO_Event_Selector_EPoll_select(VALUE self, VALUE duration) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
selector->idle_duration.tv_sec = 0;
selector->idle_duration.tv_nsec = 0;
int ready = IO_Event_Selector_ready_flush(&selector->backend);
struct select_arguments arguments = {
.selector = selector,
.count = EPOLL_MAX_EVENTS,
.result = 0,
.storage = {
.tv_sec = 0,
.tv_nsec = 0
},
.saved = {},
};
arguments.timeout = &arguments.storage;
// Process any currently pending events:
int result = select_internal_with_gvl(&arguments);
// If we:
// 1. Didn't process any ready fibers, and
// 2. Didn't process any events from non-blocking select (above), and
// 3. There are no items in the ready list,
// then we can perform a blocking select.
if (!ready && !result && !selector->backend.ready) {
arguments.timeout = make_timeout(duration, &arguments.storage);
if (select_blocking_allowed(arguments.timeout)) {
struct timespec start_time;
IO_Event_Time_current(&start_time);
// Wait for events to occur:
result = select_internal_without_gvl(&arguments);
struct timespec end_time;
IO_Event_Time_current(&end_time);
IO_Event_Time_elapsed(&start_time, &end_time, &selector->idle_duration);
}
}
if (result) {
return rb_ensure(select_handle_events, (VALUE)&arguments, select_handle_events_ensure, (VALUE)&arguments);
} else {
return RB_INT2NUM(0);
}
}
|
#transfer ⇒ Object
401 402 403 404 405 406 407 |
# File 'ext/io/event/selector/epoll.c', line 401
VALUE IO_Event_Selector_EPoll_transfer(VALUE self)
{
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
return IO_Event_Selector_loop_yield(&selector->backend);
}
|
#wakeup ⇒ Object
1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 |
# File 'ext/io/event/selector/epoll.c', line 1087
VALUE IO_Event_Selector_EPoll_wakeup(VALUE self) {
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
// If we are blocking, we can schedule a nop event to wake up the selector:
if (selector->blocked) {
IO_Event_Interrupt_signal(&selector->interrupt);
return Qtrue;
}
return Qfalse;
}
|
#yield ⇒ Object
417 418 419 420 421 422 423 |
# File 'ext/io/event/selector/epoll.c', line 417
VALUE IO_Event_Selector_EPoll_yield(VALUE self)
{
struct IO_Event_Selector_EPoll *selector = NULL;
TypedData_Get_Struct(self, struct IO_Event_Selector_EPoll, &IO_Event_Selector_EPoll_Type, selector);
return IO_Event_Selector_yield(&selector->backend);
}
|