From a901b166901601c6b132c2036882ad9754722f1c Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 15 Aug 2013 16:21:30 -0700 Subject: [PATCH 01/26] std: bootstrapping libuv-based fileio in newrt... open & close the test "touch"es a new file --- src/libstd/rt/uv/file.rs | 169 ++++++++++++++++++++++++++++++++++++--- src/libstd/rt/uv/mod.rs | 22 +++-- src/libstd/rt/uv/uvll.rs | 45 +++++++++++ src/rt/rustrt.def.in | 10 +++ 4 files changed, 232 insertions(+), 14 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 2d14505509759..cab27ee29c1c0 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -11,30 +11,87 @@ use prelude::*; use ptr::null; use libc::c_void; -use rt::uv::{Request, NativeHandle, Loop, FsCallback}; +use rt::uv::{Request, NativeHandle, Loop, FsCallback, + status_to_maybe_uv_error_with_loop}; use rt::uv::uvll; use rt::uv::uvll::*; +use path::Path; +use cast::transmute; +use libc::{c_int}; pub struct FsRequest(*uvll::uv_fs_t); impl Request for FsRequest; +#[allow(non_camel_case_types)] +pub enum UvFileFlag { + O_RDONLY, + O_WRONLY, + O_RDWR, + O_CREAT, + O_TRUNC +} +pub fn map_flag(v: UvFileFlag) -> int { + unsafe { + match v { + O_RDONLY => uvll::get_O_RDONLY() as int, + O_WRONLY => uvll::get_O_WRONLY() as int, + O_RDWR => uvll::get_O_RDWR() as int, + O_CREAT => uvll::get_O_CREAT() as int, + O_TRUNC => uvll::get_O_TRUNC() as int + } + } +} + +pub struct RequestData { + complete_cb: Option +} + impl FsRequest { - fn new() -> FsRequest { + pub fn new(cb: Option) -> FsRequest { let fs_req = unsafe { malloc_req(UV_FS) }; assert!(fs_req.is_not_null()); - let fs_req = fs_req as *uvll::uv_write_t; - unsafe { uvll::set_data_for_req(fs_req, null::<()>()); } - NativeHandle::from_native_handle(fs_req) + let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req); + fs_req.install_req_data(cb); + fs_req + } + + pub fn install_req_data(&self, cb: Option) { + let fs_req = (self.native_handle()) as *uvll::uv_write_t; + let data = ~RequestData { + complete_cb: cb + }; + unsafe { + let data = transmute::<~RequestData, *c_void>(data); + uvll::set_data_for_req(fs_req, data); + } } - fn delete(self) { - unsafe { free_req(self.native_handle() as *c_void) } + fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData { + unsafe { + let data = uvll::get_data_for_req((self.native_handle())); + let data = transmute::<&*c_void, &mut ~RequestData>(&data); + return &mut **data; + } } - fn open(&mut self, _loop_: &Loop, _cb: FsCallback) { + pub fn get_result(&mut self) -> c_int { + unsafe { + uvll::get_result_from_fs_req(self.native_handle()) + } } - fn close(&mut self, _loop_: &Loop, _cb: FsCallback) { + pub fn get_loop(&self) -> Loop { + unsafe { Loop{handle:uvll::get_loop_from_fs_req(self.native_handle())} } + } + + fn cleanup_and_delete(self) { + unsafe { + uvll::fs_req_cleanup(self.native_handle()); + let data = uvll::get_data_for_uv_handle(self.native_handle()); + let _data = transmute::<*c_void, ~RequestData>(data); + uvll::set_data_for_uv_handle(self.native_handle(), null::<()>()); + free_req(self.native_handle() as *c_void) + } } } @@ -46,3 +103,97 @@ impl NativeHandle<*uvll::uv_fs_t> for FsRequest { match self { &FsRequest(ptr) => ptr } } } + +pub struct FileDescriptor(c_int); +impl FileDescriptor { + fn new(fd: c_int) -> FileDescriptor { + FileDescriptor(fd) + } + + pub fn from_open_req(req: &mut FsRequest) -> FileDescriptor { + FileDescriptor::new(req.get_result()) + } + + pub fn open(loop_: Loop, path: Path, flags: int, mode: int, + cb: FsCallback) -> int { + let req = FsRequest::new(Some(cb)); + path.to_str().to_c_str().with_ref(|p| unsafe { + uvll::fs_open(loop_.native_handle(), + req.native_handle(), p, flags, mode, complete_cb) as int + }) + + } + + fn close(self, loop_: Loop, cb: FsCallback) -> int { + let req = FsRequest::new(Some(cb)); + unsafe { + uvll::fs_close(loop_.native_handle(), req.native_handle(), + self.native_handle(), complete_cb) as int + } + } +} +extern fn complete_cb(req: *uv_fs_t) { + let mut req: FsRequest = NativeHandle::from_native_handle(req); + let loop_ = req.get_loop(); + // pull the user cb out of the req data + let cb = { + let data = req.get_req_data(); + assert!(data.complete_cb.is_some()); + // option dance, option dance. oooooh yeah. + data.complete_cb.take_unwrap() + }; + // in uv_fs_open calls, the result will be the fd in the + // case of success, otherwise it's -1 indicating an error + let result = req.get_result(); + let status = status_to_maybe_uv_error_with_loop( + loop_.native_handle(), result); + // we have a req and status, call the user cb.. + // only giving the user a ref to the FsRequest, as we + // have to clean it up, afterwards (and they aren't really + // reusable, anyways + cb(&mut req, status); + // clean up the req (and its data!) after calling the user cb + req.cleanup_and_delete(); +} + +impl NativeHandle for FileDescriptor { + fn from_native_handle(handle: c_int) -> FileDescriptor { + FileDescriptor(handle) + } + fn native_handle(&self) -> c_int { + match self { &FileDescriptor(ptr) => ptr } + } +} + +mod test { + use super::*; + //use rt::test::*; + use unstable::run_in_bare_thread; + use path::Path; + use rt::uv::Loop; + + // this is equiv to touch, i guess? + fn file_test_touch_impl() { + debug!("hello?") + do run_in_bare_thread { + debug!("In bare thread") + let loop_ = Loop::new(); + let flags = map_flag(O_RDWR) | + map_flag(O_CREAT) | map_flag(O_TRUNC); + do FileDescriptor::open(loop_, Path("./foo.txt"), flags, 0644) + |req, uverr| { + let loop_ = req.get_loop(); + assert!(uverr.is_none()); + let fd = FileDescriptor::from_open_req(req); + do fd.close(loop_) |_, uverr| { + assert!(uverr.is_none()); + }; + }; + } + } + + #[test] + fn file_test_touch() { + file_test_touch_impl(); + } +} diff --git a/src/libstd/rt/uv/mod.rs b/src/libstd/rt/uv/mod.rs index 9312efbf03e9a..75b9a5ac553e8 100644 --- a/src/libstd/rt/uv/mod.rs +++ b/src/libstd/rt/uv/mod.rs @@ -53,7 +53,7 @@ use rt::io::IoError; //#[cfg(test)] use unstable::run_in_bare_thread; -pub use self::file::FsRequest; +pub use self::file::{FsRequest}; pub use self::net::{StreamWatcher, TcpWatcher, UdpWatcher}; pub use self::idle::IdleWatcher; pub use self::timer::TimerWatcher; @@ -125,7 +125,7 @@ pub type ReadCallback = ~fn(StreamWatcher, int, Buf, Option); pub type NullCallback = ~fn(); pub type IdleCallback = ~fn(IdleWatcher, Option); pub type ConnectionCallback = ~fn(StreamWatcher, Option); -pub type FsCallback = ~fn(FsRequest, Option); +pub type FsCallback = ~fn(&mut FsRequest, Option); pub type TimerCallback = ~fn(TimerWatcher, Option); pub type AsyncCallback = ~fn(AsyncWatcher, Option); pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option); @@ -281,6 +281,20 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError { } } +/// Given a uv handle, convert a callback status to a UvError +pub fn status_to_maybe_uv_error_with_loop( + loop_: *uvll::uv_loop_t, + status: c_int) -> Option { + if status != -1 { + None + } else { + unsafe { + rtdebug!("loop: %x", loop_ as uint); + let err = uvll::last_error(loop_); + Some(UvError(err)) + } + } +} /// Given a uv handle, convert a callback status to a UvError pub fn status_to_maybe_uv_error>(handle: U, status: c_int) -> Option { @@ -290,9 +304,7 @@ pub fn status_to_maybe_uv_error>(handle: U, unsafe { rtdebug!("handle: %x", handle.native_handle() as uint); let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle()); - rtdebug!("loop: %x", loop_ as uint); - let err = uvll::last_error(loop_); - Some(UvError(err)) + status_to_maybe_uv_error_with_loop(loop_, status) } } } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 71387b09a8d0a..b6cffa754c148 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -617,7 +617,40 @@ pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint { return rust_uv_ip6_port(addr); } +pub unsafe fn fs_open(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags: int, mode: int, + cb: *u8) -> c_int { + rust_uv_fs_open(loop_ptr, req, path, flags as c_int, mode as c_int, cb) +} +pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, + cb: *u8) -> c_int { + rust_uv_fs_close(loop_ptr, req, fd, cb) +} +pub unsafe fn fs_req_cleanup(req: *uv_fs_t) { + rust_uv_fs_req_cleanup(req); +} + // data access helpers +pub unsafe fn get_O_RDONLY() -> c_int { + rust_uv_get_O_RDONLY() +} +pub unsafe fn get_O_WRONLY() -> c_int { + rust_uv_get_O_WRONLY() +} +pub unsafe fn get_O_RDWR() -> c_int { + rust_uv_get_O_RDWR() +} +pub unsafe fn get_O_CREAT() -> c_int { + rust_uv_get_O_CREAT() +} +pub unsafe fn get_O_TRUNC() -> c_int { + rust_uv_get_O_TRUNC() +} +pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int { + rust_uv_get_result_from_fs_req(req) +} +pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t { + rust_uv_get_loop_from_fs_req(req) +} pub unsafe fn get_loop_for_uv_handle(handle: *T) -> *c_void { #[fixed_stack_segment]; #[inline(never)]; @@ -784,6 +817,18 @@ extern { fn rust_uv_timer_start(timer_handle: *uv_timer_t, cb: uv_timer_cb, timeout: libc::uint64_t, repeat: libc::uint64_t) -> c_int; fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; + fn rust_uv_fs_open(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, + flags: c_int, mode: c_int, cb: *u8) -> c_int; + fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, + cb: *u8) -> c_int; + fn rust_uv_fs_req_cleanup(req: *uv_fs_t); + fn rust_uv_get_O_RDONLY() -> c_int; + fn rust_uv_get_O_WRONLY() -> c_int; + fn rust_uv_get_O_RDWR() -> c_int; + fn rust_uv_get_O_CREAT() -> c_int; + fn rust_uv_get_O_TRUNC() -> c_int; + fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int; + fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t; fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t; fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t; diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index ecf22d72b128e..0e9eefd3018c7 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -108,6 +108,16 @@ rust_uv_idle_delete rust_uv_idle_init rust_uv_idle_start rust_uv_idle_stop +rust_uv_fs_open +rust_uv_fs_close +rust_uv_get_O_RDONLY +rust_uv_get_O_WRONLY +rust_uv_get_O_RDWR +rust_uv_get_O_CREAT +rust_uv_get_O_TRUNC +rust_uv_get_result_from_fs_req +rust_uv_get_loop_from_fs_req +rust_uv_fs_req_cleanup rust_dbg_lock_create rust_dbg_lock_destroy rust_dbg_lock_lock From dabbac1d6c06c00f24148ffc58b42455496fdd3c Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 15 Aug 2013 23:54:54 -0700 Subject: [PATCH 02/26] std: working tests for low-level libuv open, write and close operations --- src/libstd/rt/uv/file.rs | 119 +++++++++++++++++++++++++++++++++++---- src/libstd/rt/uv/uvll.rs | 34 ++++++----- src/rt/rust_uv.cpp | 47 ++++++++++++++-- src/rt/rustrt.def.in | 5 ++ 4 files changed, 174 insertions(+), 31 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index cab27ee29c1c0..2a16a34070d24 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -11,8 +11,9 @@ use prelude::*; use ptr::null; use libc::c_void; -use rt::uv::{Request, NativeHandle, Loop, FsCallback, - status_to_maybe_uv_error_with_loop}; +use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, + status_to_maybe_uv_error_with_loop, + vec_to_uv_buf};//, vec_from_uv_buf}; use rt::uv::uvll; use rt::uv::uvll::*; use path::Path; @@ -30,6 +31,14 @@ pub enum UvFileFlag { O_CREAT, O_TRUNC } +// just want enough to get 0644 +#[allow(non_camel_case_types)] +pub enum UvFileMode { + S_IWUSR, + S_IRUSR, + S_IRGRP, + S_IROTH +} pub fn map_flag(v: UvFileFlag) -> int { unsafe { match v { @@ -41,9 +50,21 @@ pub fn map_flag(v: UvFileFlag) -> int { } } } +pub fn map_mode(v: UvFileMode) -> int { + unsafe { + match v { + S_IWUSR => uvll::get_S_IWUSR() as int, + S_IRUSR => uvll::get_S_IRUSR() as int, + S_IRGRP => uvll::get_S_IRGRP() as int, + S_IROTH => uvll::get_S_IROTH() as int + } + } +} pub struct RequestData { - complete_cb: Option + complete_cb: Option, + buf: Option, + raw_fd: Option } impl FsRequest { @@ -58,7 +79,9 @@ impl FsRequest { pub fn install_req_data(&self, cb: Option) { let fs_req = (self.native_handle()) as *uvll::uv_write_t; let data = ~RequestData { - complete_cb: cb + complete_cb: cb, + buf: None, + raw_fd: None }; unsafe { let data = transmute::<~RequestData, *c_void>(data); @@ -86,10 +109,10 @@ impl FsRequest { fn cleanup_and_delete(self) { unsafe { - uvll::fs_req_cleanup(self.native_handle()); - let data = uvll::get_data_for_uv_handle(self.native_handle()); + let data = uvll::get_data_for_req(self.native_handle()); let _data = transmute::<*c_void, ~RequestData>(data); - uvll::set_data_for_uv_handle(self.native_handle(), null::<()>()); + uvll::set_data_for_req(self.native_handle(), null::<()>()); + uvll::fs_req_cleanup(self.native_handle()); free_req(self.native_handle() as *c_void) } } @@ -121,10 +144,24 @@ impl FileDescriptor { uvll::fs_open(loop_.native_handle(), req.native_handle(), p, flags, mode, complete_cb) as int }) + } + pub fn write(&self, loop_: Loop, buf: ~[u8], offset: i64, cb: FsCallback) + -> int { + let mut req = FsRequest::new(Some(cb)); + let len = buf.len(); + let buf = vec_to_uv_buf(buf); + let base_ptr = buf.base as *c_void; + req.get_req_data().buf = Some(buf); + req.get_req_data().raw_fd = Some(self.native_handle()); + unsafe { + uvll::fs_write(loop_.native_handle(), req.native_handle(), + self.native_handle(), base_ptr, + len, offset, complete_cb) as int + } } - fn close(self, loop_: Loop, cb: FsCallback) -> int { + pub fn close(self, loop_: Loop, cb: FsCallback) -> int { let req = FsRequest::new(Some(cb)); unsafe { uvll::fs_close(loop_.native_handle(), req.native_handle(), @@ -170,17 +207,22 @@ mod test { //use rt::test::*; use unstable::run_in_bare_thread; use path::Path; - use rt::uv::Loop; + use rt::uv::{Loop};//, slice_to_uv_buf}; // this is equiv to touch, i guess? fn file_test_touch_impl() { debug!("hello?") do run_in_bare_thread { debug!("In bare thread") - let loop_ = Loop::new(); + let mut loop_ = Loop::new(); let flags = map_flag(O_RDWR) | - map_flag(O_CREAT) | map_flag(O_TRUNC); - do FileDescriptor::open(loop_, Path("./foo.txt"), flags, 0644) + map_flag(O_CREAT); + // 0644 + let mode = map_mode(S_IWUSR) | + map_mode(S_IRUSR) | + map_mode(S_IRGRP) | + map_mode(S_IROTH); + do FileDescriptor::open(loop_, Path("./foo.txt"), flags, mode) |req, uverr| { let loop_ = req.get_loop(); assert!(uverr.is_none()); @@ -189,6 +231,7 @@ mod test { assert!(uverr.is_none()); }; }; + loop_.run(); } } @@ -196,4 +239,56 @@ mod test { fn file_test_touch() { file_test_touch_impl(); } + + fn file_test_tee_impl() { + debug!("hello?") + do run_in_bare_thread { + debug!("In bare thread") + let mut loop_ = Loop::new(); + let flags = map_flag(O_RDWR) | + map_flag(O_CREAT); + // 0644 + let mode = map_mode(S_IWUSR) | + map_mode(S_IRUSR) | + map_mode(S_IRGRP) | + map_mode(S_IROTH); + do FileDescriptor::open(loop_, Path("./file_tee_test.txt"), flags, mode) + |req, uverr| { + let loop_ = req.get_loop(); + assert!(uverr.is_none()); + let fd = FileDescriptor::from_open_req(req); + let msg: ~[u8] = "hello world".as_bytes().to_owned(); + let raw_fd = fd.native_handle(); + do fd.write(loop_, msg, -1) |_, uverr| { + let fd = FileDescriptor(raw_fd); + do fd.close(loop_) |_, _| { + assert!(uverr.is_none()); + }; + }; + }; + loop_.run(); + } + } + + #[test] + fn file_test_tee() { + file_test_tee_impl(); + } + + fn naive_print(input: ~str) { + do run_in_bare_thread { + let mut loop_ = Loop::new(); + let stdout = FileDescriptor(1); + let msg = input.as_bytes().to_owned(); + do stdout.write(loop_, msg, -1) |_, uverr| { + assert!(uverr.is_none()); + }; + loop_.run(); + } + } + + #[test] + fn file_test_println() { + naive_print(~"oh yeah.\n"); + } } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index b6cffa754c148..0fbf45fca9702 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -621,6 +621,10 @@ pub unsafe fn fs_open(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags: cb: *u8) -> c_int { rust_uv_fs_open(loop_ptr, req, path, flags as c_int, mode as c_int, cb) } +pub unsafe fn fs_write(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void, + len: uint, offset: i64, cb: *u8) -> c_int { + rust_uv_fs_write(loop_ptr, req, fd, buf, len as c_uint, offset, cb) +} pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int { rust_uv_fs_close(loop_ptr, req, fd, cb) @@ -630,21 +634,15 @@ pub unsafe fn fs_req_cleanup(req: *uv_fs_t) { } // data access helpers -pub unsafe fn get_O_RDONLY() -> c_int { - rust_uv_get_O_RDONLY() -} -pub unsafe fn get_O_WRONLY() -> c_int { - rust_uv_get_O_WRONLY() -} -pub unsafe fn get_O_RDWR() -> c_int { - rust_uv_get_O_RDWR() -} -pub unsafe fn get_O_CREAT() -> c_int { - rust_uv_get_O_CREAT() -} -pub unsafe fn get_O_TRUNC() -> c_int { - rust_uv_get_O_TRUNC() -} +pub unsafe fn get_O_RDONLY() -> c_int { rust_uv_get_O_RDONLY() } +pub unsafe fn get_O_WRONLY() -> c_int { rust_uv_get_O_WRONLY() } +pub unsafe fn get_O_RDWR() -> c_int { rust_uv_get_O_RDWR() } +pub unsafe fn get_O_CREAT() -> c_int { rust_uv_get_O_CREAT() } +pub unsafe fn get_O_TRUNC() -> c_int { rust_uv_get_O_TRUNC() } +pub unsafe fn get_S_IWUSR() -> c_int { rust_uv_get_S_IWUSR() } +pub unsafe fn get_S_IRUSR() -> c_int { rust_uv_get_S_IRUSR() } +pub unsafe fn get_S_IRGRP() -> c_int { rust_uv_get_S_IRGRP() } +pub unsafe fn get_S_IROTH() -> c_int { rust_uv_get_S_IROTH() } pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int { rust_uv_get_result_from_fs_req(req) } @@ -819,6 +817,8 @@ extern { fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; fn rust_uv_fs_open(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, flags: c_int, mode: c_int, cb: *u8) -> c_int; + fn rust_uv_fs_write(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, + buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int; fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int; fn rust_uv_fs_req_cleanup(req: *uv_fs_t); @@ -827,6 +827,10 @@ extern { fn rust_uv_get_O_RDWR() -> c_int; fn rust_uv_get_O_CREAT() -> c_int; fn rust_uv_get_O_TRUNC() -> c_int; + fn rust_uv_get_S_IWUSR() -> c_int; + fn rust_uv_get_S_IRUSR() -> c_int; + fn rust_uv_get_S_IRGRP() -> c_int; + fn rust_uv_get_S_IROTH() -> c_int; fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int; fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t; diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index b5d6e02b46a4c..a788b0f71a4a5 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -18,16 +18,13 @@ #include #endif +#include #include "uv.h" #include "rust_globals.h" extern "C" void* rust_uv_loop_new() { -// XXX libuv doesn't always ignore SIGPIPE even though we don't need it. -#ifndef __WIN32__ - signal(SIGPIPE, SIG_IGN); -#endif return (void*)uv_loop_new(); } @@ -517,3 +514,45 @@ extern "C" uintptr_t rust_uv_req_type_max() { return UV_REQ_TYPE_MAX; } + +extern "C" int +rust_uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, + int mode, uv_fs_cb cb) { + return uv_fs_open(loop, req, path, flags, mode, cb); +} +extern "C" int +rust_uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { + return uv_fs_close(loop, req, fd, cb); +} +extern "C" void +rust_uv_fs_req_cleanup(uv_fs_t* req) { + uv_fs_req_cleanup(req); +} +extern "C" int +rust_uv_get_O_RDONLY() { + return O_RDONLY; +} +extern "C" int +rust_uv_get_O_WRONLY() { + return O_WRONLY; +} +extern "C" int +rust_uv_get_O_RDWR() { + return O_RDWR; +} +extern "C" int +rust_uv_get_O_CREAT() { + return O_CREAT; +} +extern "C" int +rust_uv_get_O_TRUNC() { + return O_TRUNC; +} +extern "C" int +rust_uv_get_result_from_fs_req(uv_fs_t* req) { + return req->result; +} +extern "C" uv_loop_t* +rust_uv_get_loop_from_fs_req(uv_fs_t* req) { + return req->loop; +} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 0e9eefd3018c7..d342ffa194ae1 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -109,12 +109,17 @@ rust_uv_idle_init rust_uv_idle_start rust_uv_idle_stop rust_uv_fs_open +rust_uv_fs_write rust_uv_fs_close rust_uv_get_O_RDONLY rust_uv_get_O_WRONLY rust_uv_get_O_RDWR rust_uv_get_O_CREAT rust_uv_get_O_TRUNC +rust_uv_get_S_IRUSR +rust_uv_get_S_IWUSR +rust_uv_get_S_IROTH +rust_uv_get_S_IRGRP rust_uv_get_result_from_fs_req rust_uv_get_loop_from_fs_req rust_uv_fs_req_cleanup From c49c2921b0250fee51b935e3d164cc1bdb8a9445 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Fri, 16 Aug 2013 17:47:35 -0700 Subject: [PATCH 03/26] std: add read and unlink to low-level FileDescriptor + end-to-end CRUD test --- src/libstd/rt/uv/file.rs | 159 ++++++++++++++++++++++++++------------- src/libstd/rt/uv/uvll.rs | 13 ++++ src/rt/rust_uv.cpp | 35 +++++++-- src/rt/rustrt.def.in | 2 + 4 files changed, 151 insertions(+), 58 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 2a16a34070d24..ef8c131688b44 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -13,12 +13,14 @@ use ptr::null; use libc::c_void; use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, status_to_maybe_uv_error_with_loop, - vec_to_uv_buf};//, vec_from_uv_buf}; + vec_to_uv_buf, vec_from_uv_buf}; use rt::uv::uvll; use rt::uv::uvll::*; use path::Path; use cast::transmute; use libc::{c_int}; +use option::{None, Some, Option}; +use vec; pub struct FsRequest(*uvll::uv_fs_t); impl Request for FsRequest; @@ -110,7 +112,15 @@ impl FsRequest { fn cleanup_and_delete(self) { unsafe { let data = uvll::get_data_for_req(self.native_handle()); - let _data = transmute::<*c_void, ~RequestData>(data); + let mut _data = transmute::<*c_void, ~RequestData>(data); + // if set we're going to convert the buf param back into + // a rust vec, as that's the mechanism by which the raw + // uv_buf_t's .base field gets freed. We immediately discard + // the result + if _data.buf.is_some() { + let buf = _data.buf.take_unwrap(); + vec_from_uv_buf(buf); + } uvll::set_data_for_req(self.native_handle(), null::<()>()); uvll::fs_req_cleanup(self.native_handle()); free_req(self.native_handle() as *c_void) @@ -146,6 +156,15 @@ impl FileDescriptor { }) } + pub fn unlink(loop_: Loop, path: Path, cb: FsCallback) -> int { + let req = FsRequest::new(Some(cb)); + path.to_str().to_c_str().with_ref(|p| unsafe { + uvll::fs_unlink(loop_.native_handle(), + req.native_handle(), p, complete_cb) as int + }) + } + + // as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write pub fn write(&self, loop_: Loop, buf: ~[u8], offset: i64, cb: FsCallback) -> int { let mut req = FsRequest::new(Some(cb)); @@ -161,6 +180,31 @@ impl FileDescriptor { } } + // really contemplated having this just take a read_len param and have + // the buf live in the scope of this request.. but decided that exposing + // an unsafe mechanism that takes a buf_ptr and len would be much more + // flexible, but the caller is now in the position of managing that + // buf (with all of the sadface that this entails) + pub fn read(&self, loop_: Loop, buf_ptr: Option<*c_void>, len: uint, offset: i64, cb: FsCallback) + -> int { + let mut req = FsRequest::new(Some(cb)); + req.get_req_data().raw_fd = Some(self.native_handle()); + unsafe { + let buf_ptr = match buf_ptr { + Some(ptr) => ptr, + None => { + let buf = vec::from_elem(len, 0u8); + let buf = vec_to_uv_buf(buf); + req.get_req_data().buf = Some(buf); + buf.base as *c_void + } + }; + uvll::fs_read(loop_.native_handle(), req.native_handle(), + self.native_handle(), buf_ptr, + len, offset, complete_cb) as int + } + } + pub fn close(self, loop_: Loop, cb: FsCallback) -> int { let req = FsRequest::new(Some(cb)); unsafe { @@ -205,90 +249,99 @@ impl NativeHandle for FileDescriptor { mod test { use super::*; //use rt::test::*; + use libc::{STDOUT_FILENO}; + use str; use unstable::run_in_bare_thread; use path::Path; - use rt::uv::{Loop};//, slice_to_uv_buf}; - - // this is equiv to touch, i guess? - fn file_test_touch_impl() { - debug!("hello?") - do run_in_bare_thread { - debug!("In bare thread") - let mut loop_ = Loop::new(); - let flags = map_flag(O_RDWR) | - map_flag(O_CREAT); - // 0644 - let mode = map_mode(S_IWUSR) | - map_mode(S_IRUSR) | - map_mode(S_IRGRP) | - map_mode(S_IROTH); - do FileDescriptor::open(loop_, Path("./foo.txt"), flags, mode) - |req, uverr| { - let loop_ = req.get_loop(); - assert!(uverr.is_none()); - let fd = FileDescriptor::from_open_req(req); - do fd.close(loop_) |_, uverr| { - assert!(uverr.is_none()); - }; - }; - loop_.run(); - } - } - - #[test] - fn file_test_touch() { - file_test_touch_impl(); - } + use rt::uv::{Loop, vec_from_uv_buf};//, slice_to_uv_buf}; + use option::{None}; - fn file_test_tee_impl() { + fn file_test_full_simple_impl() { debug!("hello?") do run_in_bare_thread { debug!("In bare thread") let mut loop_ = Loop::new(); - let flags = map_flag(O_RDWR) | + let create_flags = map_flag(O_RDWR) | map_flag(O_CREAT); + let read_flags = map_flag(O_RDONLY); // 0644 let mode = map_mode(S_IWUSR) | map_mode(S_IRUSR) | map_mode(S_IRGRP) | map_mode(S_IROTH); - do FileDescriptor::open(loop_, Path("./file_tee_test.txt"), flags, mode) + let path_str = "./file_full_simple.txt"; + let write_val = "hello"; + do FileDescriptor::open(loop_, Path(path_str), create_flags, mode) |req, uverr| { let loop_ = req.get_loop(); assert!(uverr.is_none()); let fd = FileDescriptor::from_open_req(req); - let msg: ~[u8] = "hello world".as_bytes().to_owned(); + let msg: ~[u8] = write_val.as_bytes().to_owned(); let raw_fd = fd.native_handle(); do fd.write(loop_, msg, -1) |_, uverr| { let fd = FileDescriptor(raw_fd); - do fd.close(loop_) |_, _| { + do fd.close(loop_) |req, _| { + let loop_ = req.get_loop(); assert!(uverr.is_none()); + do FileDescriptor::open(loop_, Path(path_str), read_flags,0) + |req, uverr| { + assert!(uverr.is_none()); + let loop_ = req.get_loop(); + let len = 1028; + let fd = FileDescriptor::from_open_req(req); + let raw_fd = fd.native_handle(); + do fd.read(loop_, None, len, 0) |req, uverr| { + assert!(uverr.is_none()); + let loop_ = req.get_loop(); + // we know nread >=0 because uverr is none.. + let nread = req.get_result() as uint; + // nread == 0 would be EOF + if nread > 0 { + let buf = vec_from_uv_buf( + req.get_req_data().buf.take_unwrap()) + .take_unwrap(); + let read_str = str::from_bytes( + buf.slice(0, + nread)); + assert!(read_str == ~"hello"); + do FileDescriptor(raw_fd).close(loop_) |_,uverr| { + assert!(uverr.is_none()); + do FileDescriptor::unlink(loop_, Path(path_str)) + |_,uverr| { + assert!(uverr.is_none()); + }; + }; + } + }; + }; }; }; }; loop_.run(); + loop_.close(); } } #[test] - fn file_test_tee() { - file_test_tee_impl(); + fn file_test_full_simple() { + file_test_full_simple_impl(); } - fn naive_print(input: ~str) { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let stdout = FileDescriptor(1); - let msg = input.as_bytes().to_owned(); - do stdout.write(loop_, msg, -1) |_, uverr| { - assert!(uverr.is_none()); - }; - loop_.run(); - } + fn naive_print(loop_: Loop, input: ~str) { + let stdout = FileDescriptor(STDOUT_FILENO); + let msg = input.as_bytes().to_owned(); + do stdout.write(loop_, msg, -1) |_, uverr| { + assert!(uverr.is_none()); + }; } #[test] - fn file_test_println() { - naive_print(~"oh yeah.\n"); + fn file_test_write_to_stdout() { + do run_in_bare_thread { + let mut loop_ = Loop::new(); + naive_print(loop_, ~"zanzibar!\n"); + loop_.run(); + loop_.close(); + }; } } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 0fbf45fca9702..1b257b708c47a 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -621,10 +621,19 @@ pub unsafe fn fs_open(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags: cb: *u8) -> c_int { rust_uv_fs_open(loop_ptr, req, path, flags as c_int, mode as c_int, cb) } + +pub unsafe fn fs_unlink(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, + cb: *u8) -> c_int { + rust_uv_fs_unlink(loop_ptr, req, path, cb) +} pub unsafe fn fs_write(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void, len: uint, offset: i64, cb: *u8) -> c_int { rust_uv_fs_write(loop_ptr, req, fd, buf, len as c_uint, offset, cb) } +pub unsafe fn fs_read(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void, + len: uint, offset: i64, cb: *u8) -> c_int { + rust_uv_fs_read(loop_ptr, req, fd, buf, len as c_uint, offset, cb) +} pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int { rust_uv_fs_close(loop_ptr, req, fd, cb) @@ -817,8 +826,12 @@ extern { fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; fn rust_uv_fs_open(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, flags: c_int, mode: c_int, cb: *u8) -> c_int; + fn rust_uv_fs_unlink(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char, + cb: *u8) -> c_int; fn rust_uv_fs_write(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int; + fn rust_uv_fs_read(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, + buf: *c_void, len: c_uint, offset: i64, cb: *u8) -> c_int; fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int; fn rust_uv_fs_req_cleanup(req: *uv_fs_t); diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index a788b0f71a4a5..e08b4ac21ebf9 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -13,11 +13,6 @@ #include #endif -#ifndef __WIN32__ -// for signal -#include -#endif - #include #include "uv.h" @@ -521,6 +516,20 @@ rust_uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, return uv_fs_open(loop, req, path, flags, mode, cb); } extern "C" int +rust_uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { + return uv_fs_unlink(loop, req, path, cb); +} +extern "C" int +rust_uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf, + size_t len, int64_t offset, uv_fs_cb cb) { + return uv_fs_write(loop, req, fd, buf, len, offset, cb); +} +extern "C" int +rust_uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf, + size_t len, int64_t offset, uv_fs_cb cb) { + return uv_fs_read(loop, req, fd, buf, len, offset, cb); +} +extern "C" int rust_uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) { return uv_fs_close(loop, req, fd, cb); } @@ -549,6 +558,22 @@ rust_uv_get_O_TRUNC() { return O_TRUNC; } extern "C" int +rust_uv_get_S_IWUSR() { + return S_IWUSR; +} +extern "C" int +rust_uv_get_S_IRUSR() { + return S_IRUSR; +} +extern "C" int +rust_uv_get_S_IRGRP() { + return S_IRGRP; +} +extern "C" int +rust_uv_get_S_IROTH() { + return S_IROTH; +} +extern "C" int rust_uv_get_result_from_fs_req(uv_fs_t* req) { return req->result; } diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index d342ffa194ae1..824a3931771e5 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -109,7 +109,9 @@ rust_uv_idle_init rust_uv_idle_start rust_uv_idle_stop rust_uv_fs_open +rust_uv_fs_unlink rust_uv_fs_write +rust_uv_fs_read rust_uv_fs_close rust_uv_get_O_RDONLY rust_uv_get_O_WRONLY From e0a80ee332dc347d588bfcea66c11896c04263bb Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sat, 17 Aug 2013 00:34:24 -0700 Subject: [PATCH 04/26] std: support async/threadpool & sync paths in uv_fs_* calls + add sync test --- src/libstd/rt/uv/file.rs | 204 ++++++++++++++++++++++++++++++++------- 1 file changed, 169 insertions(+), 35 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index ef8c131688b44..35e425ce65917 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -147,49 +147,92 @@ impl FileDescriptor { FileDescriptor::new(req.get_result()) } + fn open_common(loop_: Loop, path: Path, flags: int, mode: int, + cb: Option) -> int { + let complete_cb_ptr = match cb { + Some(_) => compl_cb, + None => 0 as *u8 + }; + let is_sync = cb.is_none(); + let req = FsRequest::new(cb); + let result = path.to_str().to_c_str().with_ref(|p| unsafe { + uvll::fs_open(loop_.native_handle(), + req.native_handle(), p, flags, mode, complete_cb_ptr) as int + }); + if is_sync { req.cleanup_and_delete(); } + result + } pub fn open(loop_: Loop, path: Path, flags: int, mode: int, cb: FsCallback) -> int { - let req = FsRequest::new(Some(cb)); - path.to_str().to_c_str().with_ref(|p| unsafe { - uvll::fs_open(loop_.native_handle(), - req.native_handle(), p, flags, mode, complete_cb) as int - }) + FileDescriptor::open_common(loop_, path, flags, mode, Some(cb)) + } + pub fn open_sync(loop_: Loop, path: Path, flags: int, mode: int) -> int { + FileDescriptor::open_common(loop_, path, flags, mode, None) } - pub fn unlink(loop_: Loop, path: Path, cb: FsCallback) -> int { - let req = FsRequest::new(Some(cb)); - path.to_str().to_c_str().with_ref(|p| unsafe { + fn unlink_common(loop_: Loop, path: Path, cb: Option) -> int { + let complete_cb_ptr = match cb { + Some(_) => compl_cb, + None => 0 as *u8 + }; + let is_sync = cb.is_none(); + let req = FsRequest::new(cb); + let result = path.to_str().to_c_str().with_ref(|p| unsafe { uvll::fs_unlink(loop_.native_handle(), - req.native_handle(), p, complete_cb) as int - }) + req.native_handle(), p, complete_cb_ptr) as int + }); + if is_sync { req.cleanup_and_delete(); } + result + } + pub fn unlink(loop_: Loop, path: Path, cb: FsCallback) -> int { + FileDescriptor::unlink_common(loop_, path, Some(cb)) + } + pub fn unlink_sync(loop_: Loop, path: Path) -> int { + FileDescriptor::unlink_common(loop_, path, None) } // as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write - pub fn write(&self, loop_: Loop, buf: ~[u8], offset: i64, cb: FsCallback) + fn write_common(&self, loop_: Loop, buf: ~[u8], offset: i64, cb: Option) -> int { - let mut req = FsRequest::new(Some(cb)); + let complete_cb_ptr = match cb { + Some(_) => compl_cb, + None => 0 as *u8 + }; + let is_sync = cb.is_none(); + let mut req = FsRequest::new(cb); let len = buf.len(); let buf = vec_to_uv_buf(buf); let base_ptr = buf.base as *c_void; req.get_req_data().buf = Some(buf); req.get_req_data().raw_fd = Some(self.native_handle()); - unsafe { + let result = unsafe { uvll::fs_write(loop_.native_handle(), req.native_handle(), self.native_handle(), base_ptr, - len, offset, complete_cb) as int - } + len, offset, complete_cb_ptr) as int + }; + if is_sync { req.cleanup_and_delete(); } + result + } + pub fn write(&self, loop_: Loop, buf: ~[u8], offset: i64, cb: FsCallback) + -> int { + self.write_common(loop_, buf, offset, Some(cb)) + } + pub fn write_sync(&self, loop_: Loop, buf: ~[u8], offset: i64) + -> int { + self.write_common(loop_, buf, offset, None) } - // really contemplated having this just take a read_len param and have - // the buf live in the scope of this request.. but decided that exposing - // an unsafe mechanism that takes a buf_ptr and len would be much more - // flexible, but the caller is now in the position of managing that - // buf (with all of the sadface that this entails) - pub fn read(&self, loop_: Loop, buf_ptr: Option<*c_void>, len: uint, offset: i64, cb: FsCallback) + fn read_common(&self, loop_: Loop, buf_ptr: Option<*c_void>, + len: uint, offset: i64, cb: Option) -> int { - let mut req = FsRequest::new(Some(cb)); + let complete_cb_ptr = match cb { + Some(_) => compl_cb, + None => 0 as *u8 + }; + let is_sync = cb.is_none(); + let mut req = FsRequest::new(cb); req.get_req_data().raw_fd = Some(self.native_handle()); - unsafe { + let result = unsafe { let buf_ptr = match buf_ptr { Some(ptr) => ptr, None => { @@ -201,19 +244,43 @@ impl FileDescriptor { }; uvll::fs_read(loop_.native_handle(), req.native_handle(), self.native_handle(), buf_ptr, - len, offset, complete_cb) as int - } + len, offset, complete_cb_ptr) as int + }; + if is_sync { req.cleanup_and_delete(); } + result + } + pub fn read(&self, loop_: Loop, buf_ptr: Option<*c_void>, + len: uint, offset: i64, cb: FsCallback) + -> int { + self.read_common(loop_, buf_ptr, len, offset, Some(cb)) + } + pub fn read_sync(&self, loop_: Loop, buf_ptr: Option<*c_void>, len: uint, offset: i64) + -> int { + self.read_common(loop_, buf_ptr, len, offset, None) } - pub fn close(self, loop_: Loop, cb: FsCallback) -> int { - let req = FsRequest::new(Some(cb)); - unsafe { + fn close_common(self, loop_: Loop, cb: Option) -> int { + let complete_cb_ptr = match cb { + Some(_) => compl_cb, + None => 0 as *u8 + }; + let is_sync = cb.is_none(); + let req = FsRequest::new(cb); + let result = unsafe { uvll::fs_close(loop_.native_handle(), req.native_handle(), - self.native_handle(), complete_cb) as int - } + self.native_handle(), complete_cb_ptr) as int + }; + if is_sync { req.cleanup_and_delete(); } + result + } + pub fn close(self, loop_: Loop, cb: FsCallback) -> int { + self.close_common(loop_, Some(cb)) + } + pub fn close_sync(self, loop_: Loop) -> int { + self.close_common(loop_, None) } } -extern fn complete_cb(req: *uv_fs_t) { +extern fn compl_cb(req: *uv_fs_t) { let mut req: FsRequest = NativeHandle::from_native_handle(req); let loop_ = req.get_loop(); // pull the user cb out of the req data @@ -249,17 +316,18 @@ impl NativeHandle for FileDescriptor { mod test { use super::*; //use rt::test::*; - use libc::{STDOUT_FILENO}; + use option::{Some}; + use libc::{STDOUT_FILENO, c_void}; + use vec; use str; use unstable::run_in_bare_thread; use path::Path; - use rt::uv::{Loop, vec_from_uv_buf};//, slice_to_uv_buf}; + use rt::uv::{Loop, vec_to_uv_buf, vec_from_uv_buf, + status_to_maybe_uv_error_with_loop}; use option::{None}; fn file_test_full_simple_impl() { - debug!("hello?") do run_in_bare_thread { - debug!("In bare thread") let mut loop_ = Loop::new(); let create_flags = map_flag(O_RDWR) | map_flag(O_CREAT); @@ -321,12 +389,78 @@ mod test { loop_.close(); } } + fn file_test_full_simple_impl_sync() { + do run_in_bare_thread { + // setup + let mut loop_ = Loop::new(); + let create_flags = map_flag(O_RDWR) | + map_flag(O_CREAT); + let read_flags = map_flag(O_RDONLY); + // 0644 + let mode = map_mode(S_IWUSR) | + map_mode(S_IRUSR) | + map_mode(S_IRGRP) | + map_mode(S_IROTH); + let path_str = "./file_full_simple_sync.txt"; + let write_val = "hello"; + // open/create + let result = FileDescriptor::open_sync(loop_, Path(path_str), create_flags, mode); + assert!(status_to_maybe_uv_error_with_loop( + loop_.native_handle(), result as i32).is_none()); + let fd = FileDescriptor(result as i32); + let msg: ~[u8] = write_val.as_bytes().to_owned(); + // write + let result = fd.write_sync(loop_, msg, -1); + assert!(status_to_maybe_uv_error_with_loop( + loop_.native_handle(), result as i32).is_none()); + // close + let result = fd.close_sync(loop_); + assert!(status_to_maybe_uv_error_with_loop( + loop_.native_handle(), result as i32).is_none()); + // re-open + let result = FileDescriptor::open_sync(loop_, Path(path_str), read_flags,0); + assert!(status_to_maybe_uv_error_with_loop( + loop_.native_handle(), result as i32).is_none()); + let len = 1028; + let fd = FileDescriptor(result as i32); + // read + let buf: ~[u8] = vec::from_elem(len, 0u8); + let buf = vec_to_uv_buf(buf); + let buf_ptr = buf.base as *c_void; + let result = fd.read_sync(loop_, Some(buf_ptr), len, 0); + assert!(status_to_maybe_uv_error_with_loop( + loop_.native_handle(), result as i32).is_none()); + let nread = result; + // nread == 0 would be EOF.. we know it's >= zero because otherwise + // the above assert would fail + if nread > 0 { + let buf = vec_from_uv_buf(buf).take_unwrap(); + let read_str = str::from_bytes( + buf.slice(0, nread as uint)); + assert!(read_str == ~"hello"); + // close + let result = fd.close_sync(loop_); + assert!(status_to_maybe_uv_error_with_loop( + loop_.native_handle(), result as i32).is_none()); + // unlink + let result = FileDescriptor::unlink_sync(loop_, Path(path_str)); + assert!(status_to_maybe_uv_error_with_loop( + loop_.native_handle(), result as i32).is_none()); + } else { fail!("nread was 0.. wudn't expectin' that."); } + loop_.close(); + } + } #[test] fn file_test_full_simple() { file_test_full_simple_impl(); } + #[test] + fn file_test_full_simple_sync() { + file_test_full_simple_impl_sync(); + } + fn naive_print(loop_: Loop, input: ~str) { let stdout = FileDescriptor(STDOUT_FILENO); let msg = input.as_bytes().to_owned(); From f60bd75f4d8b776cf1e777b59d2d2262d03818a7 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Mon, 19 Aug 2013 16:06:31 -0700 Subject: [PATCH 05/26] std: remove fcntl const bindings + making valgrind clean w/ no owned vecs --- src/libstd/rt/uv/file.rs | 192 ++++++++++++++------------------------- src/libstd/rt/uv/uvll.rs | 18 ---- src/rt/rust_uv.cpp | 36 -------- src/rt/rustrt.def.in | 9 -- 4 files changed, 68 insertions(+), 187 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 35e425ce65917..f3f6c32516255 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -12,60 +12,19 @@ use prelude::*; use ptr::null; use libc::c_void; use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, - status_to_maybe_uv_error_with_loop, - vec_to_uv_buf, vec_from_uv_buf}; + status_to_maybe_uv_error_with_loop}; use rt::uv::uvll; use rt::uv::uvll::*; use path::Path; use cast::transmute; use libc::{c_int}; use option::{None, Some, Option}; -use vec; pub struct FsRequest(*uvll::uv_fs_t); impl Request for FsRequest; -#[allow(non_camel_case_types)] -pub enum UvFileFlag { - O_RDONLY, - O_WRONLY, - O_RDWR, - O_CREAT, - O_TRUNC -} -// just want enough to get 0644 -#[allow(non_camel_case_types)] -pub enum UvFileMode { - S_IWUSR, - S_IRUSR, - S_IRGRP, - S_IROTH -} -pub fn map_flag(v: UvFileFlag) -> int { - unsafe { - match v { - O_RDONLY => uvll::get_O_RDONLY() as int, - O_WRONLY => uvll::get_O_WRONLY() as int, - O_RDWR => uvll::get_O_RDWR() as int, - O_CREAT => uvll::get_O_CREAT() as int, - O_TRUNC => uvll::get_O_TRUNC() as int - } - } -} -pub fn map_mode(v: UvFileMode) -> int { - unsafe { - match v { - S_IWUSR => uvll::get_S_IWUSR() as int, - S_IRUSR => uvll::get_S_IRUSR() as int, - S_IRGRP => uvll::get_S_IRGRP() as int, - S_IROTH => uvll::get_S_IROTH() as int - } - } -} - pub struct RequestData { complete_cb: Option, - buf: Option, raw_fd: Option } @@ -82,7 +41,6 @@ impl FsRequest { let fs_req = (self.native_handle()) as *uvll::uv_write_t; let data = ~RequestData { complete_cb: cb, - buf: None, raw_fd: None }; unsafe { @@ -112,15 +70,7 @@ impl FsRequest { fn cleanup_and_delete(self) { unsafe { let data = uvll::get_data_for_req(self.native_handle()); - let mut _data = transmute::<*c_void, ~RequestData>(data); - // if set we're going to convert the buf param back into - // a rust vec, as that's the mechanism by which the raw - // uv_buf_t's .base field gets freed. We immediately discard - // the result - if _data.buf.is_some() { - let buf = _data.buf.take_unwrap(); - vec_from_uv_buf(buf); - } + let _data = transmute::<*c_void, ~RequestData>(data); uvll::set_data_for_req(self.native_handle(), null::<()>()); uvll::fs_req_cleanup(self.native_handle()); free_req(self.native_handle() as *c_void) @@ -192,7 +142,7 @@ impl FileDescriptor { } // as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write - fn write_common(&self, loop_: Loop, buf: ~[u8], offset: i64, cb: Option) + fn write_common(&self, loop_: Loop, buf: Buf, offset: i64, cb: Option) -> int { let complete_cb_ptr = match cb { Some(_) => compl_cb, @@ -200,10 +150,8 @@ impl FileDescriptor { }; let is_sync = cb.is_none(); let mut req = FsRequest::new(cb); - let len = buf.len(); - let buf = vec_to_uv_buf(buf); let base_ptr = buf.base as *c_void; - req.get_req_data().buf = Some(buf); + let len = buf.len as uint; req.get_req_data().raw_fd = Some(self.native_handle()); let result = unsafe { uvll::fs_write(loop_.native_handle(), req.native_handle(), @@ -213,17 +161,17 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn write(&self, loop_: Loop, buf: ~[u8], offset: i64, cb: FsCallback) + pub fn write(&self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) -> int { self.write_common(loop_, buf, offset, Some(cb)) } - pub fn write_sync(&self, loop_: Loop, buf: ~[u8], offset: i64) + pub fn write_sync(&self, loop_: Loop, buf: Buf, offset: i64) -> int { self.write_common(loop_, buf, offset, None) } - fn read_common(&self, loop_: Loop, buf_ptr: Option<*c_void>, - len: uint, offset: i64, cb: Option) + fn read_common(&self, loop_: Loop, buf: Buf, + offset: i64, cb: Option) -> int { let complete_cb_ptr = match cb { Some(_) => compl_cb, @@ -232,31 +180,22 @@ impl FileDescriptor { let is_sync = cb.is_none(); let mut req = FsRequest::new(cb); req.get_req_data().raw_fd = Some(self.native_handle()); + let buf_ptr = buf.base as *c_void; let result = unsafe { - let buf_ptr = match buf_ptr { - Some(ptr) => ptr, - None => { - let buf = vec::from_elem(len, 0u8); - let buf = vec_to_uv_buf(buf); - req.get_req_data().buf = Some(buf); - buf.base as *c_void - } - }; uvll::fs_read(loop_.native_handle(), req.native_handle(), self.native_handle(), buf_ptr, - len, offset, complete_cb_ptr) as int + buf.len as uint, offset, complete_cb_ptr) as int }; if is_sync { req.cleanup_and_delete(); } result } - pub fn read(&self, loop_: Loop, buf_ptr: Option<*c_void>, - len: uint, offset: i64, cb: FsCallback) + pub fn read(&self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) -> int { - self.read_common(loop_, buf_ptr, len, offset, Some(cb)) + self.read_common(loop_, buf, offset, Some(cb)) } - pub fn read_sync(&self, loop_: Loop, buf_ptr: Option<*c_void>, len: uint, offset: i64) + pub fn read_sync(&self, loop_: Loop, buf: Buf, offset: i64) -> int { - self.read_common(loop_, buf_ptr, len, offset, None) + self.read_common(loop_, buf, offset, None) } fn close_common(self, loop_: Loop, cb: Option) -> int { @@ -316,61 +255,67 @@ impl NativeHandle for FileDescriptor { mod test { use super::*; //use rt::test::*; - use option::{Some}; - use libc::{STDOUT_FILENO, c_void}; + use libc::{STDOUT_FILENO}; use vec; use str; use unstable::run_in_bare_thread; use path::Path; - use rt::uv::{Loop, vec_to_uv_buf, vec_from_uv_buf, + use rt::uv::{Loop, Buf, slice_to_uv_buf, status_to_maybe_uv_error_with_loop}; - use option::{None}; + use libc::{O_CREAT, O_RDWR, O_RDONLY, + S_IWUSR, S_IRUSR}; //NOTE: need defs for S_**GRP|S_**OTH in libc:: ... + //S_IRGRP, S_IROTH}; fn file_test_full_simple_impl() { do run_in_bare_thread { let mut loop_ = Loop::new(); - let create_flags = map_flag(O_RDWR) | - map_flag(O_CREAT); - let read_flags = map_flag(O_RDONLY); - // 0644 - let mode = map_mode(S_IWUSR) | - map_mode(S_IRUSR) | - map_mode(S_IRGRP) | - map_mode(S_IROTH); + let create_flags = O_RDWR | O_CREAT; + let read_flags = O_RDONLY; + // 0644 BZZT! WRONG! 0600! See below. + let mode = S_IWUSR |S_IRUSR; + // these aren't defined in std::libc :( + //map_mode(S_IRGRP) | + //map_mode(S_IROTH); let path_str = "./file_full_simple.txt"; - let write_val = "hello"; - do FileDescriptor::open(loop_, Path(path_str), create_flags, mode) + let write_val = "hello".as_bytes().to_owned(); + let write_buf = slice_to_uv_buf(write_val); + let write_buf_ptr: *Buf = &write_buf; + let read_buf_len = 1028; + let read_mem = vec::from_elem(read_buf_len, 0u8); + let read_buf = slice_to_uv_buf(read_mem); + let read_buf_ptr: *Buf = &read_buf; + do FileDescriptor::open(loop_, Path(path_str), create_flags as int, mode as int) |req, uverr| { let loop_ = req.get_loop(); assert!(uverr.is_none()); let fd = FileDescriptor::from_open_req(req); - let msg: ~[u8] = write_val.as_bytes().to_owned(); let raw_fd = fd.native_handle(); - do fd.write(loop_, msg, -1) |_, uverr| { + let buf = unsafe { *write_buf_ptr }; + do fd.write(loop_, buf, -1) |_, uverr| { let fd = FileDescriptor(raw_fd); do fd.close(loop_) |req, _| { let loop_ = req.get_loop(); assert!(uverr.is_none()); - do FileDescriptor::open(loop_, Path(path_str), read_flags,0) + do FileDescriptor::open(loop_, Path(path_str), read_flags as int,0) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); - let len = 1028; let fd = FileDescriptor::from_open_req(req); let raw_fd = fd.native_handle(); - do fd.read(loop_, None, len, 0) |req, uverr| { + let read_buf = unsafe { *read_buf_ptr }; + do fd.read(loop_, read_buf, 0) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); // we know nread >=0 because uverr is none.. let nread = req.get_result() as uint; // nread == 0 would be EOF if nread > 0 { - let buf = vec_from_uv_buf( - req.get_req_data().buf.take_unwrap()) - .take_unwrap(); - let read_str = str::from_bytes( - buf.slice(0, - nread)); + let read_str = unsafe { + let read_buf = *read_buf_ptr; + str::from_bytes( + vec::from_buf( + read_buf.base, nread)) + }; assert!(read_str == ~"hello"); do FileDescriptor(raw_fd).close(loop_) |_,uverr| { assert!(uverr.is_none()); @@ -393,24 +338,25 @@ mod test { do run_in_bare_thread { // setup let mut loop_ = Loop::new(); - let create_flags = map_flag(O_RDWR) | - map_flag(O_CREAT); - let read_flags = map_flag(O_RDONLY); + let create_flags = O_RDWR | + O_CREAT; + let read_flags = O_RDONLY; // 0644 - let mode = map_mode(S_IWUSR) | - map_mode(S_IRUSR) | - map_mode(S_IRGRP) | - map_mode(S_IROTH); + let mode = S_IWUSR | + S_IRUSR; + //S_IRGRP | + //S_IROTH; let path_str = "./file_full_simple_sync.txt"; - let write_val = "hello"; + let write_val = "hello".as_bytes().to_owned(); + let write_buf = slice_to_uv_buf(write_val); // open/create - let result = FileDescriptor::open_sync(loop_, Path(path_str), create_flags, mode); + let result = FileDescriptor::open_sync(loop_, Path(path_str), + create_flags as int, mode as int); assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); let fd = FileDescriptor(result as i32); - let msg: ~[u8] = write_val.as_bytes().to_owned(); // write - let result = fd.write_sync(loop_, msg, -1); + let result = fd.write_sync(loop_, write_buf, -1); assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); // close @@ -418,25 +364,24 @@ mod test { assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); // re-open - let result = FileDescriptor::open_sync(loop_, Path(path_str), read_flags,0); + let result = FileDescriptor::open_sync(loop_, Path(path_str), + read_flags as int,0); assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); let len = 1028; let fd = FileDescriptor(result as i32); // read - let buf: ~[u8] = vec::from_elem(len, 0u8); - let buf = vec_to_uv_buf(buf); - let buf_ptr = buf.base as *c_void; - let result = fd.read_sync(loop_, Some(buf_ptr), len, 0); + let read_mem: ~[u8] = vec::from_elem(len, 0u8); + let buf = slice_to_uv_buf(read_mem); + let result = fd.read_sync(loop_, buf, 0); assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); let nread = result; // nread == 0 would be EOF.. we know it's >= zero because otherwise // the above assert would fail if nread > 0 { - let buf = vec_from_uv_buf(buf).take_unwrap(); let read_str = str::from_bytes( - buf.slice(0, nread as uint)); + read_mem.slice(0, nread as uint)); assert!(read_str == ~"hello"); // close let result = fd.close_sync(loop_); @@ -461,19 +406,18 @@ mod test { file_test_full_simple_impl_sync(); } - fn naive_print(loop_: Loop, input: ~str) { + fn naive_print(loop_: Loop, input: &str) { let stdout = FileDescriptor(STDOUT_FILENO); - let msg = input.as_bytes().to_owned(); - do stdout.write(loop_, msg, -1) |_, uverr| { - assert!(uverr.is_none()); - }; + let write_val = input.as_bytes(); + let write_buf = slice_to_uv_buf(write_val); + stdout.write_sync(loop_, write_buf, 0); } #[test] fn file_test_write_to_stdout() { do run_in_bare_thread { let mut loop_ = Loop::new(); - naive_print(loop_, ~"zanzibar!\n"); + naive_print(loop_, "zanzibar!\n"); loop_.run(); loop_.close(); }; diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 1b257b708c47a..caac418b7339b 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -643,15 +643,6 @@ pub unsafe fn fs_req_cleanup(req: *uv_fs_t) { } // data access helpers -pub unsafe fn get_O_RDONLY() -> c_int { rust_uv_get_O_RDONLY() } -pub unsafe fn get_O_WRONLY() -> c_int { rust_uv_get_O_WRONLY() } -pub unsafe fn get_O_RDWR() -> c_int { rust_uv_get_O_RDWR() } -pub unsafe fn get_O_CREAT() -> c_int { rust_uv_get_O_CREAT() } -pub unsafe fn get_O_TRUNC() -> c_int { rust_uv_get_O_TRUNC() } -pub unsafe fn get_S_IWUSR() -> c_int { rust_uv_get_S_IWUSR() } -pub unsafe fn get_S_IRUSR() -> c_int { rust_uv_get_S_IRUSR() } -pub unsafe fn get_S_IRGRP() -> c_int { rust_uv_get_S_IRGRP() } -pub unsafe fn get_S_IROTH() -> c_int { rust_uv_get_S_IROTH() } pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int { rust_uv_get_result_from_fs_req(req) } @@ -835,15 +826,6 @@ extern { fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int; fn rust_uv_fs_req_cleanup(req: *uv_fs_t); - fn rust_uv_get_O_RDONLY() -> c_int; - fn rust_uv_get_O_WRONLY() -> c_int; - fn rust_uv_get_O_RDWR() -> c_int; - fn rust_uv_get_O_CREAT() -> c_int; - fn rust_uv_get_O_TRUNC() -> c_int; - fn rust_uv_get_S_IWUSR() -> c_int; - fn rust_uv_get_S_IRUSR() -> c_int; - fn rust_uv_get_S_IRGRP() -> c_int; - fn rust_uv_get_S_IROTH() -> c_int; fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int; fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t; diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index e08b4ac21ebf9..7ee68ff53045d 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -538,42 +538,6 @@ rust_uv_fs_req_cleanup(uv_fs_t* req) { uv_fs_req_cleanup(req); } extern "C" int -rust_uv_get_O_RDONLY() { - return O_RDONLY; -} -extern "C" int -rust_uv_get_O_WRONLY() { - return O_WRONLY; -} -extern "C" int -rust_uv_get_O_RDWR() { - return O_RDWR; -} -extern "C" int -rust_uv_get_O_CREAT() { - return O_CREAT; -} -extern "C" int -rust_uv_get_O_TRUNC() { - return O_TRUNC; -} -extern "C" int -rust_uv_get_S_IWUSR() { - return S_IWUSR; -} -extern "C" int -rust_uv_get_S_IRUSR() { - return S_IRUSR; -} -extern "C" int -rust_uv_get_S_IRGRP() { - return S_IRGRP; -} -extern "C" int -rust_uv_get_S_IROTH() { - return S_IROTH; -} -extern "C" int rust_uv_get_result_from_fs_req(uv_fs_t* req) { return req->result; } diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 824a3931771e5..5100e732308f2 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -113,15 +113,6 @@ rust_uv_fs_unlink rust_uv_fs_write rust_uv_fs_read rust_uv_fs_close -rust_uv_get_O_RDONLY -rust_uv_get_O_WRONLY -rust_uv_get_O_RDWR -rust_uv_get_O_CREAT -rust_uv_get_O_TRUNC -rust_uv_get_S_IRUSR -rust_uv_get_S_IWUSR -rust_uv_get_S_IROTH -rust_uv_get_S_IRGRP rust_uv_get_result_from_fs_req rust_uv_get_loop_from_fs_req rust_uv_fs_req_cleanup From 47f0e91689403c8472dc63e58e735f42251427ab Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Mon, 19 Aug 2013 16:10:43 -0700 Subject: [PATCH 06/26] std: CRUD file io bindings in uvio, fs_open()/unlink() in IoFactory + test --- src/libstd/rt/rtio.rs | 23 ++++++ src/libstd/rt/uv/uvio.rs | 167 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index f36c96706e5d6..1095104773d1d 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -10,10 +10,12 @@ use option::*; use result::*; +use libc::c_int; use rt::io::IoError; use super::io::net::ip::{IpAddr, SocketAddr}; use rt::uv::uvio; +use path::Path; // XXX: ~object doesn't work currently so these are some placeholder // types to use instead @@ -46,11 +48,27 @@ pub trait RemoteCallback { fn fire(&mut self); } +/// Data needed to make a successful open(2) call +/// Using unix flag conventions for now, which happens to also be what's supported +/// libuv (it does translation to windows under the hood). +pub struct FileOpenConfig { + /// Path to file to be opened + path: Path, + /// Flags for file access mode (as per open(2)) + flags: int, + /// File creation mode, ignored unless O_CREAT is passed as part of flags + mode: int +} + pub trait IoFactory { fn tcp_connect(&mut self, addr: SocketAddr) -> Result<~RtioTcpStreamObject, IoError>; fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError>; fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>; fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>; + fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileDescriptor; + fn fs_open(&mut self, path: Path, flags: int, mode:int) + -> Result<~RtioFileDescriptor, IoError>; + fn fs_unlink(&mut self, path: Path) -> Result<(), IoError>; } pub trait RtioTcpListener : RtioSocket { @@ -93,3 +111,8 @@ pub trait RtioUdpSocket : RtioSocket { pub trait RtioTimer { fn sleep(&mut self, msecs: u64); } + +pub trait RtioFileDescriptor { + fn read(&mut self, buf: &mut [u8], offset: i64) -> Result; + fn write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError>; +} diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 6920e776a09e5..913b19ec38f99 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -17,6 +17,8 @@ use libc::{c_int, c_uint, c_void}; use ops::Drop; use option::*; use ptr; +use str; +use path::Path; use result::*; use rt::io::IoError; use rt::io::net::ip::{SocketAddr, IpAddr}; @@ -455,6 +457,68 @@ impl IoFactory for UvIoFactory { let home = get_handle_to_current_scheduler!(); Ok(~UvTimer::new(watcher, home)) } + + fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileDescriptor { + ~UvFileDescriptor { + loop_: Loop{handle:self.uv_loop().native_handle()}, + fd: file::FileDescriptor(fd), + close_on_drop: close_on_drop + } as ~RtioFileDescriptor + } + + fn fs_open(&mut self, path: Path, flags: int, mode: int) + -> Result<~RtioFileDescriptor, IoError> { + let loop_ = Loop {handle: self.uv_loop().native_handle()}; + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + let path_cell = Cell::new(path); + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let path = path_cell.take(); + do file::FileDescriptor::open(loop_, path, flags, mode) |req,err| { + if err.is_none() { + let res = Ok(~UvFileDescriptor { + loop_: loop_, + fd: file::FileDescriptor(req.get_result()), + close_on_drop: true} as ~RtioFileDescriptor); + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } else { + let res = Err(uv_error_to_io_error(err.unwrap())); + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + } + }; + }; + assert!(!result_cell.is_empty()); + return result_cell.take(); + } + + fn fs_unlink(&mut self, path: Path) -> Result<(), IoError> { + let loop_ = Loop {handle: self.uv_loop().native_handle()}; + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + let path_cell = Cell::new(path); + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + let path = path_cell.take(); + do file::FileDescriptor::unlink(loop_, path) |_, err| { + let res = match err { + None => Ok(()), + Some(err) => Err(uv_error_to_io_error(err)) + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; + }; + assert!(!result_cell.is_empty()); + return result_cell.take(); + } } pub struct UvTcpListener { @@ -992,6 +1056,73 @@ impl RtioTimer for UvTimer { } } +pub struct UvFileDescriptor { + loop_: Loop, + fd: file::FileDescriptor, + close_on_drop: bool +} + +impl UvFileDescriptor { +} + +impl Drop for UvFileDescriptor { + fn drop(&self) { + if self.close_on_drop { + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do self.fd.close(self.loop_) |_,_| { + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; + }; + } + } +} + +impl RtioFileDescriptor for UvFileDescriptor { + fn read(&mut self, buf: &mut [u8], offset: i64) -> Result { + let scheduler = Local::take::(); + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + let buf_ptr: *&mut [u8] = &buf; + do scheduler.deschedule_running_task_and_then |_, task| { + let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; + let task_cell = Cell::new(task); + do self.fd.read(self.loop_, buf, offset) |req, uverr| { + let res = match uverr { + None => Ok(req.get_result() as int), + Some(err) => Err(uv_error_to_io_error(err)) + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; + }; + result_cell.take() + } + fn write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { + let scheduler = Local::take::(); + let result_cell = Cell::new_empty(); + let result_cell_ptr: *Cell> = &result_cell; + let buf_ptr: *&[u8] = &buf; + do scheduler.deschedule_running_task_and_then |_, task| { + let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; + let task_cell = Cell::new(task); + do self.fd.write(self.loop_, buf, offset) |_, uverr| { + let res = match uverr { + None => Ok(()), + Some(err) => Err(uv_error_to_io_error(err)) + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; + }; + result_cell.take() + } +} + #[test] fn test_simple_io_no_connect() { do run_in_newsched_task { @@ -1498,3 +1629,39 @@ fn test_timer_sleep_simple() { } } } + +fn file_test_uvio_full_simple_impl() { + use libc::{O_CREAT, O_RDWR, O_RDONLY, + S_IWUSR, S_IRUSR}; + use str::StrSlice; // why does this have to be explicitly imported to work? + // compiler was complaining about no trait for str that + // does .as_bytes() .. + unsafe { + let io = Local::unsafe_borrow::(); + let create_flags = O_RDWR | O_CREAT; + let ro_flags = O_RDONLY; + let write_val = "hello uvio!"; + let mode = S_IWUSR | S_IRUSR; + let path = "./file_test_uvio_full.txt"; + { + let mut fd = (*io).fs_open(Path(path), create_flags as int, mode as int).unwrap(); + let write_buf = write_val.as_bytes(); + fd.write(write_buf, 0); + } + { + let mut fd = (*io).fs_open(Path(path), ro_flags as int, mode as int).unwrap(); + let mut read_vec = [0, .. 1028]; + let nread = fd.read(read_vec, 0).unwrap(); + let read_val = str::from_bytes(read_vec.slice(0, nread as uint)); + assert!(read_val == write_val.to_owned()); + } + (*io).fs_unlink(Path(path)); + } +} + +#[test] +fn file_test_uvio_full_simple() { + do run_in_newsched_task { + file_test_uvio_full_simple_impl(); + } +} From f6d897d7d97c6f75126d487da196084aaafde659 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Mon, 19 Aug 2013 21:57:47 -0700 Subject: [PATCH 07/26] std: rt::io::file::FileStream fleshed out.. needs more work.. see extended - change all uses of Path in fn args to &P - FileStream.read assumptions were wrong (libuv file io is non-positional) - the above will mean that we "own" Seek impl info .. should probably push it in UvFileDescriptor.. - needs more tests --- src/libstd/rt/io/file.rs | 109 +++++++++++++++++++++++++++++++++------ src/libstd/rt/rtio.rs | 5 +- src/libstd/rt/uv/file.rs | 40 ++++++++------ src/libstd/rt/uv/uvio.rs | 13 ++--- 4 files changed, 127 insertions(+), 40 deletions(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 9128961165900..0e972206ea747 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -12,6 +12,11 @@ use prelude::*; use super::support::PathLike; use super::{Reader, Writer, Seek}; use super::SeekStyle; +use rt::rtio::{RtioFileDescriptor, IoFactory, IoFactoryObject}; +use rt::io::{io_error, read_error, EndOfFile}; +use rt::local::Local; +use libc::{O_RDWR, O_RDONLY, O_WRONLY, S_IWUSR, S_IRUSR, + O_CREAT, O_TRUNC, O_APPEND}; /// # FIXME #7785 /// * Ugh, this is ridiculous. What is the best way to represent these options? @@ -36,29 +41,85 @@ enum FileAccess { ReadWrite } -pub struct FileStream; +pub struct FileStream { + fd: ~RtioFileDescriptor, + last_nread: int +} impl FileStream { - pub fn open(_path: &P, - _mode: FileMode, - _access: FileAccess + pub fn open(path: &P, + mode: FileMode, + access: FileAccess ) -> Option { - fail!() + let open_result = unsafe { + let io = Local::unsafe_borrow::(); + let mut flags = match mode { + Open => 0, + Create => O_CREAT, + OpenOrCreate => O_CREAT, + Append => O_APPEND, + Truncate => O_TRUNC, + CreateOrTruncate => O_TRUNC | O_CREAT + }; + flags = match access { + Read => flags | O_RDONLY, + Write => flags | O_WRONLY, + ReadWrite => flags | O_RDWR + }; + let create_mode = match mode { + Create|OpenOrCreate|CreateOrTruncate => + S_IRUSR | S_IWUSR, + _ => 0 + }; + (*io).fs_open(path, flags as int, create_mode as int) + }; + match open_result { + Ok(fd) => Some(FileStream { + fd: fd, + last_nread: -1 + }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } } } impl Reader for FileStream { - fn read(&mut self, _buf: &mut [u8]) -> Option { - fail!() + fn read(&mut self, buf: &mut [u8]) -> Option { + match self.fd.read(buf, 0) { + Ok(read) => { + self.last_nread = read; + match read { + 0 => None, + _ => Some(read as uint) + } + }, + Err(ioerr) => { + // EOF is indicated by returning None + if ioerr.kind != EndOfFile { + read_error::cond.raise(ioerr); + } + return None; + } + } } fn eof(&mut self) -> bool { - fail!() + self.last_nread == 0 } } impl Writer for FileStream { - fn write(&mut self, _v: &[u8]) { fail!() } + fn write(&mut self, buf: &[u8]) { + match self.fd.write(buf, 0) { + Ok(_) => (), + Err(ioerr) => { + io_error::cond.raise(ioerr); + } + } + } fn flush(&mut self) { fail!() } } @@ -69,11 +130,29 @@ impl Seek for FileStream { fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } } +fn file_test_smoke_test_impl() { + use rt::test::*; + do run_in_newsched_task { + let message = "it's alright. have a good time"; + let filename = &Path("rt_io_file_test.txt"); + { + let mut write_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + write_stream.write(message.as_bytes()); + } + { + use str; + let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_buf = [0, .. 1028]; + let read_str = match read_stream.read(read_buf).unwrap() { + -1|0 => fail!("shouldn't happen"), + n => str::from_bytes(read_buf.slice_to(n)) + }; + assert!(read_str == message.to_owned()); + } + } +} + #[test] -#[ignore] -fn super_simple_smoke_test_lets_go_read_some_files_and_have_a_good_time() { - let message = "it's alright. have a good time"; - let filename = &Path("test.txt"); - let mut outstream = FileStream::open(filename, Create, Read).unwrap(); - outstream.write(message.as_bytes()); +fn file_test_smoke_test() { + file_test_smoke_test_impl(); } diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 1095104773d1d..fedffa3284443 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -16,6 +16,7 @@ use rt::io::IoError; use super::io::net::ip::{IpAddr, SocketAddr}; use rt::uv::uvio; use path::Path; +use super::io::support::PathLike; // XXX: ~object doesn't work currently so these are some placeholder // types to use instead @@ -66,9 +67,9 @@ pub trait IoFactory { fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>; fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>; fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileDescriptor; - fn fs_open(&mut self, path: Path, flags: int, mode:int) + fn fs_open(&mut self, path: &P, flags: int, mode:int) -> Result<~RtioFileDescriptor, IoError>; - fn fs_unlink(&mut self, path: Path) -> Result<(), IoError>; + fn fs_unlink(&mut self, path: &P) -> Result<(), IoError>; } pub trait RtioTcpListener : RtioSocket { diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index f3f6c32516255..056250ba968e6 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -15,7 +15,7 @@ use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, status_to_maybe_uv_error_with_loop}; use rt::uv::uvll; use rt::uv::uvll::*; -use path::Path; +use super::super::io::support::PathLike; use cast::transmute; use libc::{c_int}; use option::{None, Some, Option}; @@ -97,7 +97,7 @@ impl FileDescriptor { FileDescriptor::new(req.get_result()) } - fn open_common(loop_: Loop, path: Path, flags: int, mode: int, + fn open_common(loop_: Loop, path: &P, flags: int, mode: int, cb: Option) -> int { let complete_cb_ptr = match cb { Some(_) => compl_cb, @@ -105,39 +105,44 @@ impl FileDescriptor { }; let is_sync = cb.is_none(); let req = FsRequest::new(cb); - let result = path.to_str().to_c_str().with_ref(|p| unsafe { + let result = path.path_as_str(|p| { + p.to_c_str().with_ref(|p| unsafe { uvll::fs_open(loop_.native_handle(), req.native_handle(), p, flags, mode, complete_cb_ptr) as int + }) }); if is_sync { req.cleanup_and_delete(); } result } - pub fn open(loop_: Loop, path: Path, flags: int, mode: int, + pub fn open(loop_: Loop, path: &P, flags: int, mode: int, cb: FsCallback) -> int { FileDescriptor::open_common(loop_, path, flags, mode, Some(cb)) } - pub fn open_sync(loop_: Loop, path: Path, flags: int, mode: int) -> int { + + pub fn open_sync(loop_: Loop, path: &P, flags: int, mode: int) -> int { FileDescriptor::open_common(loop_, path, flags, mode, None) } - fn unlink_common(loop_: Loop, path: Path, cb: Option) -> int { + fn unlink_common(loop_: Loop, path: &P, cb: Option) -> int { let complete_cb_ptr = match cb { Some(_) => compl_cb, None => 0 as *u8 }; let is_sync = cb.is_none(); let req = FsRequest::new(cb); - let result = path.to_str().to_c_str().with_ref(|p| unsafe { - uvll::fs_unlink(loop_.native_handle(), - req.native_handle(), p, complete_cb_ptr) as int + let result = path.path_as_str(|p| { + p.to_c_str().with_ref(|p| unsafe { + uvll::fs_unlink(loop_.native_handle(), + req.native_handle(), p, complete_cb_ptr) as int + }) }); if is_sync { req.cleanup_and_delete(); } result } - pub fn unlink(loop_: Loop, path: Path, cb: FsCallback) -> int { + pub fn unlink(loop_: Loop, path: &P, cb: FsCallback) -> int { FileDescriptor::unlink_common(loop_, path, Some(cb)) } - pub fn unlink_sync(loop_: Loop, path: Path) -> int { + pub fn unlink_sync(loop_: Loop, path: &P) -> int { FileDescriptor::unlink_common(loop_, path, None) } @@ -284,7 +289,8 @@ mod test { let read_mem = vec::from_elem(read_buf_len, 0u8); let read_buf = slice_to_uv_buf(read_mem); let read_buf_ptr: *Buf = &read_buf; - do FileDescriptor::open(loop_, Path(path_str), create_flags as int, mode as int) + let p = Path(path_str); + do FileDescriptor::open(loop_, &p, create_flags as int, mode as int) |req, uverr| { let loop_ = req.get_loop(); assert!(uverr.is_none()); @@ -296,7 +302,7 @@ mod test { do fd.close(loop_) |req, _| { let loop_ = req.get_loop(); assert!(uverr.is_none()); - do FileDescriptor::open(loop_, Path(path_str), read_flags as int,0) + do FileDescriptor::open(loop_, &Path(path_str), read_flags as int,0) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); @@ -319,7 +325,7 @@ mod test { assert!(read_str == ~"hello"); do FileDescriptor(raw_fd).close(loop_) |_,uverr| { assert!(uverr.is_none()); - do FileDescriptor::unlink(loop_, Path(path_str)) + do FileDescriptor::unlink(loop_, &Path(path_str)) |_,uverr| { assert!(uverr.is_none()); }; @@ -350,7 +356,7 @@ mod test { let write_val = "hello".as_bytes().to_owned(); let write_buf = slice_to_uv_buf(write_val); // open/create - let result = FileDescriptor::open_sync(loop_, Path(path_str), + let result = FileDescriptor::open_sync(loop_, &Path(path_str), create_flags as int, mode as int); assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); @@ -364,7 +370,7 @@ mod test { assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); // re-open - let result = FileDescriptor::open_sync(loop_, Path(path_str), + let result = FileDescriptor::open_sync(loop_, &Path(path_str), read_flags as int,0); assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); @@ -388,7 +394,7 @@ mod test { assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); // unlink - let result = FileDescriptor::unlink_sync(loop_, Path(path_str)); + let result = FileDescriptor::unlink_sync(loop_, &Path(path_str)); assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); } else { fail!("nread was 0.. wudn't expectin' that."); } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 913b19ec38f99..2acf2cccfeae9 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -18,7 +18,6 @@ use ops::Drop; use option::*; use ptr; use str; -use path::Path; use result::*; use rt::io::IoError; use rt::io::net::ip::{SocketAddr, IpAddr}; @@ -31,6 +30,7 @@ use rt::uv::*; use rt::uv::idle::IdleWatcher; use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; use unstable::sync::Exclusive; +use super::super::io::support::PathLike; #[cfg(test)] use container::Container; #[cfg(test)] use unstable::run_in_bare_thread; @@ -466,7 +466,7 @@ impl IoFactory for UvIoFactory { } as ~RtioFileDescriptor } - fn fs_open(&mut self, path: Path, flags: int, mode: int) + fn fs_open(&mut self, path: &P, flags: int, mode: int) -> Result<~RtioFileDescriptor, IoError> { let loop_ = Loop {handle: self.uv_loop().native_handle()}; let result_cell = Cell::new_empty(); @@ -497,7 +497,7 @@ impl IoFactory for UvIoFactory { return result_cell.take(); } - fn fs_unlink(&mut self, path: Path) -> Result<(), IoError> { + fn fs_unlink(&mut self, path: &P) -> Result<(), IoError> { let loop_ = Loop {handle: self.uv_loop().native_handle()}; let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -1636,6 +1636,7 @@ fn file_test_uvio_full_simple_impl() { use str::StrSlice; // why does this have to be explicitly imported to work? // compiler was complaining about no trait for str that // does .as_bytes() .. + use path::Path; unsafe { let io = Local::unsafe_borrow::(); let create_flags = O_RDWR | O_CREAT; @@ -1644,18 +1645,18 @@ fn file_test_uvio_full_simple_impl() { let mode = S_IWUSR | S_IRUSR; let path = "./file_test_uvio_full.txt"; { - let mut fd = (*io).fs_open(Path(path), create_flags as int, mode as int).unwrap(); + let mut fd = (*io).fs_open(&Path(path), create_flags as int, mode as int).unwrap(); let write_buf = write_val.as_bytes(); fd.write(write_buf, 0); } { - let mut fd = (*io).fs_open(Path(path), ro_flags as int, mode as int).unwrap(); + let mut fd = (*io).fs_open(&Path(path), ro_flags as int, mode as int).unwrap(); let mut read_vec = [0, .. 1028]; let nread = fd.read(read_vec, 0).unwrap(); let read_val = str::from_bytes(read_vec.slice(0, nread as uint)); assert!(read_val == write_val.to_owned()); } - (*io).fs_unlink(Path(path)); + (*io).fs_unlink(&Path(path)); } } From 4015b4a9b4ec90b5b5d6542474e396181c7df8b5 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 20 Aug 2013 00:34:50 -0700 Subject: [PATCH 08/26] std: add FileStream::unlink + more tests --- src/libstd/rt/io/file.rs | 54 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 0e972206ea747..6973e117131cb 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -15,6 +15,7 @@ use super::SeekStyle; use rt::rtio::{RtioFileDescriptor, IoFactory, IoFactoryObject}; use rt::io::{io_error, read_error, EndOfFile}; use rt::local::Local; +use rt::test::*; use libc::{O_RDWR, O_RDONLY, O_WRONLY, S_IWUSR, S_IRUSR, O_CREAT, O_TRUNC, O_APPEND}; @@ -84,6 +85,18 @@ impl FileStream { } } } + fn unlink(path: &P) { + let unlink_result = unsafe { + let io = Local::unsafe_borrow::(); + (*io).fs_unlink(path) + }; + match unlink_result { + Ok(_) => (), + Err(ioerr) => { + io_error::cond.raise(ioerr); + } + } + } } impl Reader for FileStream { @@ -131,10 +144,9 @@ impl Seek for FileStream { } fn file_test_smoke_test_impl() { - use rt::test::*; do run_in_newsched_task { let message = "it's alright. have a good time"; - let filename = &Path("rt_io_file_test.txt"); + let filename = &Path("./rt_io_file_test.txt"); { let mut write_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); write_stream.write(message.as_bytes()); @@ -149,6 +161,7 @@ fn file_test_smoke_test_impl() { }; assert!(read_str == message.to_owned()); } + FileStream::unlink(filename); } } @@ -156,3 +169,40 @@ fn file_test_smoke_test_impl() { fn file_test_smoke_test() { file_test_smoke_test_impl(); } + +fn file_test_invalid_path_opened_without_create_should_raise_condition_impl() { + do run_in_newsched_task { + let filename = &Path("./file_that_does_not_exist.txt"); + let mut called = false; + do io_error::cond.trap(|_| { + called = true; + }).inside { + let result = FileStream::open(filename, Open, Read); + assert!(result.is_none()); + } + assert!(called); + } +} +#[test] +fn file_test_invalid_path_opened_without_create_should_raise_condition() { + file_test_invalid_path_opened_without_create_should_raise_condition_impl(); +} + +fn file_test_unlinking_invalid_path_should_raise_condition_impl() { + use io; + do run_in_newsched_task { + let filename = &Path("./another_file_that_does_not_exist.txt"); + let mut called = false; + do io_error::cond.trap(|e| { + io::println(fmt!("condition kind: %?", e.kind)); + called = true; + }).inside { + FileStream::unlink(filename); + } + assert!(called); + } +} +#[test] +fn file_test_unlinking_invalid_path_should_raise_condition() { + file_test_unlinking_invalid_path_should_raise_condition_impl(); +} From 48d67610285b423e806e0c44be43d01d5c1a7dbc Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 20 Aug 2013 15:35:40 -0700 Subject: [PATCH 09/26] std: adding #[fixed_stack_segment] as needed in new uvll calls --- src/libstd/rt/uv/uvll.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index caac418b7339b..1e189e9088550 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -619,34 +619,50 @@ pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint { pub unsafe fn fs_open(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags: int, mode: int, cb: *u8) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_fs_open(loop_ptr, req, path, flags as c_int, mode as c_int, cb) } pub unsafe fn fs_unlink(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, cb: *u8) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_fs_unlink(loop_ptr, req, path, cb) } pub unsafe fn fs_write(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void, len: uint, offset: i64, cb: *u8) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_fs_write(loop_ptr, req, fd, buf, len as c_uint, offset, cb) } pub unsafe fn fs_read(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, buf: *c_void, len: uint, offset: i64, cb: *u8) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_fs_read(loop_ptr, req, fd, buf, len as c_uint, offset, cb) } pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int, cb: *u8) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_fs_close(loop_ptr, req, fd, cb) } pub unsafe fn fs_req_cleanup(req: *uv_fs_t) { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_fs_req_cleanup(req); } // data access helpers pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_get_result_from_fs_req(req) } pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t { + #[fixed_stack_segment]; #[inline(never)]; + rust_uv_get_loop_from_fs_req(req) } pub unsafe fn get_loop_for_uv_handle(handle: *T) -> *c_void { From 05c8cc70c90032d578606e811bbb1266cd8d2fcd Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 20 Aug 2013 15:38:41 -0700 Subject: [PATCH 10/26] std: rework file io.. support [p]read,[p]write, impl seek/tell + more tests --- src/libstd/rt/io/file.rs | 140 ++++++++++++++++++++++++++++++++++----- src/libstd/rt/io/mod.rs | 1 + src/libstd/rt/rtio.rs | 15 +++-- src/libstd/rt/uv/uvio.rs | 111 ++++++++++++++++++++++--------- 4 files changed, 214 insertions(+), 53 deletions(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 6973e117131cb..edc2953a4dd9c 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -11,16 +11,15 @@ use prelude::*; use super::support::PathLike; use super::{Reader, Writer, Seek}; -use super::SeekStyle; -use rt::rtio::{RtioFileDescriptor, IoFactory, IoFactoryObject}; +use super::{SeekSet, SeekStyle}; +use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject}; use rt::io::{io_error, read_error, EndOfFile}; use rt::local::Local; use rt::test::*; use libc::{O_RDWR, O_RDONLY, O_WRONLY, S_IWUSR, S_IRUSR, O_CREAT, O_TRUNC, O_APPEND}; -/// # FIXME #7785 -/// * Ugh, this is ridiculous. What is the best way to represent these options? +/// Instructions on how to open a file and return a `FileStream`. enum FileMode { /// Opens an existing file. IoError if file does not exist. Open, @@ -36,15 +35,29 @@ enum FileMode { CreateOrTruncate, } +/// How should the file be opened? `FileStream`s opened with `Read` will +/// raise an `io_error` condition if written to. enum FileAccess { Read, Write, ReadWrite } +/// Abstraction representing *positional* access to a file. In this case, +/// *positional* refers to it keeping an encounter *cursor* of where in the +/// file a subsequent `read` or `write` will begin from. Users of a `FileStream` +/// can `seek` to move the cursor to a given location *within the bounds of the +/// file* and can ask to have the `FileStream` `tell` them the location, in +/// bytes, of the cursor. +/// +/// This abstraction is roughly modeled on the access workflow as represented +/// by `open(2)`, `read(2)`, `write(2)` and friends. +/// +/// The `open` and `unlink` static methods are provided to manage creation/removal +/// of files. All other methods operatin on an instance of `FileStream`. pub struct FileStream { - fd: ~RtioFileDescriptor, - last_nread: int + fd: ~RtioFileStream, + last_nread: int, } impl FileStream { @@ -101,7 +114,7 @@ impl FileStream { impl Reader for FileStream { fn read(&mut self, buf: &mut [u8]) -> Option { - match self.fd.read(buf, 0) { + match self.fd.read(buf) { Ok(read) => { self.last_nread = read; match read { @@ -126,7 +139,7 @@ impl Reader for FileStream { impl Writer for FileStream { fn write(&mut self, buf: &[u8]) { - match self.fd.write(buf, 0) { + match self.fd.write(buf) { Ok(_) => (), Err(ioerr) => { io_error::cond.raise(ioerr); @@ -134,13 +147,46 @@ impl Writer for FileStream { } } - fn flush(&mut self) { fail!() } + fn flush(&mut self) { + match self.fd.flush() { + Ok(_) => (), + Err(ioerr) => { + read_error::cond.raise(ioerr); + } + } + } } impl Seek for FileStream { - fn tell(&self) -> u64 { fail!() } + fn tell(&self) -> u64 { + let res = self.fd.tell(); + match res { + Ok(cursor) => cursor, + Err(ioerr) => { + read_error::cond.raise(ioerr); + return -1; + } + } + } - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } + fn seek(&mut self, pos: i64, style: SeekStyle) { + use libc::{SEEK_SET, SEEK_CUR, SEEK_END}; + let whence = match style { + SeekSet => SEEK_SET, + SeekCur => SEEK_CUR, + SeekEnd => SEEK_END + } as i64; + match self.fd.seek(pos, whence) { + Ok(_) => { + // successful seek resets EOF indocator + self.last_nread = -1; + () + }, + Err(ioerr) => { + read_error::cond.raise(ioerr); + } + } + } } fn file_test_smoke_test_impl() { @@ -166,7 +212,7 @@ fn file_test_smoke_test_impl() { } #[test] -fn file_test_smoke_test() { +fn file_test_io_smoke_test() { file_test_smoke_test_impl(); } @@ -184,17 +230,15 @@ fn file_test_invalid_path_opened_without_create_should_raise_condition_impl() { } } #[test] -fn file_test_invalid_path_opened_without_create_should_raise_condition() { +fn file_test_io_invalid_path_opened_without_create_should_raise_condition() { file_test_invalid_path_opened_without_create_should_raise_condition_impl(); } fn file_test_unlinking_invalid_path_should_raise_condition_impl() { - use io; do run_in_newsched_task { let filename = &Path("./another_file_that_does_not_exist.txt"); let mut called = false; do io_error::cond.trap(|e| { - io::println(fmt!("condition kind: %?", e.kind)); called = true; }).inside { FileStream::unlink(filename); @@ -203,6 +247,70 @@ fn file_test_unlinking_invalid_path_should_raise_condition_impl() { } } #[test] -fn file_test_unlinking_invalid_path_should_raise_condition() { +fn file_test_iounlinking_invalid_path_should_raise_condition() { file_test_unlinking_invalid_path_should_raise_condition_impl(); } + +fn file_test_io_non_positional_read_impl() { + do run_in_newsched_task { + use str; + let message = "ten-four"; + let mut read_mem = [0, .. 8]; + let filename = &Path("./rt_io_file_test_positional.txt"); + { + let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + rw_stream.write(message.as_bytes()); + } + { + let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + { + let read_buf = read_mem.mut_slice(0, 4); + read_stream.read(read_buf); + } + { + let read_buf = read_mem.mut_slice(4, 8); + read_stream.read(read_buf); + } + } + FileStream::unlink(filename); + let read_str = str::from_bytes(read_mem); + assert!(read_str == message.to_owned()); + } +} + +#[test] +fn file_test_io_non_positional_read() { + file_test_io_non_positional_read_impl(); +} + +fn file_test_io_seeking_impl() { + do run_in_newsched_task { + use str; + let message = "ten-four"; + let mut read_mem = [0, .. 4]; + let set_cursor = 4 as u64; + let mut tell_pos_pre_read; + let mut tell_pos_post_read; + let filename = &Path("./rt_io_file_test_seeking.txt"); + { + let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + rw_stream.write(message.as_bytes()); + } + { + let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + read_stream.seek(set_cursor as i64, SeekSet); + tell_pos_pre_read = read_stream.tell(); + read_stream.read(read_mem); + tell_pos_post_read = read_stream.tell(); + } + FileStream::unlink(filename); + let read_str = str::from_bytes(read_mem); + assert!(read_str == message.slice(4, 8).to_owned()); + assert!(tell_pos_pre_read == set_cursor); + assert!(tell_pos_post_read == message.len() as u64); + } +} +#[test] +fn file_test_io_seek_and_tell_smoke_test() { + file_test_io_seeking_impl(); +} diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 8b18fbcfa45d8..23b8017bc512c 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -461,6 +461,7 @@ pub enum SeekStyle { /// # XXX /// * Are `u64` and `i64` the right choices? pub trait Seek { + /// Return position of file cursor in the stream fn tell(&self) -> u64; /// Seek to an offset in a stream diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index fedffa3284443..3a14f679fa767 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -66,9 +66,9 @@ pub trait IoFactory { fn tcp_bind(&mut self, addr: SocketAddr) -> Result<~RtioTcpListenerObject, IoError>; fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>; fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>; - fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileDescriptor; + fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream; fn fs_open(&mut self, path: &P, flags: int, mode:int) - -> Result<~RtioFileDescriptor, IoError>; + -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &P) -> Result<(), IoError>; } @@ -113,7 +113,12 @@ pub trait RtioTimer { fn sleep(&mut self, msecs: u64); } -pub trait RtioFileDescriptor { - fn read(&mut self, buf: &mut [u8], offset: i64) -> Result; - fn write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError>; +pub trait RtioFileStream { + fn read(&mut self, buf: &mut [u8]) -> Result; + fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; + fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result; + fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError>; + fn seek(&mut self, pos: i64, whence: i64) -> Result<(), IoError>; + fn tell(&self) -> Result; + fn flush(&mut self) -> Result<(), IoError>; } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 2acf2cccfeae9..2a62c782d0ba1 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -31,6 +31,7 @@ use rt::uv::idle::IdleWatcher; use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; use unstable::sync::Exclusive; use super::super::io::support::PathLike; +use libc::{lseek, c_long, SEEK_CUR}; #[cfg(test)] use container::Container; #[cfg(test)] use unstable::run_in_bare_thread; @@ -458,19 +459,20 @@ impl IoFactory for UvIoFactory { Ok(~UvTimer::new(watcher, home)) } - fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileDescriptor { - ~UvFileDescriptor { + fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream { + ~UvFileStream { loop_: Loop{handle:self.uv_loop().native_handle()}, fd: file::FileDescriptor(fd), - close_on_drop: close_on_drop - } as ~RtioFileDescriptor + close_on_drop: close_on_drop, + } as ~RtioFileStream } fn fs_open(&mut self, path: &P, flags: int, mode: int) - -> Result<~RtioFileDescriptor, IoError> { + -> Result<~RtioFileStream, IoError> { let loop_ = Loop {handle: self.uv_loop().native_handle()}; let result_cell = Cell::new_empty(); - let result_cell_ptr: *Cell> = &result_cell; + let result_cell_ptr: *Cell> = &result_cell; let path_cell = Cell::new(path); let scheduler = Local::take::(); do scheduler.deschedule_running_task_and_then |_, task| { @@ -478,10 +480,10 @@ impl IoFactory for UvIoFactory { let path = path_cell.take(); do file::FileDescriptor::open(loop_, path, flags, mode) |req,err| { if err.is_none() { - let res = Ok(~UvFileDescriptor { + let res = Ok(~UvFileStream { loop_: loop_, fd: file::FileDescriptor(req.get_result()), - close_on_drop: true} as ~RtioFileDescriptor); + close_on_drop: true} as ~RtioFileStream); unsafe { (*result_cell_ptr).put_back(res); } let scheduler = Local::take::(); scheduler.resume_blocked_task_immediately(task_cell.take()); @@ -1056,32 +1058,14 @@ impl RtioTimer for UvTimer { } } -pub struct UvFileDescriptor { +pub struct UvFileStream { loop_: Loop, fd: file::FileDescriptor, close_on_drop: bool } -impl UvFileDescriptor { -} - -impl Drop for UvFileDescriptor { - fn drop(&self) { - if self.close_on_drop { - let scheduler = Local::take::(); - do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell::new(task); - do self.fd.close(self.loop_) |_,_| { - let scheduler = Local::take::(); - scheduler.resume_blocked_task_immediately(task_cell.take()); - }; - }; - } - } -} - -impl RtioFileDescriptor for UvFileDescriptor { - fn read(&mut self, buf: &mut [u8], offset: i64) -> Result { +impl UvFileStream { + fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result { let scheduler = Local::take::(); let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -1101,7 +1085,7 @@ impl RtioFileDescriptor for UvFileDescriptor { }; result_cell.take() } - fn write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { + fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { let scheduler = Local::take::(); let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -1123,6 +1107,69 @@ impl RtioFileDescriptor for UvFileDescriptor { } } +impl Drop for UvFileStream { + fn drop(&self) { + if self.close_on_drop { + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do self.fd.close(self.loop_) |_,_| { + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; + }; + } + } +} + +impl RtioFileStream for UvFileStream { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.base_read(buf, -1) + } + fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { + self.base_write(buf, -1) + } + fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result { + self.base_read(buf, offset as i64) + } + fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> { + self.base_write(buf, offset as i64) + } + fn seek(&mut self, pos: i64, whence: i64) -> Result<(), IoError> { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + match lseek((*self.fd), pos as c_long, whence as c_int) { + -1 => { + Err(IoError { + kind: OtherIoError, + desc: "Failed to lseek.", + detail: None + }) + }, + _ => Ok(()) + } + } + } + fn tell(&self) -> Result { + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + match lseek((*self.fd), 0, SEEK_CUR) { + -1 => { + Err(IoError { + kind: OtherIoError, + desc: "Failed to lseek, needed to tell().", + detail: None + }) + }, + n=> Ok(n as u64) + } + } + } + fn flush(&mut self) -> Result<(), IoError> { + Ok(()) + } +} + #[test] fn test_simple_io_no_connect() { do run_in_newsched_task { @@ -1647,12 +1694,12 @@ fn file_test_uvio_full_simple_impl() { { let mut fd = (*io).fs_open(&Path(path), create_flags as int, mode as int).unwrap(); let write_buf = write_val.as_bytes(); - fd.write(write_buf, 0); + fd.write(write_buf); } { let mut fd = (*io).fs_open(&Path(path), ro_flags as int, mode as int).unwrap(); let mut read_vec = [0, .. 1028]; - let nread = fd.read(read_vec, 0).unwrap(); + let nread = fd.read(read_vec).unwrap(); let read_val = str::from_bytes(read_vec.slice(0, nread as uint)); assert!(read_val == write_val.to_owned()); } From 0e9964189db9feb5bd1f35a2690954008d95cdb0 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 20 Aug 2013 17:54:37 -0700 Subject: [PATCH 11/26] std: lint appeasement for unused param in condition handler --- src/libstd/rt/io/file.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index edc2953a4dd9c..23860ca885aca 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -238,7 +238,7 @@ fn file_test_unlinking_invalid_path_should_raise_condition_impl() { do run_in_newsched_task { let filename = &Path("./another_file_that_does_not_exist.txt"); let mut called = false; - do io_error::cond.trap(|e| { + do io_error::cond.trap(|_| { called = true; }).inside { FileStream::unlink(filename); From a7ee85b50b8c4b58dfb8640692d3b63f8b604b28 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Tue, 20 Aug 2013 22:00:49 -0700 Subject: [PATCH 12/26] std: stripping unneeded fcntl.h include from rust_uv.cpp --- src/rt/rust_uv.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 7ee68ff53045d..43e6b97bc1861 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -13,7 +13,6 @@ #include #endif -#include #include "uv.h" #include "rust_globals.h" From c3a819b01c4993585ea38c9fbb5dadc6c59bbe05 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 21 Aug 2013 10:29:51 -0700 Subject: [PATCH 13/26] std: writing to stdout only works when using -1 offset.. --- src/libstd/rt/uv/file.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 056250ba968e6..15fecc19884aa 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -416,7 +416,7 @@ mod test { let stdout = FileDescriptor(STDOUT_FILENO); let write_val = input.as_bytes(); let write_buf = slice_to_uv_buf(write_val); - stdout.write_sync(loop_, write_buf, 0); + stdout.write_sync(loop_, write_buf, -1); } #[test] From 10ff5355b3668cb14ffde844abd49457a61c87cc Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 21 Aug 2013 10:31:51 -0700 Subject: [PATCH 14/26] std: UvFileStream implements HomingIO + .home_for_io() wrapper usage --- src/libstd/rt/uv/uvio.rs | 99 ++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 2a62c782d0ba1..4dfeb3fccdbd4 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -460,11 +460,10 @@ impl IoFactory for UvIoFactory { } fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream { - ~UvFileStream { - loop_: Loop{handle:self.uv_loop().native_handle()}, - fd: file::FileDescriptor(fd), - close_on_drop: close_on_drop, - } as ~RtioFileStream + let loop_ = Loop {handle: self.uv_loop().native_handle()}; + let fd = file::FileDescriptor(fd); + let home = get_handle_to_current_scheduler!(); + ~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream } fn fs_open(&mut self, path: &P, flags: int, mode: int) @@ -480,10 +479,11 @@ impl IoFactory for UvIoFactory { let path = path_cell.take(); do file::FileDescriptor::open(loop_, path, flags, mode) |req,err| { if err.is_none() { - let res = Ok(~UvFileStream { - loop_: loop_, - fd: file::FileDescriptor(req.get_result()), - close_on_drop: true} as ~RtioFileStream); + let home = get_handle_to_current_scheduler!(); + let fd = file::FileDescriptor(req.get_result()); + let fs = ~UvFileStream::new( + loop_, fd, true, home) as ~RtioFileStream; + let res = Ok(fs); unsafe { (*result_cell_ptr).put_back(res); } let scheduler = Local::take::(); scheduler.resume_blocked_task_immediately(task_cell.take()); @@ -1061,46 +1061,64 @@ impl RtioTimer for UvTimer { pub struct UvFileStream { loop_: Loop, fd: file::FileDescriptor, - close_on_drop: bool + close_on_drop: bool, + home: SchedHandle +} + +impl HomingIO for UvFileStream { + fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home } } impl UvFileStream { + fn new(loop_: Loop, fd: file::FileDescriptor, close_on_drop: bool, + home: SchedHandle) -> UvFileStream { + UvFileStream { + loop_: loop_, + fd: fd, + close_on_drop: close_on_drop, + home: home + } + } fn base_read(&mut self, buf: &mut [u8], offset: i64) -> Result { - let scheduler = Local::take::(); let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; let buf_ptr: *&mut [u8] = &buf; - do scheduler.deschedule_running_task_and_then |_, task| { - let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; - let task_cell = Cell::new(task); - do self.fd.read(self.loop_, buf, offset) |req, uverr| { - let res = match uverr { - None => Ok(req.get_result() as int), - Some(err) => Err(uv_error_to_io_error(err)) + do self.home_for_io |self_| { + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |_, task| { + let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; + let task_cell = Cell::new(task); + do self_.fd.read(self.loop_, buf, offset) |req, uverr| { + let res = match uverr { + None => Ok(req.get_result() as int), + Some(err) => Err(uv_error_to_io_error(err)) + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); }; - unsafe { (*result_cell_ptr).put_back(res); } - let scheduler = Local::take::(); - scheduler.resume_blocked_task_immediately(task_cell.take()); }; }; result_cell.take() } fn base_write(&mut self, buf: &[u8], offset: i64) -> Result<(), IoError> { - let scheduler = Local::take::(); let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; let buf_ptr: *&[u8] = &buf; - do scheduler.deschedule_running_task_and_then |_, task| { - let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; - let task_cell = Cell::new(task); - do self.fd.write(self.loop_, buf, offset) |_, uverr| { - let res = match uverr { - None => Ok(()), - Some(err) => Err(uv_error_to_io_error(err)) + do self.home_for_io |self_| { + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |_, task| { + let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; + let task_cell = Cell::new(task); + do self_.fd.write(self.loop_, buf, offset) |_, uverr| { + let res = match uverr { + None => Ok(()), + Some(err) => Err(uv_error_to_io_error(err)) + }; + unsafe { (*result_cell_ptr).put_back(res); } + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); }; - unsafe { (*result_cell_ptr).put_back(res); } - let scheduler = Local::take::(); - scheduler.resume_blocked_task_immediately(task_cell.take()); }; }; result_cell.take() @@ -1109,15 +1127,18 @@ impl UvFileStream { impl Drop for UvFileStream { fn drop(&self) { + let self_ = unsafe { transmute::<&UvFileStream, &mut UvFileStream>(self) }; if self.close_on_drop { - let scheduler = Local::take::(); - do scheduler.deschedule_running_task_and_then |_, task| { - let task_cell = Cell::new(task); - do self.fd.close(self.loop_) |_,_| { - let scheduler = Local::take::(); - scheduler.resume_blocked_task_immediately(task_cell.take()); + do self_.home_for_io |self_| { + let scheduler = Local::take::(); + do scheduler.deschedule_running_task_and_then |_, task| { + let task_cell = Cell::new(task); + do self_.fd.close(self.loop_) |_,_| { + let scheduler = Local::take::(); + scheduler.resume_blocked_task_immediately(task_cell.take()); + }; }; - }; + } } } } From c0fba3c4acc52dba67461e485a3798cfa236761b Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 21 Aug 2013 15:13:01 -0700 Subject: [PATCH 15/26] rt: re-adding lines erroneous stripped out in merge conflict --- src/rt/rust_uv.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 43e6b97bc1861..f90931dbea922 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -13,12 +13,21 @@ #include #endif +#ifndef __WIN32__ +// for signal +#include +#endif + #include "uv.h" #include "rust_globals.h" extern "C" void* rust_uv_loop_new() { +// XXX libuv doesn't always ignore SIGPIPE even though we don't need it. +#ifndef __WIN32__ + signal(SIGPIPE, SIG_IGN); +#endif return (void*)uv_loop_new(); } From 320ccbeb53b711282be6a11623df45c789925059 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 21 Aug 2013 15:13:20 -0700 Subject: [PATCH 16/26] std: naive stdio print test in uvio --- src/libstd/rt/uv/uvio.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 4dfeb3fccdbd4..8d76c5e87270c 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -1734,3 +1734,23 @@ fn file_test_uvio_full_simple() { file_test_uvio_full_simple_impl(); } } + +fn uvio_naive_print(input: &str) { + use str::StrSlice; + unsafe { + use libc::{STDOUT_FILENO}; + let io = Local::unsafe_borrow::(); + { + let mut fd = (*io).fs_from_raw_fd(STDOUT_FILENO, false); + let write_buf = input.as_bytes(); + fd.write(write_buf); + } + } +} + +#[test] +fn file_test_uvio_write_to_stdout() { + do run_in_newsched_task { + uvio_naive_print("jubilation\n"); + } +} From ece709f172d180471d59a17bb92aa0c3f3ca25d7 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 21 Aug 2013 21:22:53 -0700 Subject: [PATCH 17/26] std: more seek tests --- src/libstd/rt/io/file.rs | 72 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 23860ca885aca..b7a923d94c744 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -11,7 +11,7 @@ use prelude::*; use super::support::PathLike; use super::{Reader, Writer, Seek}; -use super::{SeekSet, SeekStyle}; +use super::{SeekSet, SeekCur, SeekEnd, SeekStyle}; use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject}; use rt::io::{io_error, read_error, EndOfFile}; use rt::local::Local; @@ -314,3 +314,73 @@ fn file_test_io_seeking_impl() { fn file_test_io_seek_and_tell_smoke_test() { file_test_io_seeking_impl(); } + +fn file_test_io_seek_and_write_impl() { + use io; + do run_in_newsched_task { + use str; + let initial_msg = "food-is-yummy"; + let overwrite_msg = "-the-bar!!"; + let final_msg = "foo-the-bar!!"; + let seek_idx = 3; + let mut read_mem = [0, .. 13]; + let filename = &Path("./rt_io_file_test_seek_and_write.txt"); + { + let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + rw_stream.write(initial_msg.as_bytes()); + rw_stream.seek(seek_idx as i64, SeekSet); + rw_stream.write(overwrite_msg.as_bytes()); + } + { + let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + read_stream.read(read_mem); + } + FileStream::unlink(filename); + let read_str = str::from_bytes(read_mem); + io::println(fmt!("read_str: '%?' final_msg: '%?'", read_str, final_msg)); + assert!(read_str == final_msg.to_owned()); + } +} +#[test] +fn file_test_io_seek_and_write() { + file_test_io_seek_and_write_impl(); +} + +fn file_test_io_seek_shakedown_impl() { + do run_in_newsched_task { + use str; // 01234567890123 + let initial_msg = "qwer-asdf-zxcv"; + let chunk_one = "qwer"; + let chunk_two = "asdf"; + let chunk_three = "zxcv"; + let mut read_mem = [0, .. 4]; + let filename = &Path("./rt_io_file_test_seek_shakedown.txt"); + { + let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + rw_stream.write(initial_msg.as_bytes()); + } + { + let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + + read_stream.seek(-4, SeekEnd); + read_stream.read(read_mem); + let read_str = str::from_bytes(read_mem); + assert!(read_str == chunk_three.to_owned()); + + read_stream.seek(-9, SeekCur); + read_stream.read(read_mem); + let read_str = str::from_bytes(read_mem); + assert!(read_str == chunk_two.to_owned()); + + read_stream.seek(0, SeekSet); + read_stream.read(read_mem); + let read_str = str::from_bytes(read_mem); + assert!(read_str == chunk_one.to_owned()); + } + FileStream::unlink(filename); + } +} +#[test] +fn file_test_io_seek_shakedown() { + file_test_io_seek_shakedown_impl(); +} From 13eb259a091c373393d996596178f145579c9d7e Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 21 Aug 2013 21:23:16 -0700 Subject: [PATCH 18/26] change FileDescriptor instance methods to use &mut self --- src/libstd/rt/uv/file.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 15fecc19884aa..f88731ca63579 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -147,7 +147,7 @@ impl FileDescriptor { } // as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write - fn write_common(&self, loop_: Loop, buf: Buf, offset: i64, cb: Option) + fn write_common(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: Option) -> int { let complete_cb_ptr = match cb { Some(_) => compl_cb, @@ -166,16 +166,16 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn write(&self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) + pub fn write(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) -> int { self.write_common(loop_, buf, offset, Some(cb)) } - pub fn write_sync(&self, loop_: Loop, buf: Buf, offset: i64) + pub fn write_sync(&mut self, loop_: Loop, buf: Buf, offset: i64) -> int { self.write_common(loop_, buf, offset, None) } - fn read_common(&self, loop_: Loop, buf: Buf, + fn read_common(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: Option) -> int { let complete_cb_ptr = match cb { @@ -194,11 +194,11 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn read(&self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) + pub fn read(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) -> int { self.read_common(loop_, buf, offset, Some(cb)) } - pub fn read_sync(&self, loop_: Loop, buf: Buf, offset: i64) + pub fn read_sync(&mut self, loop_: Loop, buf: Buf, offset: i64) -> int { self.read_common(loop_, buf, offset, None) } @@ -294,7 +294,7 @@ mod test { |req, uverr| { let loop_ = req.get_loop(); assert!(uverr.is_none()); - let fd = FileDescriptor::from_open_req(req); + let mut fd = FileDescriptor::from_open_req(req); let raw_fd = fd.native_handle(); let buf = unsafe { *write_buf_ptr }; do fd.write(loop_, buf, -1) |_, uverr| { @@ -306,7 +306,7 @@ mod test { |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); - let fd = FileDescriptor::from_open_req(req); + let mut fd = FileDescriptor::from_open_req(req); let raw_fd = fd.native_handle(); let read_buf = unsafe { *read_buf_ptr }; do fd.read(loop_, read_buf, 0) |req, uverr| { @@ -360,7 +360,7 @@ mod test { create_flags as int, mode as int); assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); - let fd = FileDescriptor(result as i32); + let mut fd = FileDescriptor(result as i32); // write let result = fd.write_sync(loop_, write_buf, -1); assert!(status_to_maybe_uv_error_with_loop( @@ -375,7 +375,7 @@ mod test { assert!(status_to_maybe_uv_error_with_loop( loop_.native_handle(), result as i32).is_none()); let len = 1028; - let fd = FileDescriptor(result as i32); + let mut fd = FileDescriptor(result as i32); // read let read_mem: ~[u8] = vec::from_elem(len, 0u8); let buf = slice_to_uv_buf(read_mem); @@ -413,7 +413,7 @@ mod test { } fn naive_print(loop_: Loop, input: &str) { - let stdout = FileDescriptor(STDOUT_FILENO); + let mut stdout = FileDescriptor(STDOUT_FILENO); let write_val = input.as_bytes(); let write_buf = slice_to_uv_buf(write_val); stdout.write_sync(loop_, write_buf, -1); From 429b5f88f91e5f23f1ad04f6f9938fd1fa6c39a1 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 21 Aug 2013 21:29:23 -0700 Subject: [PATCH 19/26] std: rename tmp file paths to go into ./tmp folder in builddir --- src/libstd/rt/io/file.rs | 14 +++++++------- src/libstd/rt/uv/file.rs | 4 ++-- src/libstd/rt/uv/uvio.rs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index b7a923d94c744..c4ec19b6d27a8 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -192,7 +192,7 @@ impl Seek for FileStream { fn file_test_smoke_test_impl() { do run_in_newsched_task { let message = "it's alright. have a good time"; - let filename = &Path("./rt_io_file_test.txt"); + let filename = &Path("./tmp/file_rt_io_file_test.txt"); { let mut write_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); write_stream.write(message.as_bytes()); @@ -218,7 +218,7 @@ fn file_test_io_smoke_test() { fn file_test_invalid_path_opened_without_create_should_raise_condition_impl() { do run_in_newsched_task { - let filename = &Path("./file_that_does_not_exist.txt"); + let filename = &Path("./tmp/file_that_does_not_exist.txt"); let mut called = false; do io_error::cond.trap(|_| { called = true; @@ -236,7 +236,7 @@ fn file_test_io_invalid_path_opened_without_create_should_raise_condition() { fn file_test_unlinking_invalid_path_should_raise_condition_impl() { do run_in_newsched_task { - let filename = &Path("./another_file_that_does_not_exist.txt"); + let filename = &Path("./tmp/file_another_file_that_does_not_exist.txt"); let mut called = false; do io_error::cond.trap(|_| { called = true; @@ -256,7 +256,7 @@ fn file_test_io_non_positional_read_impl() { use str; let message = "ten-four"; let mut read_mem = [0, .. 8]; - let filename = &Path("./rt_io_file_test_positional.txt"); + let filename = &Path("./tmp/file_rt_io_file_test_positional.txt"); { let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); rw_stream.write(message.as_bytes()); @@ -291,7 +291,7 @@ fn file_test_io_seeking_impl() { let set_cursor = 4 as u64; let mut tell_pos_pre_read; let mut tell_pos_post_read; - let filename = &Path("./rt_io_file_test_seeking.txt"); + let filename = &Path("./tmp/file_rt_io_file_test_seeking.txt"); { let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); rw_stream.write(message.as_bytes()); @@ -324,7 +324,7 @@ fn file_test_io_seek_and_write_impl() { let final_msg = "foo-the-bar!!"; let seek_idx = 3; let mut read_mem = [0, .. 13]; - let filename = &Path("./rt_io_file_test_seek_and_write.txt"); + let filename = &Path("./tmp/file_rt_io_file_test_seek_and_write.txt"); { let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); rw_stream.write(initial_msg.as_bytes()); @@ -354,7 +354,7 @@ fn file_test_io_seek_shakedown_impl() { let chunk_two = "asdf"; let chunk_three = "zxcv"; let mut read_mem = [0, .. 4]; - let filename = &Path("./rt_io_file_test_seek_shakedown.txt"); + let filename = &Path("./tmp/file_rt_io_file_test_seek_shakedown.txt"); { let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); rw_stream.write(initial_msg.as_bytes()); diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index f88731ca63579..6abc21219e977 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -281,7 +281,7 @@ mod test { // these aren't defined in std::libc :( //map_mode(S_IRGRP) | //map_mode(S_IROTH); - let path_str = "./file_full_simple.txt"; + let path_str = "./tmp/file_full_simple.txt"; let write_val = "hello".as_bytes().to_owned(); let write_buf = slice_to_uv_buf(write_val); let write_buf_ptr: *Buf = &write_buf; @@ -352,7 +352,7 @@ mod test { S_IRUSR; //S_IRGRP | //S_IROTH; - let path_str = "./file_full_simple_sync.txt"; + let path_str = "./tmp/file_full_simple_sync.txt"; let write_val = "hello".as_bytes().to_owned(); let write_buf = slice_to_uv_buf(write_val); // open/create diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 8d76c5e87270c..fa5b49432976f 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -1711,7 +1711,7 @@ fn file_test_uvio_full_simple_impl() { let ro_flags = O_RDONLY; let write_val = "hello uvio!"; let mode = S_IWUSR | S_IRUSR; - let path = "./file_test_uvio_full.txt"; + let path = "./tmp/file_test_uvio_full.txt"; { let mut fd = (*io).fs_open(&Path(path), create_flags as int, mode as int).unwrap(); let write_buf = write_val.as_bytes(); From f85d3b3ec1c8c06a6929a960b3d544fb810e1c70 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Wed, 21 Aug 2013 23:09:39 -0700 Subject: [PATCH 20/26] std: reform fn sigs of FileDescriptor methods (better result signalling) --- src/libstd/rt/uv/file.rs | 88 +++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 6abc21219e977..eb1b12f3eb21a 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -12,7 +12,7 @@ use prelude::*; use ptr::null; use libc::c_void; use rt::uv::{Request, NativeHandle, Loop, FsCallback, Buf, - status_to_maybe_uv_error_with_loop}; + status_to_maybe_uv_error_with_loop, UvError}; use rt::uv::uvll; use rt::uv::uvll::*; use super::super::io::support::PathLike; @@ -86,6 +86,13 @@ impl NativeHandle<*uvll::uv_fs_t> for FsRequest { match self { &FsRequest(ptr) => ptr } } } + fn sync_cleanup(loop_: &Loop, result: int) + -> Result { + match status_to_maybe_uv_error_with_loop(loop_.native_handle(), result as i32) { + Some(err) => Err(err), + None => Ok(result) + } + } pub struct FileDescriptor(c_int); impl FileDescriptor { @@ -93,6 +100,7 @@ impl FileDescriptor { FileDescriptor(fd) } + pub fn from_open_req(req: &mut FsRequest) -> FileDescriptor { FileDescriptor::new(req.get_result()) } @@ -115,12 +123,13 @@ impl FileDescriptor { result } pub fn open(loop_: Loop, path: &P, flags: int, mode: int, - cb: FsCallback) -> int { - FileDescriptor::open_common(loop_, path, flags, mode, Some(cb)) + cb: FsCallback) { + FileDescriptor::open_common(loop_, path, flags, mode, Some(cb)); } - pub fn open_sync(loop_: Loop, path: &P, flags: int, mode: int) -> int { - FileDescriptor::open_common(loop_, path, flags, mode, None) + pub fn open_sync(loop_: Loop, path: &P, flags: int, mode: int) -> Result { + let result = FileDescriptor::open_common(loop_, path, flags, mode, None); + sync_cleanup(&loop_, result) } fn unlink_common(loop_: Loop, path: &P, cb: Option) -> int { @@ -139,11 +148,13 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn unlink(loop_: Loop, path: &P, cb: FsCallback) -> int { - FileDescriptor::unlink_common(loop_, path, Some(cb)) + pub fn unlink(loop_: Loop, path: &P, cb: FsCallback) { + let result = FileDescriptor::unlink_common(loop_, path, Some(cb)); + sync_cleanup(&loop_, result); } - pub fn unlink_sync(loop_: Loop, path: &P) -> int { - FileDescriptor::unlink_common(loop_, path, None) + pub fn unlink_sync(loop_: Loop, path: &P) -> Result { + let result = FileDescriptor::unlink_common(loop_, path, None); + sync_cleanup(&loop_, result) } // as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write @@ -166,13 +177,13 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn write(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) - -> int { - self.write_common(loop_, buf, offset, Some(cb)) + pub fn write(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) { + self.write_common(loop_, buf, offset, Some(cb)); } pub fn write_sync(&mut self, loop_: Loop, buf: Buf, offset: i64) - -> int { - self.write_common(loop_, buf, offset, None) + -> Result { + let result = self.write_common(loop_, buf, offset, None); + sync_cleanup(&loop_, result) } fn read_common(&mut self, loop_: Loop, buf: Buf, @@ -194,13 +205,13 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn read(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) - -> int { - self.read_common(loop_, buf, offset, Some(cb)) + pub fn read(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) { + self.read_common(loop_, buf, offset, Some(cb)); } pub fn read_sync(&mut self, loop_: Loop, buf: Buf, offset: i64) - -> int { - self.read_common(loop_, buf, offset, None) + -> Result { + let result = self.read_common(loop_, buf, offset, None); + sync_cleanup(&loop_, result) } fn close_common(self, loop_: Loop, cb: Option) -> int { @@ -217,11 +228,12 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn close(self, loop_: Loop, cb: FsCallback) -> int { - self.close_common(loop_, Some(cb)) + pub fn close(self, loop_: Loop, cb: FsCallback) { + self.close_common(loop_, Some(cb)); } - pub fn close_sync(self, loop_: Loop) -> int { - self.close_common(loop_, None) + pub fn close_sync(self, loop_: Loop) -> Result { + let result = self.close_common(loop_, None); + sync_cleanup(&loop_, result) } } extern fn compl_cb(req: *uv_fs_t) { @@ -265,8 +277,7 @@ mod test { use str; use unstable::run_in_bare_thread; use path::Path; - use rt::uv::{Loop, Buf, slice_to_uv_buf, - status_to_maybe_uv_error_with_loop}; + use rt::uv::{Loop, Buf, slice_to_uv_buf}; use libc::{O_CREAT, O_RDWR, O_RDONLY, S_IWUSR, S_IRUSR}; //NOTE: need defs for S_**GRP|S_**OTH in libc:: ... //S_IRGRP, S_IROTH}; @@ -358,31 +369,26 @@ mod test { // open/create let result = FileDescriptor::open_sync(loop_, &Path(path_str), create_flags as int, mode as int); - assert!(status_to_maybe_uv_error_with_loop( - loop_.native_handle(), result as i32).is_none()); - let mut fd = FileDescriptor(result as i32); + assert!(result.is_ok()); + let mut fd = FileDescriptor(result.unwrap() as i32); // write let result = fd.write_sync(loop_, write_buf, -1); - assert!(status_to_maybe_uv_error_with_loop( - loop_.native_handle(), result as i32).is_none()); + assert!(result.is_ok()); // close let result = fd.close_sync(loop_); - assert!(status_to_maybe_uv_error_with_loop( - loop_.native_handle(), result as i32).is_none()); + assert!(result.is_ok()); // re-open let result = FileDescriptor::open_sync(loop_, &Path(path_str), read_flags as int,0); - assert!(status_to_maybe_uv_error_with_loop( - loop_.native_handle(), result as i32).is_none()); + assert!(result.is_ok()); let len = 1028; - let mut fd = FileDescriptor(result as i32); + let mut fd = FileDescriptor(result.unwrap() as i32); // read let read_mem: ~[u8] = vec::from_elem(len, 0u8); let buf = slice_to_uv_buf(read_mem); let result = fd.read_sync(loop_, buf, 0); - assert!(status_to_maybe_uv_error_with_loop( - loop_.native_handle(), result as i32).is_none()); - let nread = result; + assert!(result.is_ok()); + let nread = result.unwrap(); // nread == 0 would be EOF.. we know it's >= zero because otherwise // the above assert would fail if nread > 0 { @@ -391,12 +397,10 @@ mod test { assert!(read_str == ~"hello"); // close let result = fd.close_sync(loop_); - assert!(status_to_maybe_uv_error_with_loop( - loop_.native_handle(), result as i32).is_none()); + assert!(result.is_ok()); // unlink let result = FileDescriptor::unlink_sync(loop_, &Path(path_str)); - assert!(status_to_maybe_uv_error_with_loop( - loop_.native_handle(), result as i32).is_none()); + assert!(result.is_ok()); } else { fail!("nread was 0.. wudn't expectin' that."); } loop_.close(); } From f01e26535738601524deba9e5f0a496527ee9d92 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 22 Aug 2013 09:07:54 -0700 Subject: [PATCH 21/26] std: moved static file actions (open,unlink) to FsRequest --- src/libstd/rt/uv/file.rs | 122 +++++++++++++++++++-------------------- src/libstd/rt/uv/uvio.rs | 4 +- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index eb1b12f3eb21a..637b5a754587f 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -37,6 +37,58 @@ impl FsRequest { fs_req } + fn open_common(loop_: Loop, path: &P, flags: int, mode: int, + cb: Option) -> int { + let complete_cb_ptr = match cb { + Some(_) => compl_cb as *u8, + None => 0 as *u8 + }; + let is_sync = cb.is_none(); + let req = FsRequest::new(cb); + let result = path.path_as_str(|p| { + p.to_c_str().with_ref(|p| unsafe { + uvll::fs_open(loop_.native_handle(), + req.native_handle(), p, flags, mode, complete_cb_ptr) as int + }) + }); + if is_sync { req.cleanup_and_delete(); } + result + } + pub fn open(loop_: Loop, path: &P, flags: int, mode: int, + cb: FsCallback) { + FsRequest::open_common(loop_, path, flags, mode, Some(cb)); + } + + pub fn open_sync(loop_: Loop, path: &P, flags: int, mode: int) -> Result { + let result = FsRequest::open_common(loop_, path, flags, mode, None); + sync_cleanup(&loop_, result) + } + + fn unlink_common(loop_: Loop, path: &P, cb: Option) -> int { + let complete_cb_ptr = match cb { + Some(_) => compl_cb as *u8, + None => 0 as *u8 + }; + let is_sync = cb.is_none(); + let req = FsRequest::new(cb); + let result = path.path_as_str(|p| { + p.to_c_str().with_ref(|p| unsafe { + uvll::fs_unlink(loop_.native_handle(), + req.native_handle(), p, complete_cb_ptr) as int + }) + }); + if is_sync { req.cleanup_and_delete(); } + result + } + pub fn unlink(loop_: Loop, path: &P, cb: FsCallback) { + let result = FsRequest::unlink_common(loop_, path, Some(cb)); + sync_cleanup(&loop_, result); + } + pub fn unlink_sync(loop_: Loop, path: &P) -> Result { + let result = FsRequest::unlink_common(loop_, path, None); + sync_cleanup(&loop_, result) + } + pub fn install_req_data(&self, cb: Option) { let fs_req = (self.native_handle()) as *uvll::uv_write_t; let data = ~RequestData { @@ -105,63 +157,11 @@ impl FileDescriptor { FileDescriptor::new(req.get_result()) } - fn open_common(loop_: Loop, path: &P, flags: int, mode: int, - cb: Option) -> int { - let complete_cb_ptr = match cb { - Some(_) => compl_cb, - None => 0 as *u8 - }; - let is_sync = cb.is_none(); - let req = FsRequest::new(cb); - let result = path.path_as_str(|p| { - p.to_c_str().with_ref(|p| unsafe { - uvll::fs_open(loop_.native_handle(), - req.native_handle(), p, flags, mode, complete_cb_ptr) as int - }) - }); - if is_sync { req.cleanup_and_delete(); } - result - } - pub fn open(loop_: Loop, path: &P, flags: int, mode: int, - cb: FsCallback) { - FileDescriptor::open_common(loop_, path, flags, mode, Some(cb)); - } - - pub fn open_sync(loop_: Loop, path: &P, flags: int, mode: int) -> Result { - let result = FileDescriptor::open_common(loop_, path, flags, mode, None); - sync_cleanup(&loop_, result) - } - - fn unlink_common(loop_: Loop, path: &P, cb: Option) -> int { - let complete_cb_ptr = match cb { - Some(_) => compl_cb, - None => 0 as *u8 - }; - let is_sync = cb.is_none(); - let req = FsRequest::new(cb); - let result = path.path_as_str(|p| { - p.to_c_str().with_ref(|p| unsafe { - uvll::fs_unlink(loop_.native_handle(), - req.native_handle(), p, complete_cb_ptr) as int - }) - }); - if is_sync { req.cleanup_and_delete(); } - result - } - pub fn unlink(loop_: Loop, path: &P, cb: FsCallback) { - let result = FileDescriptor::unlink_common(loop_, path, Some(cb)); - sync_cleanup(&loop_, result); - } - pub fn unlink_sync(loop_: Loop, path: &P) -> Result { - let result = FileDescriptor::unlink_common(loop_, path, None); - sync_cleanup(&loop_, result) - } - // as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write fn write_common(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: Option) -> int { let complete_cb_ptr = match cb { - Some(_) => compl_cb, + Some(_) => compl_cb as *u8, None => 0 as *u8 }; let is_sync = cb.is_none(); @@ -190,7 +190,7 @@ impl FileDescriptor { offset: i64, cb: Option) -> int { let complete_cb_ptr = match cb { - Some(_) => compl_cb, + Some(_) => compl_cb as *u8, None => 0 as *u8 }; let is_sync = cb.is_none(); @@ -216,7 +216,7 @@ impl FileDescriptor { fn close_common(self, loop_: Loop, cb: Option) -> int { let complete_cb_ptr = match cb { - Some(_) => compl_cb, + Some(_) => compl_cb as *u8, None => 0 as *u8 }; let is_sync = cb.is_none(); @@ -301,7 +301,7 @@ mod test { let read_buf = slice_to_uv_buf(read_mem); let read_buf_ptr: *Buf = &read_buf; let p = Path(path_str); - do FileDescriptor::open(loop_, &p, create_flags as int, mode as int) + do FsRequest::open(loop_, &p, create_flags as int, mode as int) |req, uverr| { let loop_ = req.get_loop(); assert!(uverr.is_none()); @@ -313,7 +313,7 @@ mod test { do fd.close(loop_) |req, _| { let loop_ = req.get_loop(); assert!(uverr.is_none()); - do FileDescriptor::open(loop_, &Path(path_str), read_flags as int,0) + do FsRequest::open(loop_, &Path(path_str), read_flags as int,0) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); @@ -336,7 +336,7 @@ mod test { assert!(read_str == ~"hello"); do FileDescriptor(raw_fd).close(loop_) |_,uverr| { assert!(uverr.is_none()); - do FileDescriptor::unlink(loop_, &Path(path_str)) + do FsRequest::unlink(loop_, &Path(path_str)) |_,uverr| { assert!(uverr.is_none()); }; @@ -367,7 +367,7 @@ mod test { let write_val = "hello".as_bytes().to_owned(); let write_buf = slice_to_uv_buf(write_val); // open/create - let result = FileDescriptor::open_sync(loop_, &Path(path_str), + let result = FsRequest::open_sync(loop_, &Path(path_str), create_flags as int, mode as int); assert!(result.is_ok()); let mut fd = FileDescriptor(result.unwrap() as i32); @@ -378,7 +378,7 @@ mod test { let result = fd.close_sync(loop_); assert!(result.is_ok()); // re-open - let result = FileDescriptor::open_sync(loop_, &Path(path_str), + let result = FsRequest::open_sync(loop_, &Path(path_str), read_flags as int,0); assert!(result.is_ok()); let len = 1028; @@ -399,7 +399,7 @@ mod test { let result = fd.close_sync(loop_); assert!(result.is_ok()); // unlink - let result = FileDescriptor::unlink_sync(loop_, &Path(path_str)); + let result = FsRequest::unlink_sync(loop_, &Path(path_str)); assert!(result.is_ok()); } else { fail!("nread was 0.. wudn't expectin' that."); } loop_.close(); diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index fa5b49432976f..acdd8b2dabf9f 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -477,7 +477,7 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - do file::FileDescriptor::open(loop_, path, flags, mode) |req,err| { + do file::FsRequest::open(loop_, path, flags, mode) |req,err| { if err.is_none() { let home = get_handle_to_current_scheduler!(); let fd = file::FileDescriptor(req.get_result()); @@ -508,7 +508,7 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - do file::FileDescriptor::unlink(loop_, path) |_, err| { + do file::FsRequest::unlink(loop_, path) |_, err| { let res = match err { None => Ok(()), Some(err) => Err(uv_error_to_io_error(err)) From 94b84a851c1ac088c884c8dde00199fdf91d9f4d Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 22 Aug 2013 12:29:34 -0700 Subject: [PATCH 22/26] std: all of the calls in rt::uv::file take a &Loop --- src/libstd/rt/uv/file.rs | 74 ++++++++++++++++++++-------------------- src/libstd/rt/uv/uvio.rs | 13 ++++--- 2 files changed, 43 insertions(+), 44 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 637b5a754587f..1a20ae82f17f1 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -37,7 +37,7 @@ impl FsRequest { fs_req } - fn open_common(loop_: Loop, path: &P, flags: int, mode: int, + fn open_common(loop_: &Loop, path: &P, flags: int, mode: int, cb: Option) -> int { let complete_cb_ptr = match cb { Some(_) => compl_cb as *u8, @@ -54,17 +54,17 @@ impl FsRequest { if is_sync { req.cleanup_and_delete(); } result } - pub fn open(loop_: Loop, path: &P, flags: int, mode: int, + pub fn open(loop_: &Loop, path: &P, flags: int, mode: int, cb: FsCallback) { FsRequest::open_common(loop_, path, flags, mode, Some(cb)); } - pub fn open_sync(loop_: Loop, path: &P, flags: int, mode: int) -> Result { + pub fn open_sync(loop_: &Loop, path: &P, flags: int, mode: int) -> Result { let result = FsRequest::open_common(loop_, path, flags, mode, None); - sync_cleanup(&loop_, result) + sync_cleanup(loop_, result) } - fn unlink_common(loop_: Loop, path: &P, cb: Option) -> int { + fn unlink_common(loop_: &Loop, path: &P, cb: Option) -> int { let complete_cb_ptr = match cb { Some(_) => compl_cb as *u8, None => 0 as *u8 @@ -80,13 +80,13 @@ impl FsRequest { if is_sync { req.cleanup_and_delete(); } result } - pub fn unlink(loop_: Loop, path: &P, cb: FsCallback) { + pub fn unlink(loop_: &Loop, path: &P, cb: FsCallback) { let result = FsRequest::unlink_common(loop_, path, Some(cb)); - sync_cleanup(&loop_, result); + sync_cleanup(loop_, result); } - pub fn unlink_sync(loop_: Loop, path: &P) -> Result { + pub fn unlink_sync(loop_: &Loop, path: &P) -> Result { let result = FsRequest::unlink_common(loop_, path, None); - sync_cleanup(&loop_, result) + sync_cleanup(loop_, result) } pub fn install_req_data(&self, cb: Option) { @@ -158,7 +158,7 @@ impl FileDescriptor { } // as per bnoordhuis in #libuv: offset >= 0 uses prwrite instead of write - fn write_common(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: Option) + fn write_common(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: Option) -> int { let complete_cb_ptr = match cb { Some(_) => compl_cb as *u8, @@ -177,16 +177,16 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn write(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) { + pub fn write(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) { self.write_common(loop_, buf, offset, Some(cb)); } - pub fn write_sync(&mut self, loop_: Loop, buf: Buf, offset: i64) + pub fn write_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64) -> Result { let result = self.write_common(loop_, buf, offset, None); - sync_cleanup(&loop_, result) + sync_cleanup(loop_, result) } - fn read_common(&mut self, loop_: Loop, buf: Buf, + fn read_common(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: Option) -> int { let complete_cb_ptr = match cb { @@ -205,16 +205,16 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn read(&mut self, loop_: Loop, buf: Buf, offset: i64, cb: FsCallback) { + pub fn read(&mut self, loop_: &Loop, buf: Buf, offset: i64, cb: FsCallback) { self.read_common(loop_, buf, offset, Some(cb)); } - pub fn read_sync(&mut self, loop_: Loop, buf: Buf, offset: i64) + pub fn read_sync(&mut self, loop_: &Loop, buf: Buf, offset: i64) -> Result { let result = self.read_common(loop_, buf, offset, None); - sync_cleanup(&loop_, result) + sync_cleanup(loop_, result) } - fn close_common(self, loop_: Loop, cb: Option) -> int { + fn close_common(self, loop_: &Loop, cb: Option) -> int { let complete_cb_ptr = match cb { Some(_) => compl_cb as *u8, None => 0 as *u8 @@ -228,12 +228,12 @@ impl FileDescriptor { if is_sync { req.cleanup_and_delete(); } result } - pub fn close(self, loop_: Loop, cb: FsCallback) { + pub fn close(self, loop_: &Loop, cb: FsCallback) { self.close_common(loop_, Some(cb)); } - pub fn close_sync(self, loop_: Loop) -> Result { + pub fn close_sync(self, loop_: &Loop) -> Result { let result = self.close_common(loop_, None); - sync_cleanup(&loop_, result) + sync_cleanup(loop_, result) } } extern fn compl_cb(req: *uv_fs_t) { @@ -301,26 +301,25 @@ mod test { let read_buf = slice_to_uv_buf(read_mem); let read_buf_ptr: *Buf = &read_buf; let p = Path(path_str); - do FsRequest::open(loop_, &p, create_flags as int, mode as int) + do FsRequest::open(&loop_, &p, create_flags as int, mode as int) |req, uverr| { - let loop_ = req.get_loop(); assert!(uverr.is_none()); let mut fd = FileDescriptor::from_open_req(req); let raw_fd = fd.native_handle(); let buf = unsafe { *write_buf_ptr }; - do fd.write(loop_, buf, -1) |_, uverr| { + do fd.write(&req.get_loop(), buf, -1) |req, uverr| { let fd = FileDescriptor(raw_fd); - do fd.close(loop_) |req, _| { + do fd.close(&req.get_loop()) |req, _| { let loop_ = req.get_loop(); assert!(uverr.is_none()); - do FsRequest::open(loop_, &Path(path_str), read_flags as int,0) + do FsRequest::open(&loop_, &Path(path_str), read_flags as int,0) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); let mut fd = FileDescriptor::from_open_req(req); let raw_fd = fd.native_handle(); let read_buf = unsafe { *read_buf_ptr }; - do fd.read(loop_, read_buf, 0) |req, uverr| { + do fd.read(&loop_, read_buf, 0) |req, uverr| { assert!(uverr.is_none()); let loop_ = req.get_loop(); // we know nread >=0 because uverr is none.. @@ -334,8 +333,9 @@ mod test { read_buf.base, nread)) }; assert!(read_str == ~"hello"); - do FileDescriptor(raw_fd).close(loop_) |_,uverr| { + do FileDescriptor(raw_fd).close(&loop_) |req,uverr| { assert!(uverr.is_none()); + let loop_ = &req.get_loop(); do FsRequest::unlink(loop_, &Path(path_str)) |_,uverr| { assert!(uverr.is_none()); @@ -367,18 +367,18 @@ mod test { let write_val = "hello".as_bytes().to_owned(); let write_buf = slice_to_uv_buf(write_val); // open/create - let result = FsRequest::open_sync(loop_, &Path(path_str), + let result = FsRequest::open_sync(&loop_, &Path(path_str), create_flags as int, mode as int); assert!(result.is_ok()); let mut fd = FileDescriptor(result.unwrap() as i32); // write - let result = fd.write_sync(loop_, write_buf, -1); + let result = fd.write_sync(&loop_, write_buf, -1); assert!(result.is_ok()); // close - let result = fd.close_sync(loop_); + let result = fd.close_sync(&loop_); assert!(result.is_ok()); // re-open - let result = FsRequest::open_sync(loop_, &Path(path_str), + let result = FsRequest::open_sync(&loop_, &Path(path_str), read_flags as int,0); assert!(result.is_ok()); let len = 1028; @@ -386,7 +386,7 @@ mod test { // read let read_mem: ~[u8] = vec::from_elem(len, 0u8); let buf = slice_to_uv_buf(read_mem); - let result = fd.read_sync(loop_, buf, 0); + let result = fd.read_sync(&loop_, buf, 0); assert!(result.is_ok()); let nread = result.unwrap(); // nread == 0 would be EOF.. we know it's >= zero because otherwise @@ -396,10 +396,10 @@ mod test { read_mem.slice(0, nread as uint)); assert!(read_str == ~"hello"); // close - let result = fd.close_sync(loop_); + let result = fd.close_sync(&loop_); assert!(result.is_ok()); // unlink - let result = FsRequest::unlink_sync(loop_, &Path(path_str)); + let result = FsRequest::unlink_sync(&loop_, &Path(path_str)); assert!(result.is_ok()); } else { fail!("nread was 0.. wudn't expectin' that."); } loop_.close(); @@ -416,7 +416,7 @@ mod test { file_test_full_simple_impl_sync(); } - fn naive_print(loop_: Loop, input: &str) { + fn naive_print(loop_: &Loop, input: &str) { let mut stdout = FileDescriptor(STDOUT_FILENO); let write_val = input.as_bytes(); let write_buf = slice_to_uv_buf(write_val); @@ -427,7 +427,7 @@ mod test { fn file_test_write_to_stdout() { do run_in_bare_thread { let mut loop_ = Loop::new(); - naive_print(loop_, "zanzibar!\n"); + naive_print(&loop_, "zanzibar!\n"); loop_.run(); loop_.close(); }; diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index acdd8b2dabf9f..63ff446ecf02b 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -468,7 +468,6 @@ impl IoFactory for UvIoFactory { fn fs_open(&mut self, path: &P, flags: int, mode: int) -> Result<~RtioFileStream, IoError> { - let loop_ = Loop {handle: self.uv_loop().native_handle()}; let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -477,8 +476,9 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - do file::FsRequest::open(loop_, path, flags, mode) |req,err| { + do file::FsRequest::open(self.uv_loop(), path, flags, mode) |req,err| { if err.is_none() { + let loop_ = Loop {handle: req.get_loop().native_handle()}; let home = get_handle_to_current_scheduler!(); let fd = file::FileDescriptor(req.get_result()); let fs = ~UvFileStream::new( @@ -500,7 +500,6 @@ impl IoFactory for UvIoFactory { } fn fs_unlink(&mut self, path: &P) -> Result<(), IoError> { - let loop_ = Loop {handle: self.uv_loop().native_handle()}; let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; let path_cell = Cell::new(path); @@ -508,7 +507,7 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - do file::FsRequest::unlink(loop_, path) |_, err| { + do file::FsRequest::unlink(self.uv_loop(), path) |_, err| { let res = match err { None => Ok(()), Some(err) => Err(uv_error_to_io_error(err)) @@ -1088,7 +1087,7 @@ impl UvFileStream { do scheduler.deschedule_running_task_and_then |_, task| { let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; let task_cell = Cell::new(task); - do self_.fd.read(self.loop_, buf, offset) |req, uverr| { + do self_.fd.read(&self_.loop_, buf, offset) |req, uverr| { let res = match uverr { None => Ok(req.get_result() as int), Some(err) => Err(uv_error_to_io_error(err)) @@ -1110,7 +1109,7 @@ impl UvFileStream { do scheduler.deschedule_running_task_and_then |_, task| { let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; let task_cell = Cell::new(task); - do self_.fd.write(self.loop_, buf, offset) |_, uverr| { + do self_.fd.write(&self_.loop_, buf, offset) |_, uverr| { let res = match uverr { None => Ok(()), Some(err) => Err(uv_error_to_io_error(err)) @@ -1133,7 +1132,7 @@ impl Drop for UvFileStream { let scheduler = Local::take::(); do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); - do self_.fd.close(self.loop_) |_,_| { + do self_.fd.close(&self.loop_) |_,_| { let scheduler = Local::take::(); scheduler.resume_blocked_task_immediately(task_cell.take()); }; From 6311856bf42828e3c502a28b414586badb1192c8 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 22 Aug 2013 15:03:28 -0700 Subject: [PATCH 23/26] std: slight refactor on UvFilestream seek behavior, pre-seek-refactor --- src/libstd/rt/io/file.rs | 10 ++----- src/libstd/rt/rtio.rs | 3 +- src/libstd/rt/uv/uvio.rs | 59 ++++++++++++++++++++-------------------- 3 files changed, 34 insertions(+), 38 deletions(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index c4ec19b6d27a8..816f7e08eabe6 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -170,15 +170,9 @@ impl Seek for FileStream { } fn seek(&mut self, pos: i64, style: SeekStyle) { - use libc::{SEEK_SET, SEEK_CUR, SEEK_END}; - let whence = match style { - SeekSet => SEEK_SET, - SeekCur => SEEK_CUR, - SeekEnd => SEEK_END - } as i64; - match self.fd.seek(pos, whence) { + match self.fd.seek(pos, style) { Ok(_) => { - // successful seek resets EOF indocator + // successful seek resets EOF indicator self.last_nread = -1; () }, diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index 3a14f679fa767..b73200bcda131 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -17,6 +17,7 @@ use super::io::net::ip::{IpAddr, SocketAddr}; use rt::uv::uvio; use path::Path; use super::io::support::PathLike; +use super::io::{SeekStyle}; // XXX: ~object doesn't work currently so these are some placeholder // types to use instead @@ -118,7 +119,7 @@ pub trait RtioFileStream { fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; fn pread(&mut self, buf: &mut [u8], offset: u64) -> Result; fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError>; - fn seek(&mut self, pos: i64, whence: i64) -> Result<(), IoError>; + fn seek(&mut self, pos: i64, whence: SeekStyle) -> Result; fn tell(&self) -> Result; fn flush(&mut self) -> Result<(), IoError>; } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 63ff446ecf02b..93d87fb5495cd 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -21,7 +21,7 @@ use str; use result::*; use rt::io::IoError; use rt::io::net::ip::{SocketAddr, IpAddr}; -use rt::io::{standard_error, OtherIoError}; +use rt::io::{standard_error, OtherIoError, SeekStyle, SeekSet, SeekCur, SeekEnd}; use rt::local::Local; use rt::rtio::*; use rt::sched::{Scheduler, SchedHandle}; @@ -31,7 +31,7 @@ use rt::uv::idle::IdleWatcher; use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; use unstable::sync::Exclusive; use super::super::io::support::PathLike; -use libc::{lseek, c_long, SEEK_CUR}; +use libc::{lseek, c_long}; #[cfg(test)] use container::Container; #[cfg(test)] use unstable::run_in_bare_thread; @@ -1122,6 +1122,22 @@ impl UvFileStream { }; result_cell.take() } + fn seek_common(&mut self, pos: i64, whence: c_int) -> + Result{ + #[fixed_stack_segment]; #[inline(never)]; + unsafe { + match lseek((*self.fd), pos as c_long, whence) { + -1 => { + Err(IoError { + kind: OtherIoError, + desc: "Failed to lseek.", + detail: None + }) + }, + n => Ok(n as u64) + } + } + } } impl Drop for UvFileStream { @@ -1155,35 +1171,20 @@ impl RtioFileStream for UvFileStream { fn pwrite(&mut self, buf: &[u8], offset: u64) -> Result<(), IoError> { self.base_write(buf, offset as i64) } - fn seek(&mut self, pos: i64, whence: i64) -> Result<(), IoError> { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - match lseek((*self.fd), pos as c_long, whence as c_int) { - -1 => { - Err(IoError { - kind: OtherIoError, - desc: "Failed to lseek.", - detail: None - }) - }, - _ => Ok(()) - } - } + fn seek(&mut self, pos: i64, whence: SeekStyle) -> Result { + use libc::{SEEK_SET, SEEK_CUR, SEEK_END}; + let whence = match whence { + SeekSet => SEEK_SET, + SeekCur => SEEK_CUR, + SeekEnd => SEEK_END + }; + self.seek_common(pos, whence) } fn tell(&self) -> Result { - #[fixed_stack_segment]; #[inline(never)]; - unsafe { - match lseek((*self.fd), 0, SEEK_CUR) { - -1 => { - Err(IoError { - kind: OtherIoError, - desc: "Failed to lseek, needed to tell().", - detail: None - }) - }, - n=> Ok(n as u64) - } - } + use libc::SEEK_CUR; + // this is temporary + let self_ = unsafe { cast::transmute::<&UvFileStream, &mut UvFileStream>(self) }; + self_.seek_common(0, SEEK_CUR) } fn flush(&mut self) -> Result<(), IoError> { Ok(()) From 8d997fba1a035b20d208c588cb267385dea74f6c Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 22 Aug 2013 16:31:23 -0700 Subject: [PATCH 24/26] std: put FileMode/Access->whence-mask in uvio, open/unlink as fns in file:: --- src/libstd/rt/io/file.rs | 140 ++++++++++++++------------------------- src/libstd/rt/io/mod.rs | 24 +++++++ src/libstd/rt/rtio.rs | 3 +- src/libstd/rt/uv/uvio.rs | 42 +++++++++--- 4 files changed, 109 insertions(+), 100 deletions(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index 816f7e08eabe6..65db76d5ef768 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -13,34 +13,45 @@ use super::support::PathLike; use super::{Reader, Writer, Seek}; use super::{SeekSet, SeekCur, SeekEnd, SeekStyle}; use rt::rtio::{RtioFileStream, IoFactory, IoFactoryObject}; -use rt::io::{io_error, read_error, EndOfFile}; +use rt::io::{io_error, read_error, EndOfFile, + FileMode, FileAccess, Open, Read, Create, ReadWrite}; use rt::local::Local; use rt::test::*; -use libc::{O_RDWR, O_RDONLY, O_WRONLY, S_IWUSR, S_IRUSR, - O_CREAT, O_TRUNC, O_APPEND}; -/// Instructions on how to open a file and return a `FileStream`. -enum FileMode { - /// Opens an existing file. IoError if file does not exist. - Open, - /// Creates a file. IoError if file exists. - Create, - /// Opens an existing file or creates a new one. - OpenOrCreate, - /// Opens an existing file or creates a new one, positioned at EOF. - Append, - /// Opens an existing file, truncating it to 0 bytes. - Truncate, - /// Opens an existing file or creates a new one, truncating it to 0 bytes. - CreateOrTruncate, +/// Open a file for reading/writing, as indicated by `path`. +pub fn open(path: &P, + mode: FileMode, + access: FileAccess + ) -> Option { + let open_result = unsafe { + let io = Local::unsafe_borrow::(); + (*io).fs_open(path, mode, access) + }; + match open_result { + Ok(fd) => Some(FileStream { + fd: fd, + last_nread: -1 + }), + Err(ioerr) => { + io_error::cond.raise(ioerr); + None + } + } } -/// How should the file be opened? `FileStream`s opened with `Read` will -/// raise an `io_error` condition if written to. -enum FileAccess { - Read, - Write, - ReadWrite +/// Unlink (remove) a file from the filesystem, as indicated +/// by `path`. +pub fn unlink(path: &P) { + let unlink_result = unsafe { + let io = Local::unsafe_borrow::(); + (*io).fs_unlink(path) + }; + match unlink_result { + Ok(_) => (), + Err(ioerr) => { + io_error::cond.raise(ioerr); + } + } } /// Abstraction representing *positional* access to a file. In this case, @@ -61,55 +72,6 @@ pub struct FileStream { } impl FileStream { - pub fn open(path: &P, - mode: FileMode, - access: FileAccess - ) -> Option { - let open_result = unsafe { - let io = Local::unsafe_borrow::(); - let mut flags = match mode { - Open => 0, - Create => O_CREAT, - OpenOrCreate => O_CREAT, - Append => O_APPEND, - Truncate => O_TRUNC, - CreateOrTruncate => O_TRUNC | O_CREAT - }; - flags = match access { - Read => flags | O_RDONLY, - Write => flags | O_WRONLY, - ReadWrite => flags | O_RDWR - }; - let create_mode = match mode { - Create|OpenOrCreate|CreateOrTruncate => - S_IRUSR | S_IWUSR, - _ => 0 - }; - (*io).fs_open(path, flags as int, create_mode as int) - }; - match open_result { - Ok(fd) => Some(FileStream { - fd: fd, - last_nread: -1 - }), - Err(ioerr) => { - io_error::cond.raise(ioerr); - None - } - } - } - fn unlink(path: &P) { - let unlink_result = unsafe { - let io = Local::unsafe_borrow::(); - (*io).fs_unlink(path) - }; - match unlink_result { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } } impl Reader for FileStream { @@ -188,12 +150,12 @@ fn file_test_smoke_test_impl() { let message = "it's alright. have a good time"; let filename = &Path("./tmp/file_rt_io_file_test.txt"); { - let mut write_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut write_stream = open(filename, Create, ReadWrite).unwrap(); write_stream.write(message.as_bytes()); } { use str; - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); let mut read_buf = [0, .. 1028]; let read_str = match read_stream.read(read_buf).unwrap() { -1|0 => fail!("shouldn't happen"), @@ -201,7 +163,7 @@ fn file_test_smoke_test_impl() { }; assert!(read_str == message.to_owned()); } - FileStream::unlink(filename); + unlink(filename); } } @@ -217,7 +179,7 @@ fn file_test_invalid_path_opened_without_create_should_raise_condition_impl() { do io_error::cond.trap(|_| { called = true; }).inside { - let result = FileStream::open(filename, Open, Read); + let result = open(filename, Open, Read); assert!(result.is_none()); } assert!(called); @@ -235,7 +197,7 @@ fn file_test_unlinking_invalid_path_should_raise_condition_impl() { do io_error::cond.trap(|_| { called = true; }).inside { - FileStream::unlink(filename); + unlink(filename); } assert!(called); } @@ -252,11 +214,11 @@ fn file_test_io_non_positional_read_impl() { let mut read_mem = [0, .. 8]; let filename = &Path("./tmp/file_rt_io_file_test_positional.txt"); { - let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); rw_stream.write(message.as_bytes()); } { - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); { let read_buf = read_mem.mut_slice(0, 4); read_stream.read(read_buf); @@ -266,7 +228,7 @@ fn file_test_io_non_positional_read_impl() { read_stream.read(read_buf); } } - FileStream::unlink(filename); + unlink(filename); let read_str = str::from_bytes(read_mem); assert!(read_str == message.to_owned()); } @@ -287,17 +249,17 @@ fn file_test_io_seeking_impl() { let mut tell_pos_post_read; let filename = &Path("./tmp/file_rt_io_file_test_seeking.txt"); { - let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); rw_stream.write(message.as_bytes()); } { - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); read_stream.seek(set_cursor as i64, SeekSet); tell_pos_pre_read = read_stream.tell(); read_stream.read(read_mem); tell_pos_post_read = read_stream.tell(); } - FileStream::unlink(filename); + unlink(filename); let read_str = str::from_bytes(read_mem); assert!(read_str == message.slice(4, 8).to_owned()); assert!(tell_pos_pre_read == set_cursor); @@ -320,16 +282,16 @@ fn file_test_io_seek_and_write_impl() { let mut read_mem = [0, .. 13]; let filename = &Path("./tmp/file_rt_io_file_test_seek_and_write.txt"); { - let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); rw_stream.write(initial_msg.as_bytes()); rw_stream.seek(seek_idx as i64, SeekSet); rw_stream.write(overwrite_msg.as_bytes()); } { - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); read_stream.read(read_mem); } - FileStream::unlink(filename); + unlink(filename); let read_str = str::from_bytes(read_mem); io::println(fmt!("read_str: '%?' final_msg: '%?'", read_str, final_msg)); assert!(read_str == final_msg.to_owned()); @@ -350,11 +312,11 @@ fn file_test_io_seek_shakedown_impl() { let mut read_mem = [0, .. 4]; let filename = &Path("./tmp/file_rt_io_file_test_seek_shakedown.txt"); { - let mut rw_stream = FileStream::open(filename, Create, ReadWrite).unwrap(); + let mut rw_stream = open(filename, Create, ReadWrite).unwrap(); rw_stream.write(initial_msg.as_bytes()); } { - let mut read_stream = FileStream::open(filename, Open, Read).unwrap(); + let mut read_stream = open(filename, Open, Read).unwrap(); read_stream.seek(-4, SeekEnd); read_stream.read(read_mem); @@ -371,7 +333,7 @@ fn file_test_io_seek_shakedown_impl() { let read_str = str::from_bytes(read_mem); assert!(read_str == chunk_one.to_owned()); } - FileStream::unlink(filename); + unlink(filename); } } #[test] diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 23b8017bc512c..116d240308a36 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -540,3 +540,27 @@ pub fn placeholder_error() -> IoError { detail: None } } + +/// Instructions on how to open a file and return a `FileStream`. +pub enum FileMode { + /// Opens an existing file. IoError if file does not exist. + Open, + /// Creates a file. IoError if file exists. + Create, + /// Opens an existing file or creates a new one. + OpenOrCreate, + /// Opens an existing file or creates a new one, positioned at EOF. + Append, + /// Opens an existing file, truncating it to 0 bytes. + Truncate, + /// Opens an existing file or creates a new one, truncating it to 0 bytes. + CreateOrTruncate, +} + +/// Access permissions with which the file should be opened. +/// `FileStream`s opened with `Read` will raise an `io_error` condition if written to. +pub enum FileAccess { + Read, + Write, + ReadWrite +} diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index b73200bcda131..1788b7a04e334 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -18,6 +18,7 @@ use rt::uv::uvio; use path::Path; use super::io::support::PathLike; use super::io::{SeekStyle}; +use super::io::{FileMode, FileAccess}; // XXX: ~object doesn't work currently so these are some placeholder // types to use instead @@ -68,7 +69,7 @@ pub trait IoFactory { fn udp_bind(&mut self, addr: SocketAddr) -> Result<~RtioUdpSocketObject, IoError>; fn timer_init(&mut self) -> Result<~RtioTimerObject, IoError>; fn fs_from_raw_fd(&mut self, fd: c_int, close_on_drop: bool) -> ~RtioFileStream; - fn fs_open(&mut self, path: &P, flags: int, mode:int) + fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError>; fn fs_unlink(&mut self, path: &P) -> Result<(), IoError>; } diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 93d87fb5495cd..b1b5f9f919c3b 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -31,7 +31,10 @@ use rt::uv::idle::IdleWatcher; use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; use unstable::sync::Exclusive; use super::super::io::support::PathLike; -use libc::{lseek, c_long}; +use libc::{lseek, c_long, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, + S_IRUSR, S_IWUSR}; +use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create, + CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite}; #[cfg(test)] use container::Container; #[cfg(test)] use unstable::run_in_bare_thread; @@ -466,8 +469,26 @@ impl IoFactory for UvIoFactory { ~UvFileStream::new(loop_, fd, close_on_drop, home) as ~RtioFileStream } - fn fs_open(&mut self, path: &P, flags: int, mode: int) + fn fs_open(&mut self, path: &P, fm: FileMode, fa: FileAccess) -> Result<~RtioFileStream, IoError> { + let mut flags = match fm { + Open => 0, + Create => O_CREAT, + OpenOrCreate => O_CREAT, + Append => O_APPEND, + Truncate => O_TRUNC, + CreateOrTruncate => O_TRUNC | O_CREAT + }; + flags = match fa { + Read => flags | O_RDONLY, + Write => flags | O_WRONLY, + ReadWrite => flags | O_RDWR + }; + let create_mode = match fm { + Create|OpenOrCreate|CreateOrTruncate => + S_IRUSR | S_IWUSR, + _ => 0 + }; let result_cell = Cell::new_empty(); let result_cell_ptr: *Cell> = &result_cell; @@ -476,7 +497,8 @@ impl IoFactory for UvIoFactory { do scheduler.deschedule_running_task_and_then |_, task| { let task_cell = Cell::new(task); let path = path_cell.take(); - do file::FsRequest::open(self.uv_loop(), path, flags, mode) |req,err| { + do file::FsRequest::open(self.uv_loop(), path, flags as int, create_mode as int) + |req,err| { if err.is_none() { let loop_ = Loop {handle: req.get_loop().native_handle()}; let home = get_handle_to_current_scheduler!(); @@ -1699,26 +1721,26 @@ fn test_timer_sleep_simple() { } fn file_test_uvio_full_simple_impl() { - use libc::{O_CREAT, O_RDWR, O_RDONLY, - S_IWUSR, S_IRUSR}; use str::StrSlice; // why does this have to be explicitly imported to work? // compiler was complaining about no trait for str that // does .as_bytes() .. use path::Path; + use rt::io::{Open, Create, ReadWrite, Read}; unsafe { let io = Local::unsafe_borrow::(); - let create_flags = O_RDWR | O_CREAT; - let ro_flags = O_RDONLY; let write_val = "hello uvio!"; - let mode = S_IWUSR | S_IRUSR; let path = "./tmp/file_test_uvio_full.txt"; { - let mut fd = (*io).fs_open(&Path(path), create_flags as int, mode as int).unwrap(); + let create_fm = Create; + let create_fa = ReadWrite; + let mut fd = (*io).fs_open(&Path(path), create_fm, create_fa).unwrap(); let write_buf = write_val.as_bytes(); fd.write(write_buf); } { - let mut fd = (*io).fs_open(&Path(path), ro_flags as int, mode as int).unwrap(); + let ro_fm = Open; + let ro_fa = Read; + let mut fd = (*io).fs_open(&Path(path), ro_fm, ro_fa).unwrap(); let mut read_vec = [0, .. 1028]; let nread = fd.read(read_vec).unwrap(); let read_val = str::from_bytes(read_vec.slice(0, nread as uint)); From 744c46225e09bad815b7807ca660cbdbcf187443 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 22 Aug 2013 16:33:59 -0700 Subject: [PATCH 25/26] make check appeasement --- src/libstd/rt/uv/file.rs | 3 ++- src/rt/rust_uv.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/rt/uv/file.rs b/src/libstd/rt/uv/file.rs index 1a20ae82f17f1..405dfe0a7f099 100644 --- a/src/libstd/rt/uv/file.rs +++ b/src/libstd/rt/uv/file.rs @@ -59,7 +59,8 @@ impl FsRequest { FsRequest::open_common(loop_, path, flags, mode, Some(cb)); } - pub fn open_sync(loop_: &Loop, path: &P, flags: int, mode: int) -> Result { + pub fn open_sync(loop_: &Loop, path: &P, flags: int, mode: int) + -> Result { let result = FsRequest::open_common(loop_, path, flags, mode, None); sync_cleanup(loop_, result) } diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index f90931dbea922..8ef4572f8108f 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -27,7 +27,7 @@ rust_uv_loop_new() { // XXX libuv doesn't always ignore SIGPIPE even though we don't need it. #ifndef __WIN32__ signal(SIGPIPE, SIG_IGN); -#endif +#endif return (void*)uv_loop_new(); } From b7cbd8a8fd69d7a2b540e3b4f9e808810fc1ddc0 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Thu, 22 Aug 2013 17:26:02 -0700 Subject: [PATCH 26/26] fix 32bit mac build error --- src/libstd/rt/uv/uvio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index b1b5f9f919c3b..f794c0a2bec5f 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -31,7 +31,7 @@ use rt::uv::idle::IdleWatcher; use rt::uv::net::{UvIpv4SocketAddr, UvIpv6SocketAddr}; use unstable::sync::Exclusive; use super::super::io::support::PathLike; -use libc::{lseek, c_long, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, +use libc::{lseek, off_t, O_CREAT, O_APPEND, O_TRUNC, O_RDWR, O_RDONLY, O_WRONLY, S_IRUSR, S_IWUSR}; use rt::io::{FileMode, FileAccess, OpenOrCreate, Open, Create, CreateOrTruncate, Append, Truncate, Read, Write, ReadWrite}; @@ -1148,7 +1148,7 @@ impl UvFileStream { Result{ #[fixed_stack_segment]; #[inline(never)]; unsafe { - match lseek((*self.fd), pos as c_long, whence) { + match lseek((*self.fd), pos as off_t, whence) { -1 => { Err(IoError { kind: OtherIoError,