Ruby: ext/io/wait/wait.c Source File

Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)

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
51static VALUE
52io_nread(VALUE io)
53{
54 rb_io_t *fptr = NULL;
55 ioctl_arg n;
56
57 GetOpenFile(io, fptr);
58 rb_io_check_readable(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
67static VALUE
68io_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
93static VALUE
94io_ready_p(VALUE io)
95{
96 rb_io_t *fptr;
97
98 GetOpenFile(io, fptr);
99 rb_io_check_readable(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
115static VALUE
116io_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 */
139static VALUE
140io_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 */
161static VALUE
162io_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
177static int
178wait_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"))) {
199 return RB_WAITFD_IN|RB_WAITFD_OUT;
200 }
201 if (mode == ID2SYM(rb_intern("read_write"))) {
202 return RB_WAITFD_IN|RB_WAITFD_OUT;
203 }
204 if (mode == ID2SYM(rb_intern("readable_writable"))) {
205 return RB_WAITFD_IN|RB_WAITFD_OUT;
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
228static VALUE
229io_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
273void
274Init_wait(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}
rb_define_method
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
mask
enum @11::@13::@14 mask
len
uint8_t len
Definition: escape.c:17
PRIsVALUE
#define PRIsVALUE
Definition: function.c:10
rb_cIO
VALUE rb_cIO
Definition: io.c:183
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
rb_eArgError
VALUE rb_eArgError
Definition: error.c:1058
rb_check_arity
#define rb_check_arity
Definition: error.h:34
RB_EXT_RACTOR_SAFE
#define RB_EXT_RACTOR_SAFE(f)
Definition: load.h:39
rb_time_interval
struct timeval rb_time_interval(VALUE num)
Definition: time.c:2684
ID2SYM
#define ID2SYM
Definition: symbol.h:44
rb_intern
ID rb_intern(const char *)
Definition: symbol.c:785
io.h
GetOpenFile
#define GetOpenFile
Definition: io.h:125
RB_WAITFD_OUT
#define RB_WAITFD_OUT
Definition: io.h:41
rb_io_check_writable
void rb_io_check_writable(rb_io_t *)
Definition: io.c:980
rb_io_check_readable
void rb_io_check_readable(rb_io_t *)
Definition: io.c:956
rb_io_read_pending
int rb_io_read_pending(rb_io_t *)
Definition: io.c:992
RB_IO_POINTER
#define RB_IO_POINTER(obj, fp)
Definition: io.h:124
RB_WAITFD_IN
#define RB_WAITFD_IN
Definition: io.h:39
rb_io_event_t
rb_io_event_t
Definition: io.h:44
RUBY_IO_READABLE
@ RUBY_IO_READABLE
Definition: io.h:45
RUBY_IO_PRIORITY
@ RUBY_IO_PRIORITY
Definition: io.h:47
RUBY_IO_WRITABLE
@ RUBY_IO_WRITABLE
Definition: io.h:46
rb_io_wait
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Definition: io.c:1265
RB_NUM2INT
#define RB_NUM2INT
Definition: int.h:38
RB_INT2NUM
#define RB_INT2NUM
Definition: int.h:37
mode
const char int mode
Definition: ioapi.h:137
INT2FIX
#define INT2FIX
Definition: long.h:48
NULL
#define NULL
Definition: regenc.h:69
ruby.h
argc
int argc
Definition: ruby.c:240
argv
char ** argv
Definition: ruby.c:241
Qundef
#define Qundef
Definition: special_consts.h:53
Qtrue
#define Qtrue
Definition: special_consts.h:52
Qnil
#define Qnil
Definition: special_consts.h:51
Qfalse
#define Qfalse
Definition: special_consts.h:50
rb_io_t
Definition: io.h:61
rb_io_t::fd
int fd
Definition: io.h:65
VALUE
unsigned long VALUE
Definition: value.h:38
Init_wait
void Init_wait(void)
Definition: wait.c:274
ioctl_arg
#define ioctl_arg
Definition: wait.c:33
ioctl_arg2num
#define ioctl_arg2num(i)
Definition: wait.c:34
FIONREAD_POSSIBLE_P
#define FIONREAD_POSSIBLE_P(fd)
Definition: wait.c:40
ioctl
int ioctl(int, int,...)
Definition: win32.c:2867