io-nonblock 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e7f197b776a167ab8e464d769208e51374e123069c567469f5ace8329bcdaa37
4
- data.tar.gz: 482709a0e5dd558e54a6bcd1329df17a91d36cb6910585446b1685a5389d5af1
3
+ metadata.gz: 72722b1ffc6a232b51665e937ecabe164a15e2dbccdb35628fe158db78e56713
4
+ data.tar.gz: 491aa2cbbb825667d190e5dca3f3ef44abb7fcc65d2a5080e33f5fa4936142f0
5
5
  SHA512:
6
- metadata.gz: 5e55dadc9959a30f527985b7afdb0297dfbdc9b0680a49037099ce0205301992cfbcccd84aa52f18704529d31afb30bc1b033f2284902714fea5e38e5344f60f
7
- data.tar.gz: '00328f04184febef11667804acc88257c28383fbfb65a54649b16fbe1937172af000798ca201aaf2cdd44c572b37dff48b0cc14cdc436b162efc8e437b3e89cd'
6
+ metadata.gz: 9c1e8c2abd77710e460dc12c39a89f2bf3e2466208bc422e97ec1891629d71d569c95c8b80beadd0ef5f5673c53f4101f016930038770266b2f62732972f7b65
7
+ data.tar.gz: 3045f739c5bdcbef2c1335bfd0024842e5be44d0af0a3a90fb49c3ca9151fa02e74520cc854b3207e328b8c1a7f19fde5b580ad121c511590860e484de5b335d
@@ -2,6 +2,13 @@
2
2
  require 'mkmf'
3
3
  target = "io/nonblock"
4
4
 
5
+ unless RUBY_ENGINE == 'ruby'
6
+ File.write("Makefile", dummy_makefile($srcdir).join(""))
7
+ return
8
+ end
9
+
10
+ have_func("rb_io_descriptor")
11
+
5
12
  hdr = %w"fcntl.h"
6
13
  if have_macro("O_NONBLOCK", hdr) and
7
14
  (have_macro("F_GETFL", hdr) or have_macro("F_SETFL", hdr))
@@ -17,16 +17,27 @@
17
17
  #endif
18
18
  #include <fcntl.h>
19
19
 
20
+ #ifndef HAVE_RB_IO_DESCRIPTOR
21
+ static int
22
+ io_descriptor_fallback(VALUE io)
23
+ {
24
+ rb_io_t *fptr;
25
+ GetOpenFile(io, fptr);
26
+ return fptr->fd;
27
+ }
28
+ #define rb_io_descriptor io_descriptor_fallback
29
+ #endif
30
+
20
31
  #ifdef F_GETFL
21
32
  static int
22
- io_nonblock_mode(int fd)
33
+ get_fcntl_flags(int fd)
23
34
  {
24
35
  int f = fcntl(fd, F_GETFL);
25
36
  if (f == -1) rb_sys_fail(0);
26
37
  return f;
27
38
  }
28
39
  #else
29
- #define io_nonblock_mode(fd) ((void)(fd), 0)
40
+ #define get_fcntl_flags(fd) ((void)(fd), 0)
30
41
  #endif
31
42
 
32
43
  #ifdef F_GETFL
@@ -39,10 +50,8 @@ io_nonblock_mode(int fd)
39
50
  static VALUE
40
51
  rb_io_nonblock_p(VALUE io)
41
52
  {
42
- rb_io_t *fptr;
43
- GetOpenFile(io, fptr);
44
- if (io_nonblock_mode(fptr->fd) & O_NONBLOCK)
45
- return Qtrue;
53
+ if (get_fcntl_flags(rb_io_descriptor(io)) & O_NONBLOCK)
54
+ return Qtrue;
46
55
  return Qfalse;
47
56
  }
48
57
  #else
@@ -50,6 +59,15 @@ rb_io_nonblock_p(VALUE io)
50
59
  #endif
51
60
 
52
61
  #ifdef F_SETFL
62
+ static void
63
+ set_fcntl_flags(int fd, int f)
64
+ {
65
+ if (fcntl(fd, F_SETFL, f) == -1)
66
+ rb_sys_fail(0);
67
+ }
68
+
69
+ #ifndef RUBY_IO_NONBLOCK_METHODS
70
+
53
71
  static int
54
72
  io_nonblock_set(int fd, int f, int nb)
55
73
  {
@@ -63,8 +81,7 @@ io_nonblock_set(int fd, int f, int nb)
63
81
  return 0;
64
82
  f &= ~O_NONBLOCK;
65
83
  }
66
- if (fcntl(fd, F_SETFL, f) == -1)
67
- rb_sys_fail(0);
84
+ set_fcntl_flags(fd, f);
68
85
  return 1;
69
86
  }
70
87
 
