Skip to content

Commit

Permalink
Updated epoll implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Jun 12, 2021
1 parent ee05a47 commit 314d994
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 55 deletions.
111 changes: 56 additions & 55 deletions ext/event/backend/epoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#include <sys/types.h>
#include <sys/wait.h>

#include "pidfd.c"

static VALUE Event_Backend_EPoll = Qnil;
static ID id_fileno;

Expand Down Expand Up @@ -113,6 +115,60 @@ VALUE Event_Backend_EPoll_close(VALUE self) {
return Qnil;
}

struct process_wait_arguments {
struct Event_Backend_EPoll *data;
pid_t pid;
int flags;
int descriptor;
};

static
VALUE process_wait_transfer(VALUE _arguments) {
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;

Event_Backend_transfer(arguments->data->loop);

return Event_Backend_process_status_wait(arguments->pid);
}

static
VALUE process_wait_ensure(VALUE _arguments) {
struct process_wait_arguments *arguments = (struct process_wait_arguments *)_arguments;

// epoll_ctl(arguments->data->descriptor, EPOLL_CTL_DEL, arguments->descriptor, NULL);

close(arguments->descriptor);

return Qnil;
}

VALUE Event_Backend_EPoll_process_wait(VALUE self, VALUE fiber, VALUE pid, VALUE flags) {
struct Event_Backend_EPoll *data = NULL;
TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);

struct process_wait_arguments process_wait_arguments = {
.data = data,
.pid = NUM2PIDT(pid),
.flags = NUM2INT(flags),
};

process_wait_arguments.descriptor = pidfd_open(process_wait_arguments.pid, 0);
rb_update_max_fd(process_wait_arguments.descriptor);

struct epoll_event event = {
.events = EPOLLIN|EPOLLRDHUP|EPOLLONESHOT,
.data = {.ptr = (void*)fiber},
};

int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, process_wait_arguments.descriptor, &event);

if (result == -1) {
rb_sys_fail("epoll_ctl(process_wait)");
}

return rb_ensure(process_wait_transfer, (VALUE)&process_wait_arguments, process_wait_ensure, (VALUE)&process_wait_arguments);
}

static inline
uint32_t epoll_flags_from_events(int events) {
uint32_t flags = 0;
Expand Down Expand Up @@ -296,61 +352,6 @@ VALUE Event_Backend_EPoll_select(VALUE self, VALUE duration) {
return INT2NUM(arguments.count);
}

VALUE Event_Backend_EPoll_process_wait(VALUE self, VALUE fiber, VALUE pid, VALUE flags) {
pid_t pidv = NUM2PIDT(pid);
int options = NUM2INT(flags);
int state = 0;
int err = 0;

if ((flags & WNOHANG) > 0) {
// WNOHANG is nonblock by default.
pid_t ret = PIDT2NUM(waitpid(pidv, &state, options));
if (ret == -1) err = errno;
return Event_Backend_process_status(pidv, state, err);
}

struct Event_Backend_EPoll *data = NULL;
TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);

struct epoll_event event = {0};

int descriptor = pidfd_open(pidv, 0);
int duplicate = -1;

event.events = EPOLLIN | EPOLLRDHUP | EPOLLONESHOT;
event.data.ptr = (void*)fiber;

// A better approach is to batch all changes:
int result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);

if (result == -1 && errno == EEXIST) {
// The file descriptor was already inserted into epoll.
duplicate = descriptor = dup(descriptor);

rb_update_max_fd(duplicate);

if (descriptor == -1)
rb_sys_fail("dup");

result = epoll_ctl(data->descriptor, EPOLL_CTL_ADD, descriptor, &event);
}

if (result == -1) {
rb_sys_fail("epoll_ctl");
}

struct io_wait_arguments io_wait_arguments = {
.data = data,
.descriptor = descriptor,
.duplicate = duplicate
};

rb_ensure(io_wait_transfer, (VALUE)&io_wait_arguments, io_wait_ensure, (VALUE)&io_wait_arguments);
pid_t ret = PIDT2NUM(waitpid(pidv, &state, options));
if (ret == -1) err = errno;
return Event_Backend_process_status(pidv, state, err);
}

void Init_Event_Backend_EPoll(VALUE Event_Backend) {
id_fileno = rb_intern("fileno");

Expand Down
36 changes: 36 additions & 0 deletions ext/event/backend/pidfd.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <poll.h>
#include <stdlib.h>
#include <stdio.h>

#ifndef __NR_pidfd_open
#define __NR_pidfd_open 434 /* System call # on most architectures */
#endif

static int
pidfd_open(pid_t pid, unsigned int flags)
{
return syscall(__NR_pidfd_open, pid, flags);
}

0 comments on commit 314d994

Please sign in to comment.