Skip to content

Commit a901b16

Browse files
committed
std: bootstrapping libuv-based fileio in newrt... open & close
the test "touch"es a new file
1 parent f858452 commit a901b16

File tree

4 files changed

+232
-14
lines changed

4 files changed

+232
-14
lines changed

src/libstd/rt/uv/file.rs

Lines changed: 160 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,30 +11,87 @@
1111
use prelude::*;
1212
use ptr::null;
1313
use libc::c_void;
14-
use rt::uv::{Request, NativeHandle, Loop, FsCallback};
14+
use rt::uv::{Request, NativeHandle, Loop, FsCallback,
15+
status_to_maybe_uv_error_with_loop};
1516
use rt::uv::uvll;
1617
use rt::uv::uvll::*;
18+
use path::Path;
19+
use cast::transmute;
20+
use libc::{c_int};
1721

1822
pub struct FsRequest(*uvll::uv_fs_t);
1923
impl Request for FsRequest;
2024

25+
#[allow(non_camel_case_types)]
26+
pub enum UvFileFlag {
27+
O_RDONLY,
28+
O_WRONLY,
29+
O_RDWR,
30+
O_CREAT,
31+
O_TRUNC
32+
}
33+
pub fn map_flag(v: UvFileFlag) -> int {
34+
unsafe {
35+
match v {
36+
O_RDONLY => uvll::get_O_RDONLY() as int,
37+
O_WRONLY => uvll::get_O_WRONLY() as int,
38+
O_RDWR => uvll::get_O_RDWR() as int,
39+
O_CREAT => uvll::get_O_CREAT() as int,
40+
O_TRUNC => uvll::get_O_TRUNC() as int
41+
}
42+
}
43+
}
44+
45+
pub struct RequestData {
46+
complete_cb: Option<FsCallback>
47+
}
48+
2149
impl FsRequest {
22-
fn new() -> FsRequest {
50+
pub fn new(cb: Option<FsCallback>) -> FsRequest {
2351
let fs_req = unsafe { malloc_req(UV_FS) };
2452
assert!(fs_req.is_not_null());
25-
let fs_req = fs_req as *uvll::uv_write_t;
26-
unsafe { uvll::set_data_for_req(fs_req, null::<()>()); }
27-
NativeHandle::from_native_handle(fs_req)
53+
let fs_req: FsRequest = NativeHandle::from_native_handle(fs_req);
54+
fs_req.install_req_data(cb);
55+
fs_req
56+
}
57+
58+
pub fn install_req_data(&self, cb: Option<FsCallback>) {
59+
let fs_req = (self.native_handle()) as *uvll::uv_write_t;
60+
let data = ~RequestData {
61+
complete_cb: cb
62+
};
63+
unsafe {
64+
let data = transmute::<~RequestData, *c_void>(data);
65+
uvll::set_data_for_req(fs_req, data);
66+
}
2867
}
2968

30-
fn delete(self) {
31-
unsafe { free_req(self.native_handle() as *c_void) }
69+
fn get_req_data<'r>(&'r mut self) -> &'r mut RequestData {
70+
unsafe {
71+
let data = uvll::get_data_for_req((self.native_handle()));
72+
let data = transmute::<&*c_void, &mut ~RequestData>(&data);
73+
return &mut **data;
74+
}
3275
}
3376

34-
fn open(&mut self, _loop_: &Loop, _cb: FsCallback) {
77+
pub fn get_result(&mut self) -> c_int {
78+
unsafe {
79+
uvll::get_result_from_fs_req(self.native_handle())
80+
}
3581
}
3682

37-
fn close(&mut self, _loop_: &Loop, _cb: FsCallback) {
83+
pub fn get_loop(&self) -> Loop {
84+
unsafe { Loop{handle:uvll::get_loop_from_fs_req(self.native_handle())} }
85+
}
86+
87+
fn cleanup_and_delete(self) {
88+
unsafe {
89+
uvll::fs_req_cleanup(self.native_handle());
90+
let data = uvll::get_data_for_uv_handle(self.native_handle());
91+
let _data = transmute::<*c_void, ~RequestData>(data);
92+
uvll::set_data_for_uv_handle(self.native_handle(), null::<()>());
93+
free_req(self.native_handle() as *c_void)
94+
}
3895
}
3996
}
4097

@@ -46,3 +103,97 @@ impl NativeHandle<*uvll::uv_fs_t> for FsRequest {
46103
match self { &FsRequest(ptr) => ptr }
47104
}
48105
}
106+
107+
pub struct FileDescriptor(c_int);
108+
impl FileDescriptor {
109+
fn new(fd: c_int) -> FileDescriptor {
110+
FileDescriptor(fd)
111+
}
112+
113+
pub fn from_open_req(req: &mut FsRequest) -> FileDescriptor {
114+
FileDescriptor::new(req.get_result())
115+
}
116+
117+
pub fn open(loop_: Loop, path: Path, flags: int, mode: int,
118+
cb: FsCallback) -> int {
119+
let req = FsRequest::new(Some(cb));
120+
path.to_str().to_c_str().with_ref(|p| unsafe {
121+
uvll::fs_open(loop_.native_handle(),
122+
req.native_handle(), p, flags, mode, complete_cb) as int
123+
})
124+
125+
}
126+
127+
fn close(self, loop_: Loop, cb: FsCallback) -> int {
128+
let req = FsRequest::new(Some(cb));
129+
unsafe {
130+
uvll::fs_close(loop_.native_handle(), req.native_handle(),
131+
self.native_handle(), complete_cb) as int
132+
}
133+
}
134+
}
135+
extern fn complete_cb(req: *uv_fs_t) {
136+
let mut req: FsRequest = NativeHandle::from_native_handle(req);
137+
let loop_ = req.get_loop();
138+
// pull the user cb out of the req data
139+
let cb = {
140+
let data = req.get_req_data();
141+
assert!(data.complete_cb.is_some());
142+
// option dance, option dance. oooooh yeah.
143+
data.complete_cb.take_unwrap()
144+
};
145+
// in uv_fs_open calls, the result will be the fd in the
146+
// case of success, otherwise it's -1 indicating an error
147+
let result = req.get_result();
148+
let status = status_to_maybe_uv_error_with_loop(
149+
loop_.native_handle(), result);
150+
// we have a req and status, call the user cb..
151+
// only giving the user a ref to the FsRequest, as we
152+
// have to clean it up, afterwards (and they aren't really
153+
// reusable, anyways
154+
cb(&mut req, status);
155+
// clean up the req (and its data!) after calling the user cb
156+
req.cleanup_and_delete();
157+
}
158+
159+
impl NativeHandle<c_int> for FileDescriptor {
160+
fn from_native_handle(handle: c_int) -> FileDescriptor {
161+
FileDescriptor(handle)
162+
}
163+
fn native_handle(&self) -> c_int {
164+
match self { &FileDescriptor(ptr) => ptr }
165+
}
166+
}
167+
168+
mod test {
169+
use super::*;
170+
//use rt::test::*;
171+
use unstable::run_in_bare_thread;
172+
use path::Path;
173+
use rt::uv::Loop;
174+
175+
// this is equiv to touch, i guess?
176+
fn file_test_touch_impl() {
177+
debug!("hello?")
178+
do run_in_bare_thread {
179+
debug!("In bare thread")
180+
let loop_ = Loop::new();
181+
let flags = map_flag(O_RDWR) |
182+
map_flag(O_CREAT) | map_flag(O_TRUNC);
183+
do FileDescriptor::open(loop_, Path("./foo.txt"), flags, 0644)
184+
|req, uverr| {
185+
let loop_ = req.get_loop();
186+
assert!(uverr.is_none());
187+
let fd = FileDescriptor::from_open_req(req);
188+
do fd.close(loop_) |_, uverr| {
189+
assert!(uverr.is_none());
190+
};
191+
};
192+
}
193+
}
194+
195+
#[test]
196+
fn file_test_touch() {
197+
file_test_touch_impl();
198+
}
199+
}

src/libstd/rt/uv/mod.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use rt::io::IoError;
5353

5454
//#[cfg(test)] use unstable::run_in_bare_thread;
5555

56-
pub use self::file::FsRequest;
56+
pub use self::file::{FsRequest};
5757
pub use self::net::{StreamWatcher, TcpWatcher, UdpWatcher};
5858
pub use self::idle::IdleWatcher;
5959
pub use self::timer::TimerWatcher;
@@ -125,7 +125,7 @@ pub type ReadCallback = ~fn(StreamWatcher, int, Buf, Option<UvError>);
125125
pub type NullCallback = ~fn();
126126
pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
127127
pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
128-
pub type FsCallback = ~fn(FsRequest, Option<UvError>);
128+
pub type FsCallback = ~fn(&mut FsRequest, Option<UvError>);
129129
pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
130130
pub type AsyncCallback = ~fn(AsyncWatcher, Option<UvError>);
131131
pub type UdpReceiveCallback = ~fn(UdpWatcher, int, Buf, SocketAddr, uint, Option<UvError>);
@@ -281,6 +281,20 @@ pub fn uv_error_to_io_error(uverr: UvError) -> IoError {
281281
}
282282
}
283283
284+
/// Given a uv handle, convert a callback status to a UvError
285+
pub fn status_to_maybe_uv_error_with_loop(
286+
loop_: *uvll::uv_loop_t,
287+
status: c_int) -> Option<UvError> {
288+
if status != -1 {
289+
None
290+
} else {
291+
unsafe {
292+
rtdebug!("loop: %x", loop_ as uint);
293+
let err = uvll::last_error(loop_);
294+
Some(UvError(err))
295+
}
296+
}
297+
}
284298
/// Given a uv handle, convert a callback status to a UvError
285299
pub fn status_to_maybe_uv_error<T, U: Watcher + NativeHandle<*T>>(handle: U,
286300
status: c_int) -> Option<UvError> {
@@ -290,9 +304,7 @@ pub fn status_to_maybe_uv_error<T, U: Watcher + NativeHandle<*T>>(handle: U,
290304
unsafe {
291305
rtdebug!("handle: %x", handle.native_handle() as uint);
292306
let loop_ = uvll::get_loop_for_uv_handle(handle.native_handle());
293-
rtdebug!("loop: %x", loop_ as uint);
294-
let err = uvll::last_error(loop_);
295-
Some(UvError(err))
307+
status_to_maybe_uv_error_with_loop(loop_, status)
296308
}
297309
}
298310
}

