This behaves like IO#read from Ruby core. If data is not immediately available, this will unset the O_NONBLOCK flag, release the GVL, and block on the socket. This will use the MSG_WAITALL flag for the recv(2) syscall to reduce context switching.
static VALUE xread(int argc, VALUE *argv, VALUE io)
{
struct io_args a;
VALUE length;
long n;
prepare_read_io(&a, io);
rb_scan_args(argc, argv, "02", &length, &a.buf);
if (NIL_P(length))
return read_all(&a);
prepare_read_buf(&a, length);
if (a.len == 0)
return a.buf;
/* try to read as much as possible without blocking */
errno = 0;
do
n = (long)recv(a.fd, a.ptr, a.len, MSG_DONTWAIT);
while (n > 0 && (a.ptr += n) && (a.len -= n) > 0);
/* release the GVL to block on whatever's left */
rb_str_locktmp(a.buf);
while (a.len > 0 && n != 0) {
n = my_tbr(recv_all, &a);
if (n < 0) {
if (!can_retry(a.fd))
break;
}
}
rb_str_unlocktmp(a.buf);
n = RSTRING_LEN(a.buf) - a.len;
rb_str_set_len(a.buf, n);
if (n == 0) {
if (errno)
rb_sys_fail("recv");
return Qnil;
}
return a.buf;
}
This behaves like IO#read_nonblock in Ruby core. Unlike IO#read_nonblock, this does not have the side effect of setting the O_NONBLOCK flag on the file descriptor. It should otherwise behave exactly like IO#read_nonblock when dealing with sockets.
Unlike BasicSocket#recv_nonblock, this allows outbuf to be specified and reused to reduce impact on GC. This method never releases the GVL.
static VALUE read_nonblock(int argc, VALUE *argv, VALUE io)
{
struct io_args a;
long n;
read_args(&a, argc, argv, io);
if (a.len == 0)
return a.buf;
n = (long)recv(a.fd, a.ptr, a.len, MSG_DONTWAIT);
return read_retval(&a, n, "recv");
}
This behaves like IO#readpartial from Ruby core. If data is immediately not available, this will unset the O_NONBLOCK flag, release the GVL, and block on the socket.
static VALUE readpartial(int argc, VALUE *argv, VALUE io)
{
struct io_args a;
long n;
read_args(&a, argc, argv, io);
if (a.len == 0)
return a.buf;
/* try optimistically first */
n = (long)recv(a.fd, a.ptr, a.len, MSG_DONTWAIT);
while (n < 0 && can_retry(a.fd)) {
rb_str_locktmp(a.buf);
/* ugh, nothing available: block on the socket */
n = my_tbr(recv_once, &a);
rb_str_unlocktmp(a.buf);
}
return read_retval(&a, n, "recv");
}
socket_dontwait makes BasicSocket#sync= a no-op. Ruby sockets already default to synchronized operation, and socket_dontwait prevents users from changing this default as it increases complexity.
static VALUE set_sync(VALUE io, VALUE boolean)
{
return boolean;
}
This behaves like IO#write in Ruby core.
If socket buffer space is not immediately available in the kernel, this will unset the O_NONBLOCK flag, release the GVL, and block on the socket until data is written.
static VALUE xwrite(VALUE io, VALUE str)
{
struct io_args a;
long n;
prepare_write_args(&a, io, str);
/* optimistically try to send everything w/o releasing GVL */
n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
if (n == a.len)
return LONG2FIX(n);
/* buffer may be expanded in the kernel, keep trying w/o blocking */
while (n >= 0 && (a.ptr += n) && (a.len -= n) > 0)
n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
/* all done, we managed to finish without releasing the GVL */
if (a.len == 0)
return LONG2FIX(RSTRING_LEN(a.buf));
if (n < 0 && !can_retry(a.fd))
rb_sys_fail("send");
rb_str_locktmp(a.buf);
while (a.len > 0) {
n = my_tbr(send_once, &a);
if (n < 0) {
if (!can_retry(a.fd))
break;
}
}
rb_str_unlocktmp(a.buf);
n = RSTRING_LEN(a.buf) - a.len;
rb_str_set_len(a.buf, n);
if (a.len > 0)
rb_sys_fail("send");
return LONG2FIX(n);
}
This behaves like IO#write_nonblock in Ruby core. Unlike IO#write_nonblock, this does not have the side effect of setting the O_NONBLOCK flag on the file descriptor. It should otherwise behave exactly like IO#write_nonblock when dealing with sockets.
This method never releases the GVL.
static VALUE write_nonblock(VALUE io, VALUE str)
{
struct io_args a;
long n;
prepare_write_args(&a, io, str);
n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
if (n == -1)
rb_sys_fail("send");
return LONG2FIX(n);
}
Originally generated with the Darkfish Rdoc Generator 2, modified by wrongdoc.