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); }