Class: SleepyPenguin::EventFD

Inherits:
IO
  • Object
show all
Defined in:
ext/sleepy_penguin/eventfd.c,
ext/sleepy_penguin/eventfd.c

Overview

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.

Constant Summary collapse

MAX =

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

ULL2NUM(0xfffffffffffffffeULL)

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.new(*args) ⇒ Object

EventFD.new(initial_value [, flags]) -> EventFD IO object

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)



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'ext/sleepy_penguin/eventfd.c', line 21

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);
}

Instance Method Details

#incr(*args) ⇒ Object

efd.incr(integer_value[, nonblock ]) -> true or nil

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.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'ext/sleepy_penguin/eventfd.c', line 77

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(*args) ⇒ Object

efd.value() -> Integer or nil

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.



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'ext/sleepy_penguin/eventfd.c', line 116

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);
}