@@ -74,32 +91,77 @@ io_nonblock_set(int fd, int f, int nb)
74
91
  *
75
92
  * Enables non-blocking mode on a stream when set to
76
93
  * +true+, and blocking mode when set to +false+.
94
+ *
95
+ * This method set or clear O_NONBLOCK flag for the file descriptor
96
+ * in <em>ios</em>.
97
+ *
98
+ * The behavior of most IO methods is not affected by this flag
99
+ * because they retry system calls to complete their task
100
+ * after EAGAIN and partial read/write.
101
+ * (An exception is IO#syswrite which doesn't retry.)
102
+ *
103
+ * This method can be used to clear non-blocking mode of standard I/O.
104
+ * Since nonblocking methods (read_nonblock, etc.) set non-blocking mode but
105
+ * they doesn't clear it, this method is usable as follows.
106
+ *
107
+ * END { STDOUT.nonblock = false }
108
+ * STDOUT.write_nonblock("foo")
109
+ *
110
+ * Since the flag is shared across processes and
111
+ * many non-Ruby commands doesn't expect standard I/O with non-blocking mode,
112
+ * it would be safe to clear the flag before Ruby program exits.
113
+ *
114
+ * For example following Ruby program leaves STDIN/STDOUT/STDER non-blocking mode.
115
+ * (STDIN, STDOUT and STDERR are connected to a terminal.
116
+ * So making one of them nonblocking-mode effects other two.)
117
+ * Thus cat command try to read from standard input and
118
+ * it causes "Resource temporarily unavailable" error (EAGAIN).
119
+ *
120
+ * % ruby -e '
121
+ * STDOUT.write_nonblock("foo\n")'; cat
122
+ * foo
123
+ * cat: -: Resource temporarily unavailable
124
+ *
125
+ * Clearing the flag makes the behavior of cat command normal.
126
+ * (cat command waits input from standard input.)
127
+ *
128
+ * % ruby -rio/nonblock -e '
129
+ * END { STDOUT.nonblock = false }
130
+ * STDOUT.write_nonblock("foo")
131
+ * '; cat
132
+ * foo
133
+ *
77
134
  */
78
135
  static VALUE
79
- rb_io_nonblock_set(VALUE io, VALUE nb)
136
+ rb_io_nonblock_set(VALUE self, VALUE value)
80
137
  {
81
- rb_io_t *fptr;
82
- GetOpenFile(io, fptr);
83
- if (RTEST(nb))
84
- rb_io_set_nonblock(fptr);
85
- else
86
- io_nonblock_set(fptr->fd, io_nonblock_mode(fptr->fd), RTEST(nb));
87
- return io;
138
+ if (RTEST(value)) {
139
+ rb_io_t *fptr;
140
+ GetOpenFile(self, fptr);
141
+ rb_io_set_nonblock(fptr);
142
+ }
143
+ else {
144
+ int descriptor = rb_io_descriptor(self);
145
+ io_nonblock_set(descriptor, get_fcntl_flags(descriptor), RTEST(value));
146
+ }
147
+
148
+ return self;
88
149
  }
89
150
 
151
+ #endif /* RUBY_IO_NONBLOCK_METHODS */
152
+
90
153
  static VALUE
91
154
  io_nonblock_restore(VALUE arg)
92
155
  {
93
156
  int *restore = (int *)arg;
94
- if (fcntl(restore[0], F_SETFL, restore[1]) == -1)
95
- rb_sys_fail(0);
157
+ set_fcntl_flags(restore[0], restore[1]);
96
158
  return Qnil;
97
159
  }
98
160
 
99
161
  /*
100
162
  * call-seq:
101
- * io.nonblock {|io| } -> io
102
- * io.nonblock(boolean) {|io| } -> io
163
+ * io.nonblock {|io| } -> object
164
+ * io.nonblock(boolean) {|io| } -> object
103
165
  *
104
166
  * Yields +self+ in non-blocking mode.
105
167
  *
@@ -107,24 +169,25 @@ io_nonblock_restore(VALUE arg)
107
169
  * The original mode is restored after the block is executed.
108
170
  */
109
171
  static VALUE
110
- rb_io_nonblock_block(int argc, VALUE *argv, VALUE io)
172
+ rb_io_nonblock_block(int argc, VALUE *argv, VALUE self)
111
173
  {
112
174
  int nb = 1;
113
- rb_io_t *fptr;
114
- int f, restore[2];
115
175
 
116
- GetOpenFile(io, fptr);
176
+ int descriptor = rb_io_descriptor(self);
177
+
117
178
  if (argc > 0) {
118
- VALUE v;
119
- rb_scan_args(argc, argv, "01", &v);
120
- nb = RTEST(v);
179
+ VALUE v;
180
+ rb_scan_args(argc, argv, "01", &v);
181
+ nb = RTEST(v);
121
182
  }
122
- f = io_nonblock_mode(fptr->fd);
123
- restore[0] = fptr->fd;
124
- restore[1] = f;
125
- if (!io_nonblock_set(fptr->fd, f, nb))
126
- return rb_yield(io);
127
- return rb_ensure(rb_yield, io, io_nonblock_restore, (VALUE)restore);
183
+
184
+ int current_flags = get_fcntl_flags(descriptor);
185
+ int restore[2] = {descriptor, current_flags};
186
+
187
+ if (!io_nonblock_set(descriptor, current_flags, nb))
188
+ return rb_yield(self);
189
+
190
+ return rb_ensure(rb_yield, self, io_nonblock_restore, (VALUE)restore);
128
191
  }
129
192
  #else
130
193
  #define rb_io_nonblock_set rb_f_notimplement
@@ -134,7 +197,10 @@ rb_io_nonblock_block(int argc, VALUE *argv, VALUE io)
134
197
  void
135
198
  Init_nonblock(void)
136
199
  {
200
+ #ifndef RUBY_IO_NONBLOCK_METHODS
137
201
  rb_define_method(rb_cIO, "nonblock?", rb_io_nonblock_p, 0);
138
202
  rb_define_method(rb_cIO, "nonblock=", rb_io_nonblock_set, 1);
203
+ #endif
204
+
139
205
  rb_define_method(rb_cIO, "nonblock", rb_io_nonblock_block, -1);
140
206
  }
metadata CHANGED
@@ -1,34 +1,28 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: io-nonblock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nobu Nakada
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-18 00:00:00.000000000 Z
11
+ date: 2023-12-13 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Enables non-blocking mode with IO class
14
14
  email:
15
15
  - nobu@ruby-lang.org
16
16
  executables: []
17
- extensions: []
17
+ extensions:
18
+ - ext/io/nonblock/extconf.rb
18
19
  extra_rdoc_files: []
19
20
  files:
20
- - ".gitignore"
21
- - ".travis.yml"
22
21
  - COPYING
23
- - Gemfile
24
22
  - README.md
25
- - Rakefile
26
- - bin/console
27
- - bin/setup
28
23
  - ext/io/nonblock/depend
29
24
  - ext/io/nonblock/extconf.rb
30
25
  - ext/io/nonblock/nonblock.c
31
- - io-nonblock.gemspec
32
26
  homepage: https://github.com/ruby/io-nonblock
33
27
  licenses:
34
28
  - Ruby
@@ -51,7 +45,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
51
45
  - !ruby/object:Gem::Version
52
46
  version: '0'
53
47
  requirements: []
54
- rubygems_version: 3.2.0.rc.1
48
+ rubygems_version: 3.5.0.dev
55
49
  signing_key:
56
50
  specification_version: 4
57
51
  summary: Enables non-blocking mode with IO class
data/.gitignore DELETED
@@ -1,11 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /_yardoc/
4
- /coverage/
5
- /doc/
6
- /pkg/
7
- /spec/reports/
8
- /tmp/
9
- *.bundle
10
- *.dll
11
- *.so
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.8.0
6
- before_install: gem install bundler -v 2.1.4
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in etc.gemspec
4
- gemspec
data/Rakefile DELETED
@@ -1,12 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rake/testtask"
3
-
4
- Rake::TestTask.new(:test) do |t|
5
- t.libs << "test"
6
- t.libs << "lib"
7
- t.test_files = FileList["test/**/test_*.rb"]
8
- end
9
-
10
- require 'rake/extensiontask'
11
- Rake::ExtensionTask.new("io/nonblock")
12
- task :default => :test
data/bin/console DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require "bundler/setup"
4
- require "io/nonblock"
5
-
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
8
-
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
12
-
13
- require "irb"
14
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
data/io-nonblock.gemspec DELETED
@@ -1,22 +0,0 @@
1
- Gem::Specification.new do |spec|
2
- spec.name = "io-nonblock"
3
- spec.version = "0.1.0"
4
- spec.authors = ["Nobu Nakada"]
5
- spec.email = ["nobu@ruby-lang.org"]
6
-
7
- spec.summary = %q{Enables non-blocking mode with IO class}
8
- spec.description = %q{Enables non-blocking mode with IO class}
9
- spec.homepage = "https://github.com/ruby/io-nonblock"
10
- spec.licenses = ["Ruby", "BSD-2-Clause"]
11
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
12
-
13
- spec.metadata["homepage_uri"] = spec.homepage
14
- spec.metadata["source_code_uri"] = spec.homepage
15
-
16
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
17
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
- end
19
- spec.bindir = "exe"
20
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
- spec.require_paths = ["lib"]
22
- end