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
-
.__map_exc(ret) ⇒ Object
:nodoc:.
-
.__map_splice_flags(flags) ⇒ Object
:nodoc:.
-
.__splice(io_in, off_in, io_out, off_out, len, flags) ⇒ Object
:nodoc:.
-
.__tee(io_in, io_out, len, flags) ⇒ Object
:nodoc:.
-
.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.
-
.linux_sendfile(dst, src, len, offset: nil) ⇒ Object
Copies
lenbytes fromsrctodst, wheresrcrefers to an open, mmap(2)-able File anddstrefers to a Socket. -
.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.
-
.tee(io_in, io_out, len, flags = 0, exception: true) ⇒ Object
call-seq: SleepyPenguin.tee(io_in, io_out, len[, flags[, keywords]) => Integer.
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 |