diff options
Diffstat (limited to 'ext/io')
-rw-r--r-- | ext/io/console/depend | 1 | ||||
-rw-r--r-- | ext/io/nonblock/depend | 1 | ||||
-rw-r--r-- | ext/io/nonblock/io-nonblock.gemspec | 16 | ||||
-rw-r--r-- | ext/io/nonblock/nonblock.c | 67 | ||||
-rw-r--r-- | ext/io/wait/depend | 1 | ||||
-rw-r--r-- | ext/io/wait/extconf.rb | 32 | ||||
-rw-r--r-- | ext/io/wait/io-wait.gemspec | 23 | ||||
-rw-r--r-- | ext/io/wait/wait.c | 51 |
8 files changed, 134 insertions, 58 deletions
diff --git a/ext/io/console/depend b/ext/io/console/depend index e6014dcc59..06ccdde70d 100644 --- a/ext/io/console/depend +++ b/ext/io/console/depend @@ -16,6 +16,7 @@ console.o: $(hdrdir)/ruby/defines.h console.o: $(hdrdir)/ruby/encoding.h console.o: $(hdrdir)/ruby/fiber/scheduler.h console.o: $(hdrdir)/ruby/intern.h +console.o: $(hdrdir)/ruby/internal/abi.h console.o: $(hdrdir)/ruby/internal/anyargs.h console.o: $(hdrdir)/ruby/internal/arithmetic.h console.o: $(hdrdir)/ruby/internal/arithmetic/char.h diff --git a/ext/io/nonblock/depend b/ext/io/nonblock/depend index 664c262e35..7f2db65732 100644 --- a/ext/io/nonblock/depend +++ b/ext/io/nonblock/depend @@ -15,6 +15,7 @@ nonblock.o: $(hdrdir)/ruby/backward/2/stdarg.h nonblock.o: $(hdrdir)/ruby/defines.h nonblock.o: $(hdrdir)/ruby/encoding.h nonblock.o: $(hdrdir)/ruby/intern.h +nonblock.o: $(hdrdir)/ruby/internal/abi.h nonblock.o: $(hdrdir)/ruby/internal/anyargs.h nonblock.o: $(hdrdir)/ruby/internal/arithmetic.h nonblock.o: $(hdrdir)/ruby/internal/arithmetic/char.h diff --git a/ext/io/nonblock/io-nonblock.gemspec b/ext/io/nonblock/io-nonblock.gemspec index 34d736650b..f81d4fda0a 100644 --- a/ext/io/nonblock/io-nonblock.gemspec +++ b/ext/io/nonblock/io-nonblock.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |spec| spec.name = "io-nonblock" - spec.version = "0.1.0" + spec.version = "0.1.1" spec.authors = ["Nobu Nakada"] spec.email = ["nobu@ruby-lang.org"] @@ -13,13 +13,13 @@ Gem::Specification.new do |spec| spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = spec.homepage - spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do - %x[git ls-files -z].split("\x0").reject do |f| - f.match(%r{\A(?:test|spec|features)/|\A\.(?:git|travis)}) - end - end + spec.files = %w[ + COPYING + README.md + ext/io/nonblock/depend + ext/io/nonblock/extconf.rb + ext/io/nonblock/nonblock.c + ] spec.extensions = %w[ext/io/nonblock/extconf.rb] - spec.bindir = "exe" - spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] end diff --git a/ext/io/nonblock/nonblock.c b/ext/io/nonblock/nonblock.c index 1c0bdc68e7..b8a40ff38e 100644 --- a/ext/io/nonblock/nonblock.c +++ b/ext/io/nonblock/nonblock.c @@ -19,14 +19,14 @@ #ifdef F_GETFL static int -io_nonblock_mode(int fd) +get_fcntl_flags(int fd) { int f = fcntl(fd, F_GETFL); if (f == -1) rb_sys_fail(0); return f; } #else -#define io_nonblock_mode(fd) ((void)(fd), 0) +#define get_fcntl_flags(fd) ((void)(fd), 0) #endif #ifdef F_GETFL @@ -41,7 +41,7 @@ rb_io_nonblock_p(VALUE io) { rb_io_t *fptr; GetOpenFile(io, fptr); - if (io_nonblock_mode(fptr->fd) & O_NONBLOCK) + if (get_fcntl_flags(fptr->fd) & O_NONBLOCK) return Qtrue; return Qfalse; } @@ -50,6 +50,13 @@ rb_io_nonblock_p(VALUE io) #endif #ifdef F_SETFL +static void +set_fcntl_flags(int fd, int f) +{ + if (fcntl(fd, F_SETFL, f) == -1) + rb_sys_fail(0); +} + static int io_nonblock_set(int fd, int f, int nb) { @@ -63,8 +70,7 @@ io_nonblock_set(int fd, int f, int nb) return 0; f &= ~O_NONBLOCK; } - if (fcntl(fd, F_SETFL, f) == -1) - rb_sys_fail(0); + set_fcntl_flags(fd, f); return 1; } @@ -74,6 +80,46 @@ io_nonblock_set(int fd, int f, int nb) * * Enables non-blocking mode on a stream when set to * +true+, and blocking mode when set to +false+. + * + * This method set or clear O_NONBLOCK flag for the file descriptor + * in <em>ios</em>. + * + * The behavior of most IO methods is not affected by this flag + * because they retry system calls to complete their task + * after EAGAIN and partial read/write. + * (An exception is IO#syswrite which doesn't retry.) + * + * This method can be used to clear non-blocking mode of standard I/O. + * Since nonblocking methods (read_nonblock, etc.) set non-blocking mode but + * they doesn't clear it, this method is usable as follows. + * + * END { STDOUT.nonblock = false } + * STDOUT.write_nonblock("foo") + * + * Since the flag is shared across processes and + * many non-Ruby commands doesn't expect standard I/O with non-blocking mode, + * it would be safe to clear the flag before Ruby program exits. + * + * For example following Ruby program leaves STDIN/STDOUT/STDER non-blocking mode. + * (STDIN, STDOUT and STDERR are connected to a terminal. + * So making one of them nonblocking-mode effects other two.) + * Thus cat command try to read from standard input and + * it causes "Resource temporarily unavailable" error (EAGAIN). + * + * % ruby -e ' + * STDOUT.write_nonblock("foo\n")'; cat + * foo + * cat: -: Resource temporarily unavailable + * + * Clearing the flag makes the behavior of cat command normal. + * (cat command waits input from standard input.) + * + * % ruby -rio/nonblock -e ' + * END { STDOUT.nonblock = false } + * STDOUT.write_nonblock("foo") + * '; cat + * foo + * */ static VALUE rb_io_nonblock_set(VALUE io, VALUE nb) @@ -83,7 +129,7 @@ rb_io_nonblock_set(VALUE io, VALUE nb) if (RTEST(nb)) rb_io_set_nonblock(fptr); else - io_nonblock_set(fptr->fd, io_nonblock_mode(fptr->fd), RTEST(nb)); + io_nonblock_set(fptr->fd, get_fcntl_flags(fptr->fd), RTEST(nb)); return io; } @@ -91,15 +137,14 @@ static VALUE io_nonblock_restore(VALUE arg) { int *restore = (int *)arg; - if (fcntl(restore[0], F_SETFL, restore[1]) == -1) - rb_sys_fail(0); + set_fcntl_flags(restore[0], restore[1]); return Qnil; } /* * call-seq: - * io.nonblock {|io| } -> io - * io.nonblock(boolean) {|io| } -> io + * io.nonblock {|io| } -> object + * io.nonblock(boolean) {|io| } -> object * * Yields +self+ in non-blocking mode. * @@ -119,7 +164,7 @@ rb_io_nonblock_block(int argc, VALUE *argv, VALUE io) rb_scan_args(argc, argv, "01", &v); nb = RTEST(v); } - f = io_nonblock_mode(fptr->fd); + f = get_fcntl_flags(fptr->fd); restore[0] = fptr->fd; restore[1] = f; if (!io_nonblock_set(fptr->fd, f, nb)) diff --git a/ext/io/wait/depend b/ext/io/wait/depend index 0426a6a1ed..51e1af8280 100644 --- a/ext/io/wait/depend +++ b/ext/io/wait/depend @@ -16,6 +16,7 @@ wait.o: $(hdrdir)/ruby/backward/2/stdarg.h wait.o: $(hdrdir)/ruby/defines.h wait.o: $(hdrdir)/ruby/encoding.h wait.o: $(hdrdir)/ruby/intern.h +wait.o: $(hdrdir)/ruby/internal/abi.h wait.o: $(hdrdir)/ruby/internal/anyargs.h wait.o: $(hdrdir)/ruby/internal/arithmetic.h wait.o: $(hdrdir)/ruby/internal/arithmetic/char.h diff --git a/ext/io/wait/extconf.rb b/ext/io/wait/extconf.rb index d20ff4553f..eecdcce99f 100644 --- a/ext/io/wait/extconf.rb +++ b/ext/io/wait/extconf.rb @@ -1,20 +1,24 @@ # frozen_string_literal: false require 'mkmf' -target = "io/wait" -have_func("rb_io_wait") -unless macro_defined?("DOSISH", "#include <ruby.h>") - have_header(ioctl_h = "sys/ioctl.h") or ioctl_h = nil - fionread = %w[sys/ioctl.h sys/filio.h sys/socket.h].find do |h| - have_macro("FIONREAD", [h, ioctl_h].compact) - end - if fionread - $defs << "-DFIONREAD_HEADER=\"<#{fionread}>\"" - create_makefile(target) - end +if RUBY_VERSION < "2.6" + File.write("Makefile", dummy_makefile($srcdir).join("")) else - if have_func("rb_w32_ioctlsocket", "ruby.h") - have_func("rb_w32_is_socket", "ruby.h") - create_makefile(target) + target = "io/wait" + have_func("rb_io_wait") + unless macro_defined?("DOSISH", "#include <ruby.h>") + have_header(ioctl_h = "sys/ioctl.h") or ioctl_h = nil + fionread = %w[sys/ioctl.h sys/filio.h sys/socket.h].find do |h| + have_macro("FIONREAD", [h, ioctl_h].compact) + end + if fionread + $defs << "-DFIONREAD_HEADER=\"<#{fionread}>\"" + create_makefile(target) + end + else + if have_func("rb_w32_ioctlsocket", "ruby.h") + have_func("rb_w32_is_socket", "ruby.h") + create_makefile(target) + end end end diff --git a/ext/io/wait/io-wait.gemspec b/ext/io/wait/io-wait.gemspec index ec7c05dd87..b633421e48 100644 --- a/ext/io/wait/io-wait.gemspec +++ b/ext/io/wait/io-wait.gemspec @@ -1,27 +1,38 @@ -_VERSION = "0.2.1" +_VERSION = "0.2.3" Gem::Specification.new do |spec| spec.name = "io-wait" spec.version = _VERSION - spec.authors = ["Nobu Nakada"] - spec.email = ["nobu@ruby-lang.org"] + spec.authors = ["Nobu Nakada", "Charles Oliver Nutter"] + spec.email = ["nobu@ruby-lang.org", "headius@headius.com"] spec.summary = %q{Waits until IO is readable or writable without blocking.} spec.description = %q{Waits until IO is readable or writable without blocking.} spec.homepage = "https://github.com/ruby/io-wait" spec.licenses = ["Ruby", "BSD-2-Clause"] - spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0") spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = spec.homepage spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do `git ls-files -z`.split("\x0").reject do |f| - f.match(%r{\A(?:test|spec|features)/|\A\.(?:git|travis)}) + File.identical?(f, __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features|rakelib)/|\.(?:git|travis|circleci)|appveyor|Rakefile)}) end end - spec.extensions = %w[ext/io/wait/extconf.rb] spec.bindir = "exe" spec.executables = [] spec.require_paths = ["lib"] + + jruby = true if Gem::Platform.new('java') =~ spec.platform or RUBY_ENGINE == 'jruby' + spec.files.delete_if do |f| + f.end_with?(".java") or + f.start_with?("ext/") && (jruby ^ f.start_with?("ext/java/")) + end + if jruby + spec.platform = 'java' + spec.files << "lib/io/wait.jar" + spec.require_paths += ["ext/java/lib"] + else + spec.extensions = %w[ext/io/wait/extconf.rb] + end end diff --git a/ext/io/wait/wait.c b/ext/io/wait/wait.c index 8f0d16e168..568c7b54a8 100644 --- a/ext/io/wait/wait.c +++ b/ext/io/wait/wait.c @@ -77,6 +77,8 @@ wait_for_single_fd(rb_io_t *fptr, int events, struct timeval *tv) * * Returns number of bytes that can be read without blocking. * Returns zero if no information available. + * + * You must require 'io/wait' to use this method. */ static VALUE @@ -119,9 +121,12 @@ io_wait_event(VALUE io, int event, VALUE timeout) /* * call-seq: - * io.ready? -> true or false + * io.ready? -> truthy or falsy + * + * Returns a truthy value if input available without blocking, or a + * falsy value. * - * Returns +true+ if input available without blocking, or +false+. + * You must require 'io/wait' to use this method. */ static VALUE @@ -148,12 +153,14 @@ io_ready_p(VALUE io) /* * call-seq: - * io.wait_readable -> true or false - * io.wait_readable(timeout) -> true or false + * io.wait_readable -> truthy or falsy + * io.wait_readable(timeout) -> truthy or falsy + * + * Waits until IO is readable and returns a truthy value, or a falsy + * value when times out. Returns a truthy value immediately when + * buffered data is available. * - * Waits until IO is readable and returns +true+, or - * +false+ when times out. - * Returns +true+ immediately when buffered data is available. + * You must require 'io/wait' to use this method. */ static VALUE @@ -188,11 +195,13 @@ io_wait_readable(int argc, VALUE *argv, VALUE io) /* * call-seq: - * io.wait_writable -> true or false - * io.wait_writable(timeout) -> true or false + * io.wait_writable -> truthy or falsy + * io.wait_writable(timeout) -> truthy or falsy * - * Waits until IO is writable and returns +true+ or - * +false+ when times out. + * Waits until IO is writable and returns a truthy value or a falsy + * value when times out. + * + * You must require 'io/wait' to use this method. */ static VALUE io_wait_writable(int argc, VALUE *argv, VALUE io) @@ -223,11 +232,13 @@ io_wait_writable(int argc, VALUE *argv, VALUE io) #ifdef HAVE_RB_IO_WAIT /* * call-seq: - * io.wait_priority -> true or false - * io.wait_priority(timeout) -> true or false + * io.wait_priority -> truthy or falsy + * io.wait_priority(timeout) -> truthy or falsy + * + * Waits until IO is priority and returns a truthy value or a falsy + * value when times out. * - * Waits until IO is priority and returns +true+ or - * +false+ when times out. + * You must require 'io/wait' to use this method. */ static VALUE io_wait_priority(int argc, VALUE *argv, VALUE io) @@ -282,19 +293,21 @@ wait_mode_sym(VALUE mode) /* * call-seq: - * io.wait(events, timeout) -> event mask or false. - * io.wait(timeout = nil, mode = :read) -> event mask or false. + * io.wait(events, timeout) -> truthy or falsy + * io.wait(timeout = nil, mode = :read) -> truthy or falsy. * * Waits until the IO becomes ready for the specified events and returns the - * subset of events that become ready, or +false+ when times out. + * subset of events that become ready, or a falsy value when times out. * * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or * +IO::PRIORITY+. * - * Returns +true+ immediately when buffered data is available. + * Returns a truthy value immediately when buffered data is available. * * Optional parameter +mode+ is one of +:read+, +:write+, or * +:read_write+. + * + * You must require 'io/wait' to use this method. */ static VALUE |