Commit a55accd7 authored by ksss's avatar ksss

Implement IO.pipe

parent c9a4091b
...@@ -16,7 +16,7 @@ IO, File module for mruby ...@@ -16,7 +16,7 @@ IO, File module for mruby
| IO.copy_stream | | | | IO.copy_stream | | |
| IO.new, IO.for_fd, IO.open | o | | | IO.new, IO.for_fd, IO.open | o | |
| IO.foreach | | | | IO.foreach | | |
| IO.pipe | | | | IO.pipe | o | |
| IO.popen | o | | | IO.popen | o | |
| IO.read | o | | | IO.read | o | |
| IO.readlines | | | | IO.readlines | | |
......
...@@ -41,6 +41,19 @@ class IO ...@@ -41,6 +41,19 @@ class IO
end end
end end
def self.pipe(&block)
if block
begin
r, w = IO._pipe
yield r, w
ensure
r.close unless r.closed?
w.close unless w.closed?
end
else
IO._pipe
end
end
def self.read(path, length=nil, offset=nil, opt=nil) def self.read(path, length=nil, offset=nil, opt=nil)
if not opt.nil? # 4 arguments if not opt.nil? # 4 arguments
......
...@@ -149,6 +149,32 @@ mrb_fd_cloexec(mrb_state *mrb, int fd) ...@@ -149,6 +149,32 @@ mrb_fd_cloexec(mrb_state *mrb, int fd)
#endif #endif
} }
static int
mrb_cloexec_pipe(mrb_state *mrb, int fildes[2])
{
int ret;
ret = pipe(fildes);
if (ret == -1)
return -1;
mrb_fd_cloexec(mrb, fildes[0]);
mrb_fd_cloexec(mrb, fildes[1]);
return ret;
}
static int
mrb_pipe(mrb_state *mrb, int pipes[2])
{
int ret;
ret = mrb_cloexec_pipe(mrb, pipes);
if (ret == -1) {
if (errno == EMFILE || errno == ENFILE) {
mrb_garbage_collect(mrb);
ret = mrb_cloexec_pipe(mrb, pipes);
}
}
return ret;
}
#ifndef _WIN32 #ifndef _WIN32
static int static int
mrb_proc_exec(const char *pname) mrb_proc_exec(const char *pname)
...@@ -644,6 +670,42 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) ...@@ -644,6 +670,42 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io)
return 0; return 0;
} }
static mrb_value
mrb_io_s_pipe(mrb_state *mrb, mrb_value klass)
{
mrb_value r = mrb_nil_value();
mrb_value w = mrb_nil_value();
struct mrb_io *fptr_r;
struct mrb_io *fptr_w;
int pipes[2];
if (mrb_pipe(mrb, pipes) == -1) {
mrb_sys_fail(mrb, "pipe");
}
r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0));
fptr_r = mrb_io_alloc(mrb);
fptr_r->fd = pipes[0];
fptr_r->writable = 0;
fptr_r->sync = 0;
DATA_TYPE(r) = &mrb_io_type;
DATA_PTR(r) = fptr_r;
w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@pos"), mrb_fixnum_value(0));
fptr_w = mrb_io_alloc(mrb);
fptr_w->fd = pipes[1];
fptr_w->writable = 1;
fptr_w->sync = 1;
DATA_TYPE(w) = &mrb_io_type;
DATA_PTR(w) = fptr_w;
return mrb_assoc_new(mrb, r, w);
}
static mrb_value static mrb_value
mrb_io_s_select(mrb_state *mrb, mrb_value klass) mrb_io_s_select(mrb_state *mrb, mrb_value klass)
{ {
...@@ -925,6 +987,7 @@ mrb_init_io(mrb_state *mrb) ...@@ -925,6 +987,7 @@ mrb_init_io(mrb_state *mrb)
mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY());
mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY());
mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY());
mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE());
mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/ mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY()); /* 15.2.20.5.21 (x)*/
mrb_define_method(mrb, io, "sync", mrb_io_sync, MRB_ARGS_NONE()); mrb_define_method(mrb, io, "sync", mrb_io_sync, MRB_ARGS_NONE());
......
...@@ -402,28 +402,23 @@ assert('IO#close_on_exec') do ...@@ -402,28 +402,23 @@ assert('IO#close_on_exec') do
io.close io.close
io.closed? io.closed?
# # Use below when IO.pipe is implemented. begin
# begin r, w = IO.pipe
# r, w = IO.pipe assert_equal(true, r.close_on_exec?)
# assert_equal(false, r.close_on_exec?) r.close_on_exec = false
# r.close_on_exec = true assert_equal(false, r.close_on_exec?)
# assert_equal(true, r.close_on_exec?) r.close_on_exec = true
# r.close_on_exec = false assert_equal(true, r.close_on_exec?)
# assert_equal(false, r.close_on_exec?)
# r.close_on_exec = true assert_equal(true, w.close_on_exec?)
# assert_equal(true, r.close_on_exec?) w.close_on_exec = false
assert_equal(false, w.close_on_exec?)
# assert_equal(false, w.close_on_exec?) w.close_on_exec = true
# w.close_on_exec = true assert_equal(true, w.close_on_exec?)
# assert_equal(true, w.close_on_exec?) ensure
# w.close_on_exec = false r.close unless r.closed?
# assert_equal(false, w.close_on_exec?) w.close unless w.closed?
# w.close_on_exec = true end
# assert_equal(true, w.close_on_exec?)
# ensure
# r.close unless r.closed?
# w.close unless w.closed?
# end
end end
assert('IO#sysseek') do assert('IO#sysseek') do
...@@ -434,6 +429,42 @@ assert('IO#sysseek') do ...@@ -434,6 +429,42 @@ assert('IO#sysseek') do
end end
end end
assert('IO.pipe') do
called = false
IO.pipe do |r, w|
assert_true r.kind_of?(IO)
assert_true w.kind_of?(IO)
assert_false r.closed?
assert_false w.closed?
assert_true FileTest.pipe?(r)
assert_true FileTest.pipe?(w)
assert_nil r.pid
assert_nil w.pid
assert_true 2 < r.fileno
assert_true 2 < w.fileno
assert_true r.fileno != w.fileno
assert_false r.sync
assert_true w.sync
assert_equal 8, w.write('test for')
assert_equal 'test', r.read(4)
assert_equal ' for', r.read(4)
assert_equal 5, w.write(' pipe')
assert_equal nil, w.close
assert_equal ' pipe', r.read
called = true
assert_raise(IOError) { r.write 'test' }
# TODO:
# This assert expect raise IOError but got RuntimeError
# Because mruby-io not have flag for I/O readable
# assert_raise(IOError) { w.read }
end
assert_true called
assert_nothing_raised do
IO.pipe { |r, w| r.close; w.close }
end
end
assert('`cmd`') do assert('`cmd`') do
assert_equal `echo foo`, "foo\n" assert_equal `echo foo`, "foo\n"
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment