Module: SleepyPenguin

Defined in:
ext/sleepy_penguin/epoll.c,
lib/sleepy_penguin/cfr.rb,
lib/sleepy_penguin/splice.rb,
ext/sleepy_penguin/epoll.c,
ext/sleepy_penguin/eventfd.c,
ext/sleepy_penguin/init.c,
ext/sleepy_penguin/inotify.c,
ext/sleepy_penguin/timerfd.c,
ext/sleepy_penguin/kqueue.c,
ext/sleepy_penguin/splice.c,
lib/sleepy_penguin.rb

Overview

require “sleepy_penguin” include SleepyPenguin

The SleepyPenguin namespace includes the Epoll, Inotify, TimerFD, EventFD classes in its top level and no other constants.

If you are uncomfortable including SleepyPenguin, you may also use the “SP” alias if it doesn’t conflict with existing code:

require “sleepy_penguin/sp”

And then access classes via:

  • SP::Epoll

  • SP::Epoll::IO

  • SP::EventFD

  • SP::Inotify

  • SP::TimerFD

Defined Under Namespace

Modules: Ev, EvFilt, Note, VQ Classes: Epoll, EventFD, Inotify, Kevent, Kqueue, TimerFD

Constant Summary collapse

SLEEPY_PENGUIN_VERSION =
rb_str_new2(MY_GIT_VERSION)
F_MOVE =

Attempt to move pages instead of copying. This is only a hint and support for it was removed in Linux 2.6.21. It will be re-added for FUSE filesystems only in Linux 2.6.35.

UINT2NUM(SPLICE_F_MOVE)
F_NONBLOCK =

Do not block on pipe I/O. This flag only affects the pipe(s) being spliced from/to and has no effect on the non-pipe descriptor (which requires non-blocking operation to be set explicitly).

The non-blocking flag (O_NONBLOCK) on the pipe descriptors themselves are ignored by this family of functions, and using this flag is the only way to get non-blocking operation out of them.

It is highly recommended this flag be set whenever splicing from a socket into a pipe unless there is another (native) thread or process doing a blocking read on that pipe. Otherwise it is possible to block a single-threaded process if the socket buffers are larger than the pipe buffers.

UINT2NUM(SPLICE_F_NONBLOCK)
F_MORE =

Indicate that there may be more data coming into the outbound descriptor. This can allow the kernel to avoid sending partial frames from sockets. Currently only used with splice.

UINT2NUM(SPLICE_F_MORE)
F_GETPIPE_SZ =

:F_GETPIPE_SZ) => Integer

fcntl() command constant used to return the size of a pipe.
This constant is only defined when running Linux 2.6.35
or later.

require 'fcntl'
r, w = IO.pipe
r.fcntl(SleepyPenguin
F_SETPIPE_SZ =

require ‘fcntl’ r, w = IO.pipe r.fcntl(SleepyPenguin::F_SETPIPE_SZ, 131072)

fcntl() command constant used to set the size of a pipe.
This constant is only defined when running Linux 2.6.35
or later.

call-seq

Class Method Summary collapse

Class Method Details

.__map_exc(ret) ⇒ Object

:nodoc:



118
119
120
121
122
123
124
# File 'lib/sleepy_penguin/splice.rb', line 118

def self.__map_exc(ret) # :nodoc:
  case ret
  when :EAGAIN then raise Errno::EAGAIN, 'Resource temporarily unavailable'
  when nil then raise EOFError, 'end of file reached'
  end
  ret
end

.__map_splice_flags(flags) ⇒ Object

:nodoc:



112
113
114
115
116
# File 'lib/sleepy_penguin/splice.rb', line 112

def self.__map_splice_flags(flags) # :nodoc:
  onef = @__splice_f_map[flags] and return onef
  flags.respond_to?(:inject) ?
      flags.inject(0) { |fl, sym| fl |= @__splice_f_map[sym] } : flags
end

.__splice(io_in, off_in, io_out, off_out, len, flags) ⇒ Object

:nodoc:



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'ext/sleepy_penguin/splice.c', line 38

static VALUE my_splice(VALUE mod, VALUE io_in, VALUE off_in,
			VALUE io_out, VALUE off_out,
			VALUE len, VALUE flags)
{
	off_t i = 0, o = 0;
	struct copy_args a;
	ssize_t bytes;

	a.off_in = NIL_P(off_in) ? NULL : (i = NUM2OFFT(off_in), &i);
	a.off_out = NIL_P(off_out) ? NULL : (o = NUM2OFFT(off_out), &o);
	a.len = NUM2SIZET(len);
	a.flags = NUM2UINT(flags);

	for (;;) {
		a.fd_in = check_fileno(io_in);
		a.fd_out = check_fileno(io_out);
		bytes = (ssize_t)IO_RUN(nogvl_splice, &a);
		if (bytes == 0) return Qnil;
		if (bytes < 0) {
			switch (errno) {
			case EINTR: continue;
			case EAGAIN: return sym_EAGAIN;
			default: rb_sys_fail("splice");
			}
		}
		return SSIZET2NUM(bytes);
	}
}

.__tee(io_in, io_out, len, flags) ⇒ Object

:nodoc:



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'ext/sleepy_penguin/splice.c', line 83

static VALUE my_tee(VALUE mod, VALUE io_in, VALUE io_out,
			VALUE len, VALUE flags)
{
	struct tee_args a;
	ssize_t bytes;

	a.len = (size_t)NUM2SIZET(len);
	a.flags = NUM2UINT(flags);

	for (;;) {
		a.fd_in = check_fileno(io_in);
		a.fd_out = check_fileno(io_out);
		bytes = (ssize_t)IO_RUN(nogvl_tee, &a);
		if (bytes == 0) return Qnil;
		if (bytes < 0) {
			switch (errno) {
			case EINTR: continue;
			case EAGAIN: return sym_EAGAIN;
			default: rb_sys_fail("tee");
			}
		}
		return SSIZET2NUM(bytes);
	}
}

.copy_file_range(io_in, io_out, len, flags = 0, off_in: nil, off_out: nil) ⇒ Object

call-seq:

SleepyPenguin.copy_file_range(src, dst, len[, keywords]) => # Integer

Performs and in-kernel copy of len bytes from src to dst, where src and dst are regular files on the same filesystem. Returns the number of bytes copied, which may be less than requested.

flags is currently unused, but may be specified in the future.

Keywords:

:off_in and :off_out if non-nil may be used to specify an Integer offset for each respective descriptor. If specified, the file offsets of each file description will not be moved, providing pread(2)/pwrite(2)-like semantics.

See copy_file_range(2) manpage for full documentation: man7.org/linux/man-pages/man2/copy_file_range.2.html

This method only works in Linux 4.5+ with sleepy_penguin 3.5.0+, and may require up-to-date kernel headers for non-x86/x86-64 systems.



25
26
27
28
# File 'lib/sleepy_penguin/cfr.rb', line 25

def self.copy_file_range(io_in, io_out, len, flags = 0,
                         off_in: nil, off_out: nil)
  __cfr(io_in, off_in, io_out, off_out, len, flags)
end

.linux_sendfile(dst, src, len, offset: nil) ⇒ Object

Copies len bytes from src to dst, where src refers to an open, mmap(2)-able File and dst refers to a Socket. An optional offset keyword may be specified for the src File. Using offset will not adjust the offset of the underlying file handle itself; in other words: this allows concurrent threads to use linux_sendfile to write data from one open file to multiple sockets.

Returns the number of bytes written on success, or :wait_writable if the dst Socket is non-blocking and the operation would block. A return value of zero bytes indicates EOF is reached on the src file.

Newer OSes may be more flexible in whether or not dst or src is a regular file or socket, respectively.

This method was added in sleepy_penguin 3.5.0.



42
43
44
# File 'lib/sleepy_penguin.rb', line 42

def self.linux_sendfile(dst, src, len, offset: nil)
  __lsf(dst, src, offset, len)
end

.splice(io_in, io_out, len, flags = 0, off_in: nil, off_out: nil, exception: true) ⇒ Object

call-seq:

SleepyPenguin.splice(io_in, io_out, len[, flags [, keywords]) => Integer

Splice len bytes from/to a pipe. Either io_in or io_out MUST be a pipe. io_in and io_out may BOTH be pipes as of Linux 2.6.31 or later.

flags defaults to zero if unspecified. It may be an Integer bitmask, a Symbol, or Array of Symbols

The integer bitmask may any combination of:

  • SleepyPenguin::F_MOVE - attempt to move pages instead of copying

  • SleepyPenguin::F_NONBLOCK - do not block on pipe I/O (only)

  • SleepyPenguin::F_MORE - indicates more data will be sent soon

Symbols may be used as well to specify a single flag:

  • :move - corresponds to F_MOVE

  • :nonblock - corresponds to F_NONBLOCK

  • :more - corresponds to F_MORE

Or, an array of any combination of the above symbols.

Keywords:

:off_in and :off_out if non-nil may be used to

specify an offset for the respective non-pipe file descriptor.

:exception defaults to true. Setting it to false will return :EAGAIN symbol instead of raising Errno::EAGAIN. This will also return nil instead of raising EOFError when io_in is at the end.

Raises EOFError when io_in has reached end of file. Raises Errno::EAGAIN if the SleepyPenguin::F_NONBLOCK flag is set and the pipe has no data to read from or space to write to. May also raise Errno::EAGAIN if the non-pipe descriptor has no data to read from or space to write to.

As splice never exposes buffers to userspace, it will not take into account userspace buffering done by Ruby or stdio. It is also not subject to encoding/decoding filters under Ruby 1.9+.

Consider using ‘exception: false` if io_out is a pipe or if you are using non-blocking I/O on both descriptors as it avoids the cost of raising common Errno::EAGAIN exceptions.

See manpage for full documentation: man7.org/linux/man-pages/man2/splice.2.html

Support for this exists in sleepy_penguin 3.5.0+



58
59
60
61
62
63
# File 'lib/sleepy_penguin/splice.rb', line 58

def self.splice(io_in, io_out, len, flags = 0,
                off_in: nil, off_out: nil, exception: true)
  flags = __map_splice_flags(flags)
  ret = __splice(io_in, off_in, io_out, off_out, len, flags)
  exception ? __map_exc(ret) : ret
end

.tee(io_in, io_out, len, flags = 0, exception: true) ⇒ Object

call-seq:

SleepyPenguin.tee(io_in, io_out, len[, flags[, keywords]) => Integer

Copies up to len bytes of data from io_in to io_out. io_in and io_out must both refer to pipe descriptors. io_in and io_out may not be endpoints of the same pipe.

flags may be zero (the default) or a combination of:

  • SleepyPenguin::F_NONBLOCK

As a shortcut, the ‘:nonblock` symbol may be used instead.

Other splice-related flags are currently unimplemented in the kernel and have no effect.

Returns the number of bytes duplicated if successful. Raises EOFError when io_in is closed and emptied. Raises Errno::EAGAIN when io_in is empty and/or io_out is full and flags specifies non-blocking operation

Keywords:

:exception defaults to true. Setting it to false will return :EAGAIN symbol instead of raising Errno::EAGAIN. This will also return nil instead of raising EOFError when io_in is at the end.

Consider using ‘exception: false` if io_out is a pipe or if you are using non-blocking I/O on both descriptors as it avoids the cost of raising common Errno::EAGAIN exceptions.

See manpage for full documentation: man7.org/linux/man-pages/man2/tee.2.html

Support for this exists in sleepy_penguin 3.5.0+



100
101
102
103
104
# File 'lib/sleepy_penguin/splice.rb', line 100

def self.tee(io_in, io_out, len, flags = 0, exception: true)
  flags = __map_splice_flags(flags)
  ret = __tee(io_in, io_out, len, flags)
  exception ? __map_exc(ret) : ret
end