Ruby 2.7.7p221 (2022-11-24 revision 168ec2b1e5ad0e4688e963d9de019557c78feed9)
wait.c
Go to the documentation of this file.
1/**********************************************************************
2
3 io/wait.c -
4
5 $Author$
6 created at: Tue Aug 28 09:08:06 JST 2001
7
8 All the files in this distribution are covered under the Ruby's
9 license (see the file COPYING).
10
11**********************************************************************/
12
13#include "ruby.h"
14#include "ruby/io.h"
15
16#include <sys/types.h>
17#if defined(HAVE_UNISTD_H) && (defined(__sun))
18#include <unistd.h>
19#endif
20#if defined(HAVE_SYS_IOCTL_H)
21#include <sys/ioctl.h>
22#endif
23#if defined(FIONREAD_HEADER)
24#include FIONREAD_HEADER
25#endif
26
27#ifdef HAVE_RB_W32_IOCTLSOCKET
28#define ioctl ioctlsocket
29#define ioctl_arg u_long
30#define ioctl_arg2num(i) ULONG2NUM(i)
31#else
32#define ioctl_arg int
33#define ioctl_arg2num(i) INT2NUM(i)
34#endif
35
36#ifdef HAVE_RB_W32_IS_SOCKET
37#define FIONREAD_POSSIBLE_P(fd) rb_w32_is_socket(fd)
38#else
39#define FIONREAD_POSSIBLE_P(fd) ((void)(fd),Qtrue)
40#endif
41
42static VALUE io_ready_p _((VALUE io));
43static VALUE io_wait_readable _((int argc, VALUE *argv, VALUE io));
44static VALUE io_wait_writable _((int argc, VALUE *argv, VALUE io));
45void Init_wait _((void));
46
47static struct timeval *
48get_timeout(int argc, VALUE *argv, struct timeval *timerec)
49{
50 VALUE timeout = Qnil;
51 rb_check_arity(argc, 0, 1);
52 if (!argc || NIL_P(timeout = argv[0])) {
53 return NULL;
54 }
55 else {
56 *timerec = rb_time_interval(timeout);
57 return timerec;
58 }
59}
60
61static int
62wait_for_single_fd(rb_io_t *fptr, int events, struct timeval *tv)
63{
64 int i = rb_wait_for_single_fd(fptr->fd, events, tv);
65 if (i < 0)
66 rb_sys_fail(0);
68 return (i & events);
69}
70
71/*
72 * call-seq:
73 * io.nread -> int
74 *
75 * Returns number of bytes that can be read without blocking.
76 * Returns zero if no information available.
77 */
78
79static VALUE
80io_nread(VALUE io)
81{
82 rb_io_t *fptr;
83 int len;
85
86 GetOpenFile(io, fptr);
88 len = rb_io_read_pending(fptr);
89 if (len > 0) return INT2FIX(len);
90 if (!FIONREAD_POSSIBLE_P(fptr->fd)) return INT2FIX(0);
91 if (ioctl(fptr->fd, FIONREAD, &n)) return INT2FIX(0);
92 if (n > 0) return ioctl_arg2num(n);
93 return INT2FIX(0);
94}
95
96/*
97 * call-seq:
98 * io.ready? -> true or false
99 *
100 * Returns true if input available without blocking, or false.
101 */
102
103static VALUE
104io_ready_p(VALUE io)
105{
106 rb_io_t *fptr;
107 struct timeval tv = {0, 0};
108
109 GetOpenFile(io, fptr);
111 if (rb_io_read_pending(fptr)) return Qtrue;
112 if (wait_for_single_fd(fptr, RB_WAITFD_IN, &tv))
113 return Qtrue;
114 return Qfalse;
115}
116
117/*
118 * call-seq:
119 * io.wait_readable -> IO, true or nil
120 * io.wait_readable(timeout) -> IO, true or nil
121 *
122 * Waits until IO is readable without blocking and returns +self+, or
123 * +nil+ when times out.
124 * Returns +true+ immediately when buffered data is available.
125 */
126
127static VALUE
128io_wait_readable(int argc, VALUE *argv, VALUE io)
129{
130 rb_io_t *fptr;
131 struct timeval timerec;
132 struct timeval *tv;
133
134 GetOpenFile(io, fptr);
136 tv = get_timeout(argc, argv, &timerec);
137 if (rb_io_read_pending(fptr)) return Qtrue;
138 if (wait_for_single_fd(fptr, RB_WAITFD_IN, tv)) {
139 return io;
140 }
141 return Qnil;
142}
143
144/*
145 * call-seq:
146 * io.wait_writable -> IO
147 * io.wait_writable(timeout) -> IO or nil
148 *
149 * Waits until IO is writable without blocking and returns +self+ or
150 * +nil+ when times out.
151 */
152static VALUE
153io_wait_writable(int argc, VALUE *argv, VALUE io)
154{
155 rb_io_t *fptr;
156 struct timeval timerec;
157 struct timeval *tv;
158
159 GetOpenFile(io, fptr);
161 tv = get_timeout(argc, argv, &timerec);
162 if (wait_for_single_fd(fptr, RB_WAITFD_OUT, tv)) {
163 return io;
164 }
165 return Qnil;
166}
167
168static int
169wait_mode_sym(VALUE mode)
170{
171 if (mode == ID2SYM(rb_intern("r"))) {
172 return RB_WAITFD_IN;
173 }
174 if (mode == ID2SYM(rb_intern("read"))) {
175 return RB_WAITFD_IN;
176 }
177 if (mode == ID2SYM(rb_intern("readable"))) {
178 return RB_WAITFD_IN;
179 }
180 if (mode == ID2SYM(rb_intern("w"))) {
181 return RB_WAITFD_OUT;
182 }
183 if (mode == ID2SYM(rb_intern("write"))) {
184 return RB_WAITFD_OUT;
185 }
186 if (mode == ID2SYM(rb_intern("writable"))) {
187 return RB_WAITFD_OUT;
188 }
189 if (mode == ID2SYM(rb_intern("rw"))) {
191 }
192 if (mode == ID2SYM(rb_intern("read_write"))) {
194 }
195 if (mode == ID2SYM(rb_intern("readable_writable"))) {
197 }
198 rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
199 return 0;
200}
201
202/*
203 * call-seq:
204 * io.wait(timeout = nil, mode = :read) -> IO, true or nil
205 *
206 * Waits until IO is readable or writable without blocking and returns
207 * +self+, or +nil+ when times out.
208 * Returns +true+ immediately when buffered data is available.
209 * Optional parameter +mode+ is one of +:read+, +:write+, or
210 * +:read_write+.
211 */
212
213static VALUE
214io_wait_readwrite(int argc, VALUE *argv, VALUE io)
215{
216 rb_io_t *fptr;
217 struct timeval timerec;
218 struct timeval *tv = NULL;
219 int event = 0;
220 int i;
221
222 GetOpenFile(io, fptr);
223 for (i = 0; i < argc; ++i) {
224 if (SYMBOL_P(argv[i])) {
225 event |= wait_mode_sym(argv[i]);
226 }
227 else {
228 *(tv = &timerec) = rb_time_interval(argv[i]);
229 }
230 }
231 /* rb_time_interval() and might_mode() might convert the argument */
232 rb_io_check_closed(fptr);
233 if (!event) event = RB_WAITFD_IN;
234 if ((event & RB_WAITFD_IN) && rb_io_read_pending(fptr))
235 return Qtrue;
236 if (wait_for_single_fd(fptr, event, tv))
237 return io;
238 return Qnil;
239}
240
241/*
242 * IO wait methods
243 */
244
245void
247{
248 rb_define_method(rb_cIO, "nread", io_nread, 0);
249 rb_define_method(rb_cIO, "ready?", io_ready_p, 0);
250 rb_define_method(rb_cIO, "wait", io_wait_readwrite, -1);
251 rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
252 rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
253}
VALUE rb_cIO
Definition: ruby.h:2032
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2671
VALUE rb_eArgError
Definition: error.c:925
void rb_sys_fail(const char *mesg)
Definition: error.c:2795
#define RB_WAITFD_OUT
Definition: io.h:53
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Definition: thread.c:4275
void rb_io_check_closed(rb_io_t *)
Definition: io.c:718
void rb_io_check_writable(rb_io_t *)
Definition: io.c:923
void rb_io_check_readable(rb_io_t *)
Definition: io.c:899
int rb_io_read_pending(rb_io_t *)
Definition: io.c:935
#define RB_WAITFD_IN
Definition: io.h:51
#define GetOpenFile(obj, fp)
Definition: io.h:127
#define NULL
#define NIL_P(v)
#define ID2SYM(x)
const char size_t n
unsigned long VALUE
uint32_t i
__inline__ const void *__restrict__ size_t len
#define PRIsVALUE
#define rb_intern(str)
struct timeval rb_time_interval(VALUE num)
Definition: time.c:2683
#define Qtrue
#define Qnil
#define Qfalse
#define INT2FIX(i)
const VALUE * argv
#define SYMBOL_P(x)
#define rb_check_arity
void rb_define_method(VALUE, const char *, VALUE(*)(), int)
Definition: io.h:66
int fd
Definition: io.h:68
void Init_wait(void)
Definition: wait.c:246
#define ioctl_arg
Definition: wait.c:32
#define ioctl_arg2num(i)
Definition: wait.c:33
#define FIONREAD_POSSIBLE_P(fd)
Definition: wait.c:39
void Init_wait _((void))
int ioctl(int, int,...)
Definition: win32.c:2841