summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-05-22 08:38:37 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-05-22 08:38:37 +0000
commit13ddc9fdd0317694352672ac8e5e8b8482cd4e6b (patch)
tree33bf888d0b7218f797f0a5d131788b793fc7dce5 /io.c
parentdb3bdf6eca24d6f78fbf29c8c22751aca5316c29 (diff)
* rubyio.h (rb_io_set_nonblock): declared.
* io.c (rb_io_set_nonblock): new function. (io_getpartial): nonblocking read support. (io_read_nonblock): new method: IO#read_nonblock. (io_write_nonblock): new method: IO#write_nonblock. * ext/socket/socket.c (sock_connect_nonblock): new method: Socket#connect_nonblock. (sock_accept_nonblock): new method: Socket#accept_nonblock. (sock_recvfrom_nonblock): new method: Socket#recvfrom_nonblock. [ruby-core:7917] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@10176 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'io.c')
-rw-r--r--io.c130
1 files changed, 123 insertions, 7 deletions
diff --git a/io.c b/io.c
index 89c5e2b638..228149df8f 100644
--- a/io.c
+++ b/io.c
@@ -1185,8 +1185,39 @@ read_all(fptr, siz, str)
return str;
}
+void rb_io_set_nonblock(OpenFile *fptr)
+{
+ int flags;
+#ifdef F_GETFL
+ flags = fcntl(fileno(fptr->f), F_GETFL);
+ if (flags == -1) {
+ rb_sys_fail(fptr->path);
+ }
+#else
+ flags = 0;
+#endif
+ flags |= O_NONBLOCK;
+ if (fcntl(fileno(fptr->f), F_SETFL, flags) == -1) {
+ rb_sys_fail(fptr->path);
+ }
+ if (fptr->f2) {
+#ifdef F_GETFL
+ flags = fcntl(fileno(fptr->f2), F_GETFL);
+ if (flags == -1) {
+ rb_sys_fail(fptr->path);
+ }
+#else
+ flags = 0;
+#endif
+ flags |= O_NONBLOCK;
+ if (fcntl(fileno(fptr->f2), F_SETFL, flags) == -1) {
+ rb_sys_fail(fptr->path);
+ }
+ }
+}
+
static VALUE
-io_getpartial(int argc, VALUE *argv, VALUE io)
+io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
{
OpenFile *fptr;
VALUE length, str;
@@ -1214,7 +1245,9 @@ io_getpartial(int argc, VALUE *argv, VALUE io)
if (len == 0)
return str;
- READ_CHECK(fptr->f);
+ if (!nonblock) {
+ READ_CHECK(fptr->f);
+ }
if (RSTRING(str)->len != len) {
modified:
rb_raise(rb_eRuntimeError, "buffer string modified");
@@ -1223,11 +1256,17 @@ io_getpartial(int argc, VALUE *argv, VALUE io)
if (n <= 0) {
again:
if (RSTRING(str)->len != len) goto modified;
- TRAP_BEG;
- n = read(fileno(fptr->f), RSTRING(str)->ptr, len);
- TRAP_END;
+ if (nonblock) {
+ rb_io_set_nonblock(fptr);
+ n = read(fileno(fptr->f), RSTRING(str)->ptr, len);
+ }
+ else {
+ TRAP_BEG;
+ n = read(fileno(fptr->f), RSTRING(str)->ptr, len);
+ TRAP_END;
+ }
if (n < 0) {
- if (rb_io_wait_readable(fileno(fptr->f)))
+ if (!nonblock && rb_io_wait_readable(fileno(fptr->f)))
goto again;
rb_sys_fail(fptr->path);
}
@@ -1302,7 +1341,7 @@ io_readpartial(int argc, VALUE *argv, VALUE io)
{
VALUE ret;
- ret = io_getpartial(argc, argv, io);
+ ret = io_getpartial(argc, argv, io, 0);
if (NIL_P(ret))
rb_eof_error();
else
@@ -1311,6 +1350,81 @@ io_readpartial(int argc, VALUE *argv, VALUE io)
/*
* call-seq:
+ * ios.read_nonblock(maxlen) => string
+ * ios.read_nonblock(maxlen, outbuf) => outbuf
+ *
+ * Reads at most <i>maxlen</i> bytes from <em>ios</em> using
+ * read(2) system call after O_NONBLOCK is set for
+ * the underlying file descriptor.
+ *
+ * If the optional <i>outbuf</i> argument is present,
+ * it must reference a String, which will receive the data.
+ *
+ * read_nonblock just calls read(2).
+ * It causes all errors read(2) causes: EAGAIN, EINTR, etc.
+ * The caller should care such errors.
+ *
+ * read_nonblock causes EOFError on EOF.
+ *
+ * If the read buffer is not empty,
+ * read_nonblock reads from the buffer like readpartial.
+ * In this case, read(2) is not called.
+ *
+ */
+
+static VALUE
+io_read_nonblock(int argc, VALUE *argv, VALUE io)
+{
+ VALUE ret;
+
+ ret = io_getpartial(argc, argv, io, 1);
+ if (NIL_P(ret))
+ rb_eof_error();
+ else
+ return ret;
+}
+
+/*
+ * call-seq:
+ * ios.write_nonblock(string) => integer
+ *
+ * Writes the given string to <em>ios</em> using
+ * write(2) system call after O_NONBLOCK is set for
+ * the underlying file descriptor.
+ *
+ * write_nonblock just calls write(2).
+ * It causes all errors write(2) causes: EAGAIN, EINTR, etc.
+ * The result may also be smaller than string.length (partial write).
+ * The caller should care such errors and partial write.
+ *
+ */
+
+static VALUE
+rb_io_write_nonblock(VALUE io, VALUE str)
+{
+ OpenFile *fptr;
+ FILE *f;
+ long n;
+
+ rb_secure(4);
+ if (TYPE(str) != T_STRING)
+ str = rb_obj_as_string(str);
+
+ GetOpenFile(io, fptr);
+ rb_io_check_writable(fptr);
+
+ f = GetWriteFile(fptr);
+
+ rb_io_set_nonblock(fptr);
+ n = write(fileno(f), RSTRING(str)->ptr, RSTRING(str)->len);
+
+ if (n == -1) rb_sys_fail(fptr->path);
+
+ return LONG2FIX(n);
+}
+
+/*
+ * call-seq:
* ios.read([length [, buffer]]) => string, buffer, or nil
*
* Reads at most <i>length</i> bytes from the I/O stream, or to the
@@ -5663,6 +5777,8 @@ Init_IO()
rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
+ rb_define_method(rb_cIO, "read_nonblock", io_read_nonblock, -1);
+ rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, 1);
rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
rb_define_method(rb_cIO, "read", io_read, -1);
rb_define_method(rb_cIO, "write", io_write, 1);