5 #include <sys/socket.h>
8 # error MSG_DONTWAIT not defined!
18 #ifndef HAVE_RB_THREAD_IO_BLOCKING_REGION
19 # define rb_thread_io_blocking_region(fn,data,fd) \
20 rb_thread_blocking_region((fn),(data), RUBY_UBF_IO, 0)
22 static long my_tbr(rb_blocking_function_t
*fn
, void *ptr
)
24 struct io_args
*args
= (struct io_args
*)ptr
;
26 return (long)rb_thread_io_blocking_region(fn
, ptr
, args
->fd
);
29 static int set_blocking(int fd
)
31 int flags
= fcntl(fd
, F_GETFL
);
36 if ((flags
& O_NONBLOCK
))
37 flags
= fcntl(fd
, F_SETFL
, flags
& ~O_NONBLOCK
);
42 static int can_retry(int fd
)
47 return set_blocking(fd
) == -1 ? 0 : 1;
51 static void prepare_read_buf(struct io_args
*a
, VALUE length
)
53 a
->len
= NUM2LONG(length
);
55 a
->buf
= rb_str_new(NULL
, a
->len
);
58 rb_str_resize(a
->buf
, a
->len
);
60 a
->ptr
= RSTRING_PTR(a
->buf
);
63 static void prepare_read_io(struct io_args
*a
, VALUE io
)
67 GetOpenFile(io
, fptr
);
68 rb_io_check_readable(fptr
);
72 static void read_args(struct io_args
*a
, int argc
, VALUE
*argv
, VALUE io
)
76 prepare_read_io(a
, io
);
77 rb_scan_args(argc
, argv
, "11", &length
, &a
->buf
);
78 prepare_read_buf(a
, length
);
81 static VALUE
read_retval(struct io_args
*a
, long n
, const char *msg
)
84 rb_str_set_len(a
->buf
, 0);
87 rb_str_set_len(a
->buf
, n
);
96 * ios.read_nonblock(maxlen) -> string
97 * ios.read_nonblock(maxlen, outbuf) -> outbuf
99 * This behaves like IO#read_nonblock in Ruby core.
100 * Unlike IO#read_nonblock, this does not have the side effect of
101 * setting the O_NONBLOCK flag on the file descriptor. It should
102 * otherwise behave exactly like IO#read_nonblock when dealing with
105 * Unlike BasicSocket#recv_nonblock, this allows +outbuf+ to be
106 * specified and reused to reduce impact on GC. This method never
109 static VALUE
read_nonblock(int argc
, VALUE
*argv
, VALUE io
)
114 read_args(&a
, argc
, argv
, io
);
118 n
= (long)recv(a
.fd
, a
.ptr
, a
.len
, MSG_DONTWAIT
);
120 return read_retval(&a
, n
, "recv");
123 /* used to implement readpartial if the initial recv() fails with EAGAIN */
124 static VALUE
recv_once(void *arg
)
126 struct io_args
*a
= arg
;
127 long n
= (long)recv(a
->fd
, a
->ptr
, a
->len
, 0);
134 * ios.readpartial(maxlen) -> string
135 * ios.readpartial(maxlen, outbuf) -> outbuf
137 * This behaves like IO#readpartial from Ruby core.
138 * If line buffering (IO#gets) is never used for +ios+, then
139 * this can be safely used with file descriptors higher than 1023.
140 * If data is immediately not available, this will _unset_ the
141 * O_NONBLOCK flag, release the GVL, and block on the socket.
143 static VALUE
readpartial(int argc
, VALUE
*argv
, VALUE io
)
148 read_args(&a
, argc
, argv
, io
);
152 /* try optimistically first */
153 n
= (long)recv(a
.fd
, a
.ptr
, a
.len
, MSG_DONTWAIT
);
155 while (n
< 0 && can_retry(a
.fd
)) {
156 rb_str_locktmp(a
.buf
);
157 /* ugh, nothing available: block on the socket */
158 n
= my_tbr(recv_once
, &a
);
159 rb_str_unlocktmp(a
.buf
);
162 return read_retval(&a
, n
, "recv");
165 /* used to implement BasicSocket#read */
166 static VALUE
recv_all(void *arg
)
168 struct io_args
*a
= arg
;
169 long n
= (long)recv(a
->fd
, a
->ptr
, a
->len
, MSG_WAITALL
);
178 /* used to implement BasicSocket#read() */
179 static VALUE
read_all(struct io_args
*a
)
184 prepare_read_buf(a
, INT2FIX(rd_size
));
186 rb_str_locktmp(a
->buf
);
189 n
= my_tbr(recv_all
, a
);
190 } while ((n
< 0 && can_retry(a
->fd
)) || (n
> 0 && a
->len
> 0));
192 cur_len
= RSTRING_LEN(a
->buf
);
194 if (n
== 0 || a
->len
> 0) {
195 rb_str_unlocktmp(a
->buf
);
196 rb_str_set_len(a
->buf
, cur_len
- a
->len
);
200 /* everything was fully read, allocate more */
201 rb_str_unlocktmp(a
->buf
);
202 rb_str_resize(a
->buf
, cur_len
+ rd_size
);
203 rb_str_locktmp(a
->buf
);
204 a
->ptr
= RSTRING_PTR(a
->buf
) + cur_len
;
211 * ios.read([length [, buffer]]) -> string, buffer, or nil
213 * This behaves like IO#readfrom Ruby core.
214 * If line buffering (IO#gets) is never used for +ios+, then
215 * this can be safely used with file descriptors higher than 1023.
216 * If data is not immediately available, this will _unset_ the
217 * O_NONBLOCK flag, release the GVL, and block on the socket.
218 * This will use the MSG_WAITALL flag for the recv(2) syscall to
219 * reduce context switching.
221 static VALUE
xread(int argc
, VALUE
*argv
, VALUE io
)
227 prepare_read_io(&a
, io
);
228 rb_scan_args(argc
, argv
, "02", &length
, &a
.buf
);
233 prepare_read_buf(&a
, length
);
237 /* try to read as much as possible without blocking */
239 n
= (long)recv(a
.fd
, a
.ptr
, a
.len
, MSG_DONTWAIT
);
240 while (n
> 0 && (a
.ptr
+= n
) && (a
.len
-= n
) > 0);
242 /* release the GVL to block on whatever's left */
243 rb_str_locktmp(a
.buf
);
244 while (a
.len
> 0 && n
!= 0) {
245 n
= my_tbr(recv_all
, &a
);
247 if (!can_retry(a
.fd
))
251 rb_str_unlocktmp(a
.buf
);
252 n
= RSTRING_LEN(a
.buf
) - a
.len
;
253 rb_str_set_len(a
.buf
, n
);
263 static void prepare_write_args(struct io_args
*a
, VALUE io
, VALUE str
)
267 a
->buf
= (TYPE(str
) == T_STRING
) ? str
: rb_obj_as_string(str
);
268 a
->ptr
= RSTRING_PTR(a
->buf
);
269 a
->len
= RSTRING_LEN(a
->buf
);
270 GetOpenFile(io
, fptr
);
271 rb_io_check_writable(fptr
);
277 * ios.write_nonblock(string) -> integer
279 * This behaves like IO#write_nonblock in Ruby core.
280 * Unlike IO#write_nonblock, this does not have the side effect of
281 * setting the O_NONBLOCK flag on the file descriptor. It should
282 * otherwise behave exactly like IO#write_nonblock when dealing with
285 * This method never releases the GVL.
287 static VALUE
write_nonblock(VALUE io
, VALUE str
)
292 prepare_write_args(&a
, io
, str
);
293 n
= (long)send(a
.fd
, a
.ptr
, a
.len
, MSG_DONTWAIT
);
300 /* used to implement BasicSocket#write */
301 static VALUE
send_once(void *args
)
303 struct io_args
*a
= args
;
304 long n
= (long)send(a
->fd
, a
->ptr
, a
->len
, 0);
315 * ios.write(string) -> integer
317 * This behaves like IO#write in Ruby core.
319 * This can be safely used to block on file descriptors higher than 1023.
320 * If socket buffer space is not immediately available in the kernel,
321 * this will _unset_ the O_NONBLOCK flag, release the GVL, and block
322 * on the socket until data is written.
324 static VALUE
xwrite(VALUE io
, VALUE str
)
329 prepare_write_args(&a
, io
, str
);
331 /* optimistically try to send everything w/o releasing GVL */
332 n
= (long)send(a
.fd
, a
.ptr
, a
.len
, MSG_DONTWAIT
);
336 /* buffer may be expanded in the kernel, keep trying w/o blocking */
337 while (n
>= 0 && (a
.ptr
+= n
) && (a
.len
-= n
) > 0)
338 n
= (long)send(a
.fd
, a
.ptr
, a
.len
, MSG_DONTWAIT
);
340 /* all done, we managed to finish without releasing the GVL */
342 return LONG2FIX(RSTRING_LEN(a
.buf
));
344 if (n
< 0 && !can_retry(a
.fd
))
347 rb_str_locktmp(a
.buf
);
349 n
= my_tbr(send_once
, &a
);
351 if (!can_retry(a
.fd
))
355 rb_str_unlocktmp(a
.buf
);
356 n
= RSTRING_LEN(a
.buf
) - a
.len
;
357 rb_str_set_len(a
.buf
, n
);
366 * ios.sync = boolean -> boolean
368 * socket_dontwait makes BasicSocket#sync= a no-op.
369 * Ruby sockets already default to synchronized operation,
370 * and socket_dontwait prevents users from changing this default
371 * as it increases complexity.
373 static VALUE
set_sync(VALUE io
, VALUE boolean
)
378 void Init_socket_dontwait_ext(void)
380 VALUE mod
= rb_define_module("SocketDontwait");
382 rb_define_method(mod
, "sync=", set_sync
, 1);
383 rb_define_method(mod
, "read", xread
, -1);
384 rb_define_method(mod
, "read_nonblock", read_nonblock
, -1);
385 rb_define_method(mod
, "readpartial", readpartial
, -1);
386 rb_define_method(mod
, "write_nonblock", write_nonblock
, 1);
387 rb_define_method(mod
, "write", xwrite
, 1);