src/libstd/rt/uv/uvll.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,40 @@ pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint {
617617
return rust_uv_ip6_port(addr);
618618
}
619619

620+
pub unsafe fn fs_open(loop_ptr: *uv_loop_t, req: *uv_fs_t, path: *c_char, flags: int, mode: int,
621+
cb: *u8) -> c_int {
622+
rust_uv_fs_open(loop_ptr, req, path, flags as c_int, mode as c_int, cb)
623+
}
624+
pub unsafe fn fs_close(loop_ptr: *uv_loop_t, req: *uv_fs_t, fd: c_int,
625+
cb: *u8) -> c_int {
626+
rust_uv_fs_close(loop_ptr, req, fd, cb)
627+
}
628+
pub unsafe fn fs_req_cleanup(req: *uv_fs_t) {
629+
rust_uv_fs_req_cleanup(req);
630+
}
631+
620632
// data access helpers
633+
pub unsafe fn get_O_RDONLY() -> c_int {
634+
rust_uv_get_O_RDONLY()
635+
}
636+
pub unsafe fn get_O_WRONLY() -> c_int {
637+
rust_uv_get_O_WRONLY()
638+
}
639+
pub unsafe fn get_O_RDWR() -> c_int {
640+
rust_uv_get_O_RDWR()
641+
}
642+
pub unsafe fn get_O_CREAT() -> c_int {
643+
rust_uv_get_O_CREAT()
644+
}
645+
pub unsafe fn get_O_TRUNC() -> c_int {
646+
rust_uv_get_O_TRUNC()
647+
}
648+
pub unsafe fn get_result_from_fs_req(req: *uv_fs_t) -> c_int {
649+
rust_uv_get_result_from_fs_req(req)
650+
}
651+
pub unsafe fn get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t {
652+
rust_uv_get_loop_from_fs_req(req)
653+
}
621654
pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
622655
#[fixed_stack_segment]; #[inline(never)];
623656

