Ruby  2.5.0dev(2017-10-22revision60238)
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 
42 static VALUE io_ready_p _((VALUE io));
43 static VALUE io_wait_readable _((int argc, VALUE *argv, VALUE io));
44 static VALUE io_wait_writable _((int argc, VALUE *argv, VALUE io));
45 void Init_wait _((void));
46 
47 static struct timeval *
48 get_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 
61 static int
62 wait_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);
67  rb_io_check_closed(fptr);
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 
79 static VALUE
80 io_nread(VALUE io)
81 {
82  rb_io_t *fptr;
83  int len;
84  ioctl_arg n;
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, false or nil
99  *
100  * Returns true if input available without blocking, or false.
101  * Returns nil if no information available.
102  */
103 
104 static VALUE
105 io_ready_p(VALUE io)
106 {
107  rb_io_t *fptr;
108  struct timeval tv = {0, 0};
109 
110  GetOpenFile(io, fptr);
111  rb_io_check_readable(fptr);
112  if (rb_io_read_pending(fptr)) return Qtrue;
113  if (wait_for_single_fd(fptr, RB_WAITFD_IN, &tv))
114  return Qtrue;
115  return Qfalse;
116 }
117 
118 /*
119  * call-seq:
120  * io.wait_readable -> IO, true or nil
121  * io.wait_readable(timeout) -> IO, true or nil
122  *
123  * Waits until IO is readable without blocking and returns +self+, or
124  * +nil+ when times out.
125  * Returns +true+ immediately when buffered data is available.
126  */
127 
128 static VALUE
129 io_wait_readable(int argc, VALUE *argv, VALUE io)
130 {
131  rb_io_t *fptr;
132  struct timeval timerec;
133  struct timeval *tv;
134 
135  GetOpenFile(io, fptr);
136  rb_io_check_readable(fptr);
137  tv = get_timeout(argc, argv, &timerec);
138  if (rb_io_read_pending(fptr)) return Qtrue;
139  if (wait_for_single_fd(fptr, RB_WAITFD_IN, tv)) {
140  return io;
141  }
142  return Qnil;
143 }
144 
145 /*
146  * call-seq:
147  * io.wait_writable -> IO
148  * io.wait_writable(timeout) -> IO or nil
149  *
150  * Waits until IO is writable without blocking and returns +self+ or
151  * +nil+ when times out.
152  */
153 static VALUE
154 io_wait_writable(int argc, VALUE *argv, VALUE io)
155 {
156  rb_io_t *fptr;
157  struct timeval timerec;
158  struct timeval *tv;
159 
160  GetOpenFile(io, fptr);
161  rb_io_check_writable(fptr);
162  tv = get_timeout(argc, argv, &timerec);
163  if (wait_for_single_fd(fptr, RB_WAITFD_OUT, tv)) {
164  return io;
165  }
166  return Qnil;
167 }
168 
169 static int
170 wait_mode_sym(VALUE mode)
171 {
172  if (mode == ID2SYM(rb_intern("r"))) {
173  return RB_WAITFD_IN;
174  }
175  if (mode == ID2SYM(rb_intern("read"))) {
176  return RB_WAITFD_IN;
177  }
178  if (mode == ID2SYM(rb_intern("readable"))) {
179  return RB_WAITFD_IN;
180  }
181  if (mode == ID2SYM(rb_intern("w"))) {
182  return RB_WAITFD_OUT;
183  }
184  if (mode == ID2SYM(rb_intern("write"))) {
185  return RB_WAITFD_OUT;
186  }
187  if (mode == ID2SYM(rb_intern("writable"))) {
188  return RB_WAITFD_OUT;
189  }
190  if (mode == ID2SYM(rb_intern("rw"))) {
192  }
193  if (mode == ID2SYM(rb_intern("read_write"))) {
195  }
196  if (mode == ID2SYM(rb_intern("readable_writable"))) {
198  }
199  rb_raise(rb_eArgError, "unsupported mode: %"PRIsVALUE, mode);
200  return 0;
201 }
202 
203 /*
204  * call-seq:
205  * io.wait(timeout = nil, mode = :read) -> IO, true or nil
206  *
207  * Waits until IO is readable or writable without blocking and returns
208  * +self+, or +nil+ when times out.
209  * Returns +true+ immediately when buffered data is available.
210  * Optional parameter +mode+ is one of +:read+, +:write+, or
211  * +:read_write+.
212  */
213 
214 static VALUE
215 io_wait_readwrite(int argc, VALUE *argv, VALUE io)
216 {
217  rb_io_t *fptr;
218  struct timeval timerec;
219  struct timeval *tv = NULL;
220  int event = 0;
221  int i;
222 
223  GetOpenFile(io, fptr);
224  for (i = 0; i < argc; ++i) {
225  if (SYMBOL_P(argv[i])) {
226  event |= wait_mode_sym(argv[i]);
227  }
228  else {
229  *(tv = &timerec) = rb_time_interval(argv[i]);
230  }
231  }
232  /* rb_time_interval() and might_mode() might convert the argument */
233  rb_io_check_closed(fptr);
234  if (!event) event = RB_WAITFD_IN;
235  if ((event & RB_WAITFD_IN) && rb_io_read_pending(fptr))
236  return Qtrue;
237  if (wait_for_single_fd(fptr, event, tv))
238  return io;
239  return Qnil;
240 }
241 
242 /*
243  * IO wait methods
244  */
245 
246 void
248 {
249  rb_define_method(rb_cIO, "nread", io_nread, 0);
250  rb_define_method(rb_cIO, "ready?", io_ready_p, 0);
251  rb_define_method(rb_cIO, "wait", io_wait_readwrite, -1);
252  rb_define_method(rb_cIO, "wait_readable", io_wait_readable, -1);
253  rb_define_method(rb_cIO, "wait_writable", io_wait_writable, -1);
254 }
#define ioctl_arg
Definition: wait.c:32
struct timeval rb_time_interval(VALUE num)
Definition: time.c:2299
int ioctl(int, int,...)
Definition: win32.c:2756
void rb_io_check_readable(rb_io_t *)
Definition: io.c:824
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2284
#define Qtrue
Definition: ruby.h:437
Definition: io.h:62
#define rb_check_arity
Definition: intern.h:298
#define FIONREAD_POSSIBLE_P(fd)
Definition: wait.c:39
#define GetOpenFile(obj, fp)
Definition: io.h:120
#define RB_WAITFD_OUT
Definition: io.h:49
VALUE rb_eArgError
Definition: error.c:802
#define NIL_P(v)
Definition: ruby.h:451
int fd
Definition: io.h:64
int argc
Definition: ruby.c:187
#define Qfalse
Definition: ruby.h:436
void rb_sys_fail(const char *mesg)
Definition: error.c:2403
RUBY_EXTERN VALUE rb_cIO
Definition: ruby.h:1913
#define PRIsVALUE
Definition: ruby.h:135
#define Qnil
Definition: ruby.h:438
unsigned long VALUE
Definition: ruby.h:85
#define ioctl_arg2num(i)
Definition: wait.c:33
int rb_wait_for_single_fd(int fd, int events, struct timeval *tv)
Definition: thread.c:3989
register unsigned int len
Definition: zonetab.h:51
void Init_wait(void)
Definition: wait.c:247
int rb_io_read_pending(rb_io_t *)
Definition: io.c:860
#define INT2FIX(i)
Definition: ruby.h:232
void rb_io_check_writable(rb_io_t *)
Definition: io.c:848
#define ID2SYM(x)
Definition: ruby.h:383
#define RB_WAITFD_IN
Definition: io.h:47
#define rb_intern(str)
#define SYMBOL_P(x)
Definition: ruby.h:382
#define NULL
Definition: _sdbm.c:102
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1515
void rb_io_check_closed(rb_io_t *)
Definition: io.c:641
void Init_wait _((void))
char ** argv
Definition: ruby.c:188