Ruby  3.1.0dev(2021-09-10revisionb76ad15ed0da636161de0243c547ee1e6fc95681)
wait.c
Go to the documentation of this file.
1 /* -*- c-file-style: "ruby"; indent-tabs-mode: t -*- */
2 /**********************************************************************
3 
4  io/wait.c -
5 
6  $Author$
7  created at: Tue Aug 28 09:08:06 JST 2001
8 
9  All the files in this distribution are covered under the Ruby's
10  license (see the file COPYING).
11 
12 **********************************************************************/
13 
14 #include "ruby.h"
15 #include "ruby/io.h"
16 
17 #include <sys/types.h>
18 #if defined(HAVE_UNISTD_H) && (defined(__sun))
19 #include <unistd.h>
20 #endif
21 #if defined(HAVE_SYS_IOCTL_H)
22 #include <sys/ioctl.h>
23 #endif
24 #if defined(FIONREAD_HEADER)
25 #include FIONREAD_HEADER
26 #endif
27 
28 #ifdef HAVE_RB_W32_IOCTLSOCKET
29 #define ioctl ioctlsocket
30 #define ioctl_arg u_long
31 #define ioctl_arg2num(i) ULONG2NUM(i)
32 #else
33 #define ioctl_arg int
34 #define ioctl_arg2num(i) INT2NUM(i)
35 #endif
36 
37 #ifdef HAVE_RB_W32_IS_SOCKET
38 #define FIONREAD_POSSIBLE_P(fd) rb_w32_is_socket(fd)
39 #else
40 #define FIONREAD_POSSIBLE_P(fd) ((void)(fd),Qtrue)
41 #endif
42 
43 /*
44  * call-seq:
45  * io.nread -> int
46  *
47  * Returns number of bytes that can be read without blocking.
48  * Returns zero if no information available.
49  */
50 
51 static VALUE
52 io_nread(VALUE io)
53 {
54  rb_io_t *fptr = NULL;
55  ioctl_arg n;
56 
57  GetOpenFile(io, fptr);
59  int len = rb_io_read_pending(fptr);
60  if (len > 0) return INT2FIX(len);
61  if (!FIONREAD_POSSIBLE_P(fptr->fd)) return INT2FIX(0);
62  if (ioctl(fptr->fd, FIONREAD, &n)) return INT2FIX(0);
63  if (n > 0) return ioctl_arg2num(n);
64  return INT2FIX(0);
65 }
66 
67 static VALUE
68 io_wait_event(VALUE io, int event, VALUE timeout)
69 {
70  VALUE result = rb_io_wait(io, RB_INT2NUM(event), timeout);
71 
72  if (!RB_TEST(result)) {
73  return Qnil;
74  }
75 
76  int mask = RB_NUM2INT(result);
77 
78  if (mask & event) {
79  return io;
80  }
81  else {
82  return Qfalse;
83  }
84 }
85 
86 /*
87  * call-seq:
88  * io.ready? -> true or false
89  *
90  * Returns +true+ if input available without blocking, or +false+.
91  */
92 
93 static VALUE
94 io_ready_p(VALUE io)
95 {
96  rb_io_t *fptr;
97 
98  GetOpenFile(io, fptr);
100  if (rb_io_read_pending(fptr)) return Qtrue;
101 
102  return io_wait_event(io, RUBY_IO_READABLE, RB_INT2NUM(0));
103 }
104 
105 /*
106  * call-seq:
107  * io.wait_readable -> true or false
108  * io.wait_readable(timeout) -> true or false
109  *
110  * Waits until IO is readable and returns +true+, or
111  * +false+ when times out.
112  * Returns +true+ immediately when buffered data is available.
113  */
114 
115 static VALUE
116 io_wait_readable(int argc, VALUE *argv, VALUE io)
117 {
118  rb_io_t *fptr = NULL;
119 
120  RB_IO_POINTER(io, fptr);
121  rb_io_check_readable(fptr);
122 
123  if (rb_io_read_pending(fptr)) return Qtrue;
124 
125  rb_check_arity(argc, 0, 1);
126  VALUE timeout = (argc == 1 ? argv[0] : Qnil);
127 
128  return io_wait_event(io, RUBY_IO_READABLE, timeout);
129 }
130 
131 /*
132  * call-seq:
133  * io.wait_writable -> true or false
134  * io.wait_writable(timeout) -> true or false
135  *
136  * Waits until IO is writable and returns +true+ or
137  * +false+ when times out.
138  */
139 static VALUE
140 io_wait_writable(int argc, VALUE *argv, VALUE io)
141 {
142  rb_io_t *fptr = NULL;
143 
144  RB_IO_POINTER(io, fptr);
145  rb_io_check_writable(fptr);
146 
147  rb_check_arity(argc, 0, 1);
148  VALUE timeout = (argc == 1 ? argv[0] : Qnil);
149 
150  return io_wait_event(io, RUBY_IO_WRITABLE, timeout);
151 }
152 
153 /*
154  * call-seq:
155  * io.wait_priority -> true or false
156  * io.wait_priority(timeout) -> true or false
157  *
158  * Waits until IO is priority and returns +true+ or
159  * +false+ when times out.
160  */
161 static VALUE
162 io_wait_priority(int argc, VALUE *argv, VALUE io)
163 {
164  rb_io_t *fptr = NULL;
165 
166  RB_IO_POINTER(io, fptr);
167  rb_io_check_readable(fptr);
168 
169  if (rb_io_read_pending(fptr)) return Qtrue;
170 
171  rb_check_arity(argc, 0, 1);
172  VALUE timeout = argc == 1 ? argv[0] : Qnil;
173 
174  return io_wait_event(io, RUBY_IO_PRIORITY, timeout);
175 }
176 
177 static int
178 wait_mode_sym(VALUE mode)
179 {
180  if (mode == ID2SYM(rb_intern("r"))) {
181  return RB_WAITFD_IN;
182  }
183  if (mode == ID2SYM(rb_intern("read"))) {
184  return RB_WAITFD_IN;
185  }
186  if (mode == ID2SYM(rb_intern("readable"))) {
187  return RB_WAITFD_IN;
188  }
189  if (mode == ID2SYM(rb_intern("w"))) {
190  return RB_WAITFD_OUT;
191  }
192  if (mode == ID2SYM(rb_intern("write"))) {
193  return RB_WAITFD_OUT;
194  }
195  if (mode == ID2SYM(rb_intern("writable"))) {
196  return RB_WAITFD_OUT;
197  }
198  if (mode == ID2SYM(rb_intern("rw"))) {
200  }
201  if (mode == ID2SYM(rb_intern("read_write"))) {
203  }
204  if (mode == ID2SYM(rb_intern("readable_writable"))) {
206  }
207  rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
208  return 0;
209 }
210 
211 /*
212  * call-seq:
213  * io.wait(events, timeout) -> event mask or false.
214  * io.wait(timeout = nil, mode = :read) -> event mask or false.
215  *
216  * Waits until the IO becomes ready for the specified events and returns the
217  * subset of events that become ready, or +false+ when times out.
218  *
219  * The events can be a bit mask of +IO::READABLE+, +IO::WRITABLE+ or
220  * +IO::PRIORITY+.
221  *
222  * Returns +true+ immediately when buffered data is available.
223  *
224  * Optional parameter +mode+ is one of +:read+, +:write+, or
225  * +:read_write+.
226  */
227 
228 static VALUE
229 io_wait(int argc, VALUE *argv, VALUE io)
230 {
231  VALUE timeout = Qundef;
232  rb_io_event_t events = 0;
233 
234  if (argc != 2 || (RB_SYMBOL_P(argv[0]) || RB_SYMBOL_P(argv[1]))) {
235  for (int i = 0; i < argc; i += 1) {
236  if (RB_SYMBOL_P(argv[i])) {
237  events |= wait_mode_sym(argv[i]);
238  }
239  else if (timeout == Qundef) {
240  rb_time_interval(timeout = argv[i]);
241  }
242  else {
243  rb_raise(rb_eArgError, "timeout given more than once");
244  }
245  }
246  if (timeout == Qundef) timeout = Qnil;
247  }
248  else /* argc == 2 */ {
249  events = RB_NUM2UINT(argv[0]);
250  timeout = argv[1];
251  }
252 
253  if (events == 0) {
254  events = RUBY_IO_READABLE;
255  }
256 
257  if (events & RUBY_IO_READABLE) {
258  rb_io_t *fptr = NULL;
259  RB_IO_POINTER(io, fptr);
260 
261  if (rb_io_read_pending(fptr)) {
262  return Qtrue;
263  }
264  }
265 
266  return io_wait_event(io, events, timeout);
267 }
268 
269 /*
270  * IO wait methods
271  */
272 
273 void
275 {
276 #ifdef HAVE_RB_EXT_RACTOR_SAFE
277  RB_EXT_RACTOR_SAFE(true);
278 #endif
279 
280  rb_define_method(rb_cIO, "nread", io_nread, 0);
281  rb_define_method(rb_cIO, "ready?", io_ready_p, 0);
282 
283  rb_define_method(rb_cIO, "wait", io_wait, -1);
284 
285  rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
286  rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
287  rb_define_method(rb_cIO, "wait_priority", io_wait_priority, -1);
288 }
Qundef
#define Qundef
Definition: special_consts.h:53
RB_IO_POINTER
#define RB_IO_POINTER(obj, fp)
Definition: io.h:124
rb_time_interval
struct timeval rb_time_interval(VALUE num)
Definition: time.c:2622
RUBY_IO_READABLE
@ RUBY_IO_READABLE
Definition: io.h:45
RB_EXT_RACTOR_SAFE
#define RB_EXT_RACTOR_SAFE(f)
Definition: load.h:39
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:784
rb_io_event_t
rb_io_event_t
Definition: io.h:44
PRIsVALUE
#define PRIsVALUE
Definition: inttypes.h:77
rb_io_check_readable
void rb_io_check_readable(rb_io_t *)
Definition: io.c:959
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1094
INT2FIX
#define INT2FIX
Definition: long.h:48
GetOpenFile
#define GetOpenFile
Definition: io.h:125
argv
char ** argv
Definition: ruby.c:243
rb_io_t::fd
int fd
Definition: io.h:65
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:3022
rb_io_read_pending
int rb_io_read_pending(rb_io_t *)
Definition: io.c:995
RUBY_IO_PRIORITY
@ RUBY_IO_PRIORITY
Definition: io.h:47
rb_cIO
VALUE rb_cIO
Definition: io.c:183
mask
enum @12::@14::@15 mask
FIONREAD_POSSIBLE_P
#define FIONREAD_POSSIBLE_P(fd)
Definition: wait.c:40
ioctl_arg2num
#define ioctl_arg2num(i)
Definition: wait.c:34
Qfalse
#define Qfalse
Definition: special_consts.h:50
rb_check_arity
#define rb_check_arity
Definition: error.h:34
len
uint8_t len
Definition: escape.c:17
ruby.h
Qnil
#define Qnil
Definition: special_consts.h:51
RUBY_IO_WRITABLE
@ RUBY_IO_WRITABLE
Definition: io.h:46
NULL
#define NULL
Definition: regenc.h:69
Qtrue
#define Qtrue
Definition: special_consts.h:52
ioctl
int ioctl(int, int,...)
Definition: win32.c:2888
VALUE
unsigned long VALUE
Definition: value.h:38
rb_io_check_writable
void rb_io_check_writable(rb_io_t *)
Definition: io.c:983
ioctl_arg
#define ioctl_arg
Definition: wait.c:33
RB_INT2NUM
#define RB_INT2NUM
Definition: int.h:37
argc
int argc
Definition: ruby.c:242
RB_WAITFD_IN
#define RB_WAITFD_IN
Definition: io.h:39
RB_WAITFD_OUT
#define RB_WAITFD_OUT
Definition: io.h:41
ID2SYM
#define ID2SYM
Definition: symbol.h:44
io.h
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:655
rb_io_t
Definition: io.h:61
RB_NUM2INT
#define RB_NUM2INT
Definition: int.h:38
rb_io_wait
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Definition: io.c:1272
Init_wait
void Init_wait(void)
Definition: wait.c:274