ext/kgio/read_write.c in kgio-2.1.1 vs ext/kgio/read_write.c in kgio-2.2.0
- old
+ new
@@ -1,8 +1,9 @@
#include "kgio.h"
static VALUE sym_wait_readable, sym_wait_writable;
static VALUE eErrno_EPIPE, eErrno_ECONNRESET;
+static ID id_set_backtrace;
/*
* we know MSG_DONTWAIT works properly on all stream sockets under Linux
* we can define this macro for other platforms as people care and
* notice.
@@ -12,17 +13,18 @@
#endif
NORETURN(static void raise_empty_bt(VALUE, const char *));
NORETURN(static void my_eof_error(void));
NORETURN(static void wr_sys_fail(const char *));
+NORETURN(static void rd_sys_fail(const char *));
static void raise_empty_bt(VALUE err, const char *msg)
{
VALUE exc = rb_exc_new2(err, msg);
VALUE bt = rb_ary_new();
- rb_funcall(exc, rb_intern("set_backtrace"), 1, bt);
+ rb_funcall(exc, id_set_backtrace, 1, bt);
rb_exc_raise(exc);
}
static void my_eof_error(void)
{
@@ -40,10 +42,19 @@
raise_empty_bt(eErrno_ECONNRESET, msg);
}
rb_sys_fail(msg);
}
+static void rd_sys_fail(const char *msg)
+{
+ if (errno == ECONNRESET) {
+ errno = 0;
+ raise_empty_bt(eErrno_ECONNRESET, msg);
+ }
+ rb_sys_fail(msg);
+}
+
static void prepare_read(struct io_args *a, int argc, VALUE *argv, VALUE io)
{
VALUE length;
a->io = io;
@@ -76,11 +87,11 @@
} else {
a->buf = sym_wait_readable;
return 0;
}
}
- rb_sys_fail(msg);
+ rd_sys_fail(msg);
}
rb_str_set_len(a->buf, n);
if (n == 0)
a->buf = Qnil;
return 0;
@@ -162,10 +173,11 @@
{
struct io_args a;
long n;
prepare_read(&a, argc, argv, io);
+ kgio_autopush_recv(io);
if (a.len > 0) {
retry:
n = (long)recv(a.fd, a.ptr, a.len, MSG_DONTWAIT);
if (read_check(&a, n, "recv", io_wait) != 0)
@@ -318,10 +330,12 @@
prepare_write(&a, io, str);
retry:
n = (long)send(a.fd, a.ptr, a.len, MSG_DONTWAIT);
if (write_check(&a, n, "send", io_wait) != 0)
goto retry;
+ if (TYPE(a.buf) != T_SYMBOL)
+ kgio_autopush_send(io);
return a.buf;
}
/*
* This method may be optimized on some systems (e.g. GNU/Linux) to use
@@ -345,19 +359,60 @@
#else /* ! USE_MSG_DONTWAIT */
# define kgio_send kgio_write
# define kgio_trysend kgio_trywrite
#endif /* ! USE_MSG_DONTWAIT */
+/*
+ * call-seq:
+ *
+ * Kgio.tryread(io, maxlen) -> buffer
+ * Kgio.tryread(io, maxlen, buffer) -> buffer
+ *
+ * Returns nil on EOF.
+ * Returns :wait_readable if EAGAIN is encountered.
+ *
+ * Maybe used in place of PipeMethods#kgio_tryread for non-Kgio objects
+ */
+static VALUE s_tryread(int argc, VALUE *argv, VALUE mod)
+{
+ if (argc <= 1)
+ rb_raise(rb_eArgError, "wrong number of arguments");
+ return my_read(0, argc - 1, &argv[1], argv[0]);
+}
+
+/*
+ * call-seq:
+ *
+ * Kgio.trywrite(io, str) -> nil or :wait_writable
+ *
+ * Returns nil if the write was completed in full.
+ *
+ * Returns a String containing the unwritten portion if EAGAIN
+ * was encountered, but some portion was successfully written.
+ *
+ * Returns :wait_writable if EAGAIN is encountered and nothing
+ * was written.
+ *
+ * Maybe used in place of PipeMethods#kgio_trywrite for non-Kgio objects
+ */
+static VALUE s_trywrite(VALUE mod, VALUE io, VALUE str)
+{
+ return my_write(io, str, 0);
+}
+
void init_kgio_read_write(void)
{
VALUE mPipeMethods, mSocketMethods;
VALUE mKgio = rb_define_module("Kgio");
VALUE mWaiters = rb_const_get(mKgio, rb_intern("DefaultWaiters"));
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
+ rb_define_singleton_method(mKgio, "tryread", s_tryread, -1);
+ rb_define_singleton_method(mKgio, "trywrite", s_trywrite, 2);
+
/*
* Document-module: Kgio::PipeMethods
*
* This module may be used used to create classes that respond to
* various Kgio methods for reading and writing. This is included
@@ -388,10 +443,10 @@
* Returns the client IPv4 address of the socket in dotted quad
* form as a string. This is always the value of the
* Kgio::LOCALHOST constant for UNIX domain sockets.
*/
rb_define_attr(mSocketMethods, "kgio_addr", 1, 1);
-
+ id_set_backtrace = rb_intern("set_backtrace");
eErrno_EPIPE = rb_const_get(rb_mErrno, rb_intern("EPIPE"));
eErrno_ECONNRESET = rb_const_get(rb_mErrno, rb_intern("ECONNRESET"));
rb_include_module(mPipeMethods, mWaiters);
rb_include_module(mSocketMethods, mWaiters);
}