@@ -784,6 +817,18 @@ extern {
784817
fn rust_uv_timer_start(timer_handle: *uv_timer_t, cb: uv_timer_cb, timeout: libc::uint64_t,
785818
repeat: libc::uint64_t) -> c_int;
786819
fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int;
820+
fn rust_uv_fs_open(loop_ptr: *c_void, req: *uv_fs_t, path: *c_char,
821+
flags: c_int, mode: c_int, cb: *u8) -> c_int;
822+
fn rust_uv_fs_close(loop_ptr: *c_void, req: *uv_fs_t, fd: c_int,
823+
cb: *u8) -> c_int;
824+
fn rust_uv_fs_req_cleanup(req: *uv_fs_t);
825+
fn rust_uv_get_O_RDONLY() -> c_int;
826+
fn rust_uv_get_O_WRONLY() -> c_int;
827+
fn rust_uv_get_O_RDWR() -> c_int;
828+
fn rust_uv_get_O_CREAT() -> c_int;
829+
fn rust_uv_get_O_TRUNC() -> c_int;
830+
fn rust_uv_get_result_from_fs_req(req: *uv_fs_t) -> c_int;
831+
fn rust_uv_get_loop_from_fs_req(req: *uv_fs_t) -> *uv_loop_t;
787832

788833
fn rust_uv_get_stream_handle_from_connect_req(connect_req: *uv_connect_t) -> *uv_stream_t;
789834
fn rust_uv_get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t;

src/rt/rustrt.def.in

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ rust_uv_idle_delete
108108
rust_uv_idle_init
109109
rust_uv_idle_start
110110
rust_uv_idle_stop
111+
rust_uv_fs_open
112+
rust_uv_fs_close
113+
rust_uv_get_O_RDONLY
114+
rust_uv_get_O_WRONLY
115+
rust_uv_get_O_RDWR
116+
rust_uv_get_O_CREAT
117+
rust_uv_get_O_TRUNC
118+
rust_uv_get_result_from_fs_req
119+
rust_uv_get_loop_from_fs_req
120+
rust_uv_fs_req_cleanup
111121
rust_dbg_lock_create
112122
rust_dbg_lock_destroy
113123
rust_dbg_lock_lock

0 commit comments

Comments
 (0)