class SleepyPenguin::EventFD

Applications may use EventFD instead of a pipe in cases where a pipe is only used to signal events. The kernel overhead for an EventFD descriptor is much lower than that of a pipe.

As of Linux 2.6.30, an EventFD may also be used as a semaphore.

Constants

MAX

the maximum value that may be stored in an EventFD, currently 0xfffffffffffffffe

Public Class Methods

new(initial_value [, flags]) → EventFD IO object click to toggle source

Creates an EventFD object. initial_value is a non-negative Integer to start the internal counter at.

Starting with Linux 2.6.27, flags may be a mask that consists of any of the following:

  • :CLOEXEC - set the close-on-exec flag on the new object

  • :NONBLOCK - set the non-blocking I/O flag on the new object

Since Linux 2.6.30, flags may also include:

  • :SEMAPHORE - provides semaphore-like semantics (see EventFD#value)

static VALUE s_new(int argc, VALUE *argv, VALUE klass)
{
        VALUE _initval, _flags, rv;
        unsigned initval;
        int flags;
        int fd;

        rb_scan_args(argc, argv, "11", &_initval, &_flags);
        initval = NUM2UINT(_initval);
        flags = rb_sp_get_flags(klass, _flags, RB_SP_CLOEXEC(EFD_CLOEXEC));

        fd = eventfd(initval, flags);
        if (fd < 0) {
                if (rb_sp_gc_for_fd(errno))
                        fd = eventfd(initval, flags);
                if (fd < 0)
                        rb_sys_fail("eventfd");
        }

        rv = INT2FIX(fd);
        return rb_call_super(1, &rv);
}

Public Instance Methods

incr(integer_value[, nonblock ]) → true or nil click to toggle source

Increments the internal counter by integer_value which is an unsigned Integer value.

If nonblock is specified and true, this will return nil if the internal counter will overflow the value of EventFD::MAX. Otherwise it will block until the counter may be incremented without overflowing.

static VALUE incr(int argc, VALUE *argv, VALUE self)
{
        struct efd_args x;
        ssize_t w;
        VALUE value, nonblock;

        rb_scan_args(argc, argv, "11", &value, &nonblock);
        x.fd = rb_sp_fileno(self);
        if (RTEST(nonblock))
                rb_sp_set_nonblock(x.fd);

        x.val = (uint64_t)NUM2ULL(value);
retry:
        w = (ssize_t)rb_sp_fd_region(efd_write, &x, x.fd);
        if (w < 0) {
                if (errno == EAGAIN && RTEST(nonblock))
                        return Qfalse;
                if (rb_sp_wait(rb_io_wait_writable, self, &x.fd))
                        goto retry;
                rb_sys_fail("write(eventfd)");
        }

        return Qtrue;
}
value([nonblock]) → Integer or nil click to toggle source

If not created as a semaphore, returns the current value and resets the counter to zero.

If created as a semaphore, this decrements the counter value by one and returns 1.

If the counter is zero at the time of the call, this will block until the counter becomes non-zero unless nonblock is true, in which case it returns nil.

static VALUE getvalue(int argc, VALUE *argv, VALUE self)
{
        struct efd_args x;
        ssize_t w;
        VALUE nonblock;

        rb_scan_args(argc, argv, "01", &nonblock);
        x.fd = rb_sp_fileno(self);
        if (RTEST(nonblock))
                rb_sp_set_nonblock(x.fd);
retry:
        w = (ssize_t)rb_sp_fd_region(efd_read, &x, x.fd);
        if (w < 0) {
                if (errno == EAGAIN && RTEST(nonblock))
                        return Qnil;
                if (rb_sp_wait(rb_io_wait_readable, self, &x.fd))
                        goto retry;
                rb_sys_fail("read(eventfd)");
        }

        return ULL2NUM(x.val);
}