diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2013-05-17 10:45:09 -0700 |
|---|---|---|
| committer | Patrick Walton <pcwalton@mimiga.net> | 2013-05-22 21:57:05 -0700 |
| commit | 0c820d4123c754522b0655e9e74f692c55685bfa (patch) | |
| tree | 7dbb86c30b451217b4e8f75173043744fe3255ff /src/libcore/rt | |
| parent | 565942b145efbf6c1d1f66db46423d721b55d32c (diff) | |
libstd: Rename libcore to libstd and libstd to libextra; update makefiles.
This only changes the directory names; it does not change the "real" metadata names.
Diffstat (limited to 'src/libcore/rt')
32 files changed, 0 insertions, 5975 deletions
diff --git a/src/libcore/rt/context.rs b/src/libcore/rt/context.rs deleted file mode 100644 index 0d011ce42ba..00000000000 --- a/src/libcore/rt/context.rs +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use option::*; -use super::stack::StackSegment; -use libc::c_void; -use cast::{transmute, transmute_mut_unsafe, - transmute_region, transmute_mut_region}; - -// XXX: Registers is boxed so that it is 16-byte aligned, for storing -// SSE regs. It would be marginally better not to do this. In C++ we -// use an attribute on a struct. -// XXX: It would be nice to define regs as `~Option<Registers>` since -// the registers are sometimes empty, but the discriminant would -// then misalign the regs again. -pub struct Context { - /// The context entry point, saved here for later destruction - start: Option<~~fn()>, - /// Hold the registers while the task or scheduler is suspended - regs: ~Registers -} - -pub impl Context { - fn empty() -> Context { - Context { - start: None, - regs: new_regs() - } - } - - /// Create a new context that will resume execution by running ~fn() - fn new(start: ~fn(), stack: &mut StackSegment) -> Context { - // XXX: Putting main into a ~ so it's a thin pointer and can - // be passed to the spawn function. Another unfortunate - // allocation - let start = ~start; - - // The C-ABI function that is the task entry point - extern fn task_start_wrapper(f: &~fn()) { (*f)() } - - let fp: *c_void = task_start_wrapper as *c_void; - let argp: *c_void = unsafe { transmute::<&~fn(), *c_void>(&*start) }; - let sp: *uint = stack.end(); - let sp: *mut uint = unsafe { transmute_mut_unsafe(sp) }; - - // Save and then immediately load the current context, - // which we will then modify to call the given function when restored - let mut regs = new_regs(); - unsafe { - swap_registers(transmute_mut_region(&mut *regs), transmute_region(&*regs)) - }; - - initialize_call_frame(&mut *regs, fp, argp, sp); - - return Context { - start: Some(start), - regs: regs - } - } - - /* Switch contexts - - Suspend the current execution context and resume another by - saving the registers values of the executing thread to a Context - then loading the registers from a previously saved Context. - */ - fn swap(out_context: &mut Context, in_context: &Context) { - let out_regs: &mut Registers = match out_context { - &Context { regs: ~ref mut r, _ } => r - }; - let in_regs: &Registers = match in_context { - &Context { regs: ~ref r, _ } => r - }; - - unsafe { swap_registers(out_regs, in_regs) }; - } -} - -extern { - #[rust_stack] - fn swap_registers(out_regs: *mut Registers, in_regs: *Registers); -} - -#[cfg(target_arch = "x86")] -struct Registers { - eax: u32, ebx: u32, ecx: u32, edx: u32, - ebp: u32, esi: u32, edi: u32, esp: u32, - cs: u16, ds: u16, ss: u16, es: u16, fs: u16, gs: u16, - eflags: u32, eip: u32 -} - -#[cfg(target_arch = "x86")] -fn new_regs() -> ~Registers { - ~Registers { - eax: 0, ebx: 0, ecx: 0, edx: 0, - ebp: 0, esi: 0, edi: 0, esp: 0, - cs: 0, ds: 0, ss: 0, es: 0, fs: 0, gs: 0, - eflags: 0, eip: 0 - } -} - -#[cfg(target_arch = "x86")] -fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) { - - let sp = align_down(sp); - let sp = mut_offset(sp, -4); - - unsafe { *sp = arg as uint }; - let sp = mut_offset(sp, -1); - unsafe { *sp = 0 }; // The final return address - - regs.esp = sp as u32; - regs.eip = fptr as u32; - - // Last base pointer on the stack is 0 - regs.ebp = 0; -} - -#[cfg(target_arch = "x86_64")] -type Registers = [uint, ..22]; - -#[cfg(target_arch = "x86_64")] -fn new_regs() -> ~Registers { ~([0, .. 22]) } - -#[cfg(target_arch = "x86_64")] -fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) { - - // Redefinitions from regs.h - static RUSTRT_ARG0: uint = 3; - static RUSTRT_RSP: uint = 1; - static RUSTRT_IP: uint = 8; - static RUSTRT_RBP: uint = 2; - - let sp = align_down(sp); - let sp = mut_offset(sp, -1); - - // The final return address. 0 indicates the bottom of the stack - unsafe { *sp = 0; } - - rtdebug!("creating call frame"); - rtdebug!("fptr %x", fptr as uint); - rtdebug!("arg %x", arg as uint); - rtdebug!("sp %x", sp as uint); - - regs[RUSTRT_ARG0] = arg as uint; - regs[RUSTRT_RSP] = sp as uint; - regs[RUSTRT_IP] = fptr as uint; - - // Last base pointer on the stack should be 0 - regs[RUSTRT_RBP] = 0; -} - -#[cfg(target_arch = "arm")] -type Registers = [uint, ..32]; - -#[cfg(target_arch = "arm")] -fn new_regs() -> ~Registers { ~([0, .. 32]) } - -#[cfg(target_arch = "arm")] -fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) { - let sp = align_down(sp); - // sp of arm eabi is 8-byte aligned - let sp = mut_offset(sp, -2); - - // The final return address. 0 indicates the bottom of the stack - unsafe { *sp = 0; } - - regs[0] = arg as uint; // r0 - regs[13] = sp as uint; // #53 sp, r13 - regs[14] = fptr as uint; // #60 pc, r15 --> lr -} - -#[cfg(target_arch = "mips")] -type Registers = [uint, ..32]; - -#[cfg(target_arch = "mips")] -fn new_regs() -> ~Registers { ~([0, .. 32]) } - -#[cfg(target_arch = "mips")] -fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: *mut uint) { - let sp = align_down(sp); - // sp of mips o32 is 8-byte aligned - let sp = mut_offset(sp, -2); - - // The final return address. 0 indicates the bottom of the stack - unsafe { *sp = 0; } - - regs[4] = arg as uint; - regs[29] = sp as uint; - regs[25] = fptr as uint; - regs[31] = fptr as uint; -} - -fn align_down(sp: *mut uint) -> *mut uint { - unsafe { - let sp: uint = transmute(sp); - let sp = sp & !(16 - 1); - transmute::<uint, *mut uint>(sp) - } -} - -// XXX: ptr::offset is positive ints only -#[inline(always)] -pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T { - use core::sys::size_of; - (ptr as int + count * (size_of::<T>() as int)) as *mut T -} diff --git a/src/libcore/rt/env.rs b/src/libcore/rt/env.rs deleted file mode 100644 index 1d7ff173149..00000000000 --- a/src/libcore/rt/env.rs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Runtime environment settings - -use libc::{size_t, c_char, c_int}; - -pub struct Environment { - /// The number of threads to use by default - num_sched_threads: size_t, - /// The minimum size of a stack segment - min_stack_size: size_t, - /// The maximum amount of total stack per task before aborting - max_stack_size: size_t, - /// The default logging configuration - logspec: *c_char, - /// Record and report detailed information about memory leaks - detailed_leaks: bool, - /// Seed the random number generator - rust_seed: *c_char, - /// Poison allocations on free - poison_on_free: bool, - /// The argc value passed to main - argc: c_int, - /// The argv value passed to main - argv: **c_char, - /// Print GC debugging info (true if env var RUST_DEBUG_MEM is set) - debug_mem: bool, - /// Print GC debugging info (true if env var RUST_DEBUG_BORROW is set) - debug_borrow: bool, -} - -/// Get the global environment settings -/// # Safety Note -/// This will abort the process if run outside of task context -pub fn get() -> &Environment { - unsafe { rust_get_rt_env() } -} - -extern { - fn rust_get_rt_env() -> &Environment; -} diff --git a/src/libcore/rt/global_heap.rs b/src/libcore/rt/global_heap.rs deleted file mode 100644 index ce7ff87b445..00000000000 --- a/src/libcore/rt/global_heap.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use sys::{TypeDesc, size_of}; -use libc::{c_void, size_t, uintptr_t}; -use c_malloc = libc::malloc; -use c_free = libc::free; -use managed::raw::{BoxHeaderRepr, BoxRepr}; -use cast::transmute; -use unstable::intrinsics::{atomic_xadd,atomic_xsub}; -use ptr::null; -use intrinsic::TyDesc; - -pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void { - assert!(td.is_not_null()); - - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); - - // FIXME #3475: Converting between our two different tydesc types - let td: *TyDesc = transmute(td); - - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); - - let exchange_count = &mut *exchange_count_ptr(); - atomic_xadd(exchange_count, 1); - - return transmute(box); -} -/** -Thin wrapper around libc::malloc, none of the box header -stuff in exchange_alloc::malloc -*/ -pub unsafe fn malloc_raw(size: uint) -> *c_void { - let p = c_malloc(size as size_t); - if p.is_null() { - fail!("Failure in malloc_raw: result ptr is null"); - } - p -} - -pub unsafe fn free(ptr: *c_void) { - let exchange_count = &mut *exchange_count_ptr(); - atomic_xsub(exchange_count, 1); - - assert!(ptr.is_not_null()); - c_free(ptr); -} -///Thin wrapper around libc::free, as with exchange_alloc::malloc_raw -pub unsafe fn free_raw(ptr: *c_void) { - c_free(ptr); -} - -fn get_box_size(body_size: uint, body_align: uint) -> uint { - let header_size = size_of::<BoxHeaderRepr>(); - // FIXME (#2699): This alignment calculation is suspicious. Is it right? - let total_size = align_to(header_size, body_align) + body_size; - return total_size; -} - -// Rounds |size| to the nearest |alignment|. Invariant: |alignment| is a power -// of two. -fn align_to(size: uint, align: uint) -> uint { - assert!(align != 0); - (size + align - 1) & !(align - 1) -} - -fn exchange_count_ptr() -> *mut int { - // XXX: Need mutable globals - unsafe { transmute(&rust_exchange_count) } -} - -extern { - static rust_exchange_count: uintptr_t; -} diff --git a/src/libcore/rt/io/comm_adapters.rs b/src/libcore/rt/io/comm_adapters.rs deleted file mode 100644 index 7e891f1718e..00000000000 --- a/src/libcore/rt/io/comm_adapters.rs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::{Reader, Writer}; - -struct PortReader<P>; - -impl<P: GenericPort<~[u8]>> PortReader<P> { - pub fn new(_port: P) -> PortReader<P> { fail!() } -} - -impl<P: GenericPort<~[u8]>> Reader for PortReader<P> { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -struct ChanWriter<C>; - -impl<C: GenericChan<~[u8]>> ChanWriter<C> { - pub fn new(_chan: C) -> ChanWriter<C> { fail!() } -} - -impl<C: GenericChan<~[u8]>> Writer for ChanWriter<C> { - pub fn write(&mut self, _buf: &[u8]) { fail!() } - - pub fn flush(&mut self) { fail!() } -} - -struct ReaderPort<R>; - -impl<R: Reader> ReaderPort<R> { - pub fn new(_reader: R) -> ReaderPort<R> { fail!() } -} - -impl<R: Reader> GenericPort<~[u8]> for ReaderPort<R> { - fn recv(&self) -> ~[u8] { fail!() } - - fn try_recv(&self) -> Option<~[u8]> { fail!() } -} - -struct WriterChan<W>; - -impl<W: Writer> WriterChan<W> { - pub fn new(_writer: W) -> WriterChan<W> { fail!() } -} - -impl<W: Writer> GenericChan<~[u8]> for WriterChan<W> { - fn send(&self, _x: ~[u8]) { fail!() } -} diff --git a/src/libcore/rt/io/extensions.rs b/src/libcore/rt/io/extensions.rs deleted file mode 100644 index ceff2ecd77d..00000000000 --- a/src/libcore/rt/io/extensions.rs +++ /dev/null @@ -1,903 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Utility mixins that apply to all Readers and Writers - -// XXX: Not sure how this should be structured -// XXX: Iteration should probably be considered separately - -use uint; -use int; -use vec; -use rt::io::{Reader, Writer}; -use rt::io::{read_error, standard_error, EndOfFile, DEFAULT_BUF_SIZE}; -use option::{Option, Some, None}; -use unstable::finally::Finally; -use util; -use cast; -use io::{u64_to_le_bytes, u64_to_be_bytes}; - -pub trait ReaderUtil { - - /// Reads a single byte. Returns `None` on EOF. - /// - /// # Failure - /// - /// Raises the same conditions as the `read` method. Returns - /// `None` if the condition is handled. - fn read_byte(&mut self) -> Option<u8>; - - /// Reads `len` bytes and appends them to a vector. - /// - /// May push fewer than the requested number of bytes on error - /// or EOF. Returns true on success, false on EOF or error. - /// - /// # Failure - /// - /// Raises the same conditions as `read`. Additionally raises `read_error` - /// on EOF. If `read_error` is handled then `push_bytes` may push less - /// than the requested number of bytes. - fn push_bytes(&mut self, buf: &mut ~[u8], len: uint); - - /// Reads `len` bytes and gives you back a new vector of length `len` - /// - /// # Failure - /// - /// Raises the same conditions as `read`. Additionally raises `read_error` - /// on EOF. If `read_error` is handled then the returned vector may - /// contain less than the requested number of bytes. - fn read_bytes(&mut self, len: uint) -> ~[u8]; - - /// Reads all remaining bytes from the stream. - /// - /// # Failure - /// - /// Raises the same conditions as the `read` method. - fn read_to_end(&mut self) -> ~[u8]; - -} - -pub trait ReaderByteConversions { - /// Reads `n` little-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_uint_n(&mut self, nbytes: uint) -> u64; - - /// Reads `n` little-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_le_int_n(&mut self, nbytes: uint) -> i64; - - /// Reads `n` big-endian unsigned integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_uint_n(&mut self, nbytes: uint) -> u64; - - /// Reads `n` big-endian signed integer bytes. - /// - /// `n` must be between 1 and 8, inclusive. - fn read_be_int_n(&mut self, nbytes: uint) -> i64; - - /// Reads a little-endian unsigned integer. - /// - /// The number of bytes returned is system-dependant. - fn read_le_uint(&mut self) -> uint; - - /// Reads a little-endian integer. - /// - /// The number of bytes returned is system-dependant. - fn read_le_int(&mut self) -> int; - - /// Reads a big-endian unsigned integer. - /// - /// The number of bytes returned is system-dependant. - fn read_be_uint(&mut self) -> uint; - - /// Reads a big-endian integer. - /// - /// The number of bytes returned is system-dependant. - fn read_be_int(&mut self) -> int; - - /// Reads a big-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_be_u64(&mut self) -> u64; - - /// Reads a big-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_be_u32(&mut self) -> u32; - - /// Reads a big-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_be_u16(&mut self) -> u16; - - /// Reads a big-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_be_i64(&mut self) -> i64; - - /// Reads a big-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_be_i32(&mut self) -> i32; - - /// Reads a big-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_be_i16(&mut self) -> i16; - - /// Reads a big-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_be_f64(&mut self) -> f64; - - /// Reads a big-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_be_f32(&mut self) -> f32; - - /// Reads a little-endian `u64`. - /// - /// `u64`s are 8 bytes long. - fn read_le_u64(&mut self) -> u64; - - /// Reads a little-endian `u32`. - /// - /// `u32`s are 4 bytes long. - fn read_le_u32(&mut self) -> u32; - - /// Reads a little-endian `u16`. - /// - /// `u16`s are 2 bytes long. - fn read_le_u16(&mut self) -> u16; - - /// Reads a little-endian `i64`. - /// - /// `i64`s are 8 bytes long. - fn read_le_i64(&mut self) -> i64; - - /// Reads a little-endian `i32`. - /// - /// `i32`s are 4 bytes long. - fn read_le_i32(&mut self) -> i32; - - /// Reads a little-endian `i16`. - /// - /// `i16`s are 2 bytes long. - fn read_le_i16(&mut self) -> i16; - - /// Reads a little-endian `f64`. - /// - /// `f64`s are 8 byte, IEEE754 double-precision floating point numbers. - fn read_le_f64(&mut self) -> f64; - - /// Reads a little-endian `f32`. - /// - /// `f32`s are 4 byte, IEEE754 single-precision floating point numbers. - fn read_le_f32(&mut self) -> f32; - - /// Read a u8. - /// - /// `u8`s are 1 byte. - fn read_u8(&mut self) -> u8; - - /// Read an i8. - /// - /// `i8`s are 1 byte. - fn read_i8(&mut self) -> i8; - -} - -pub trait WriterByteConversions { - /// Write the result of passing n through `int::to_str_bytes`. - fn write_int(&mut self, n: int); - - /// Write the result of passing n through `uint::to_str_bytes`. - fn write_uint(&mut self, n: uint); - - /// Write a little-endian uint (number of bytes depends on system). - fn write_le_uint(&mut self, n: uint); - - /// Write a little-endian int (number of bytes depends on system). - fn write_le_int(&mut self, n: int); - - /// Write a big-endian uint (number of bytes depends on system). - fn write_be_uint(&mut self, n: uint); - - /// Write a big-endian int (number of bytes depends on system). - fn write_be_int(&mut self, n: int); - - /// Write a big-endian u64 (8 bytes). - fn write_be_u64_(&mut self, n: u64); - - /// Write a big-endian u32 (4 bytes). - fn write_be_u32(&mut self, n: u32); - - /// Write a big-endian u16 (2 bytes). - fn write_be_u16(&mut self, n: u16); - - /// Write a big-endian i64 (8 bytes). - fn write_be_i64(&mut self, n: i64); - - /// Write a big-endian i32 (4 bytes). - fn write_be_i32(&mut self, n: i32); - - /// Write a big-endian i16 (2 bytes). - fn write_be_i16(&mut self, n: i16); - - /// Write a big-endian IEEE754 double-precision floating-point (8 bytes). - fn write_be_f64(&mut self, f: f64); - - /// Write a big-endian IEEE754 single-precision floating-point (4 bytes). - fn write_be_f32(&mut self, f: f32); - - /// Write a little-endian u64 (8 bytes). - fn write_le_u64_(&mut self, n: u64); - - /// Write a little-endian u32 (4 bytes). - fn write_le_u32(&mut self, n: u32); - - /// Write a little-endian u16 (2 bytes). - fn write_le_u16(&mut self, n: u16); - - /// Write a little-endian i64 (8 bytes). - fn write_le_i64(&mut self, n: i64); - - /// Write a little-endian i32 (4 bytes). - fn write_le_i32(&mut self, n: i32); - - /// Write a little-endian i16 (2 bytes). - fn write_le_i16(&mut self, n: i16); - - /// Write a little-endian IEEE754 double-precision floating-point - /// (8 bytes). - fn write_le_f64(&mut self, f: f64); - - /// Write a litten-endian IEEE754 single-precision floating-point - /// (4 bytes). - fn write_le_f32(&mut self, f: f32); - - /// Write a u8 (1 byte). - fn write_u8(&mut self, n: u8); - - /// Write a i8 (1 byte). - fn write_i8(&mut self, n: i8); -} - -impl<T: Reader> ReaderUtil for T { - fn read_byte(&mut self) -> Option<u8> { - let mut buf = [0]; - match self.read(buf) { - Some(0) => { - debug!("read 0 bytes. trying again"); - self.read_byte() - } - Some(1) => Some(buf[0]), - Some(_) => util::unreachable(), - None => None - } - } - - fn push_bytes(&mut self, buf: &mut ~[u8], len: uint) { - unsafe { - let start_len = buf.len(); - let mut total_read = 0; - - vec::reserve_at_least(buf, start_len + len); - vec::raw::set_len(buf, start_len + len); - - do (|| { - while total_read < len { - let slice = vec::mut_slice(*buf, start_len + total_read, buf.len()); - match self.read(slice) { - Some(nread) => { - total_read += nread; - } - None => { - read_error::cond.raise(standard_error(EndOfFile)); - break; - } - } - } - }).finally { - vec::raw::set_len(buf, start_len + total_read); - } - } - } - - fn read_bytes(&mut self, len: uint) -> ~[u8] { - let mut buf = vec::with_capacity(len); - self.push_bytes(&mut buf, len); - return buf; - } - - fn read_to_end(&mut self) -> ~[u8] { - let mut buf = vec::with_capacity(DEFAULT_BUF_SIZE); - let mut keep_reading = true; - do read_error::cond.trap(|e| { - if e.kind == EndOfFile { - keep_reading = false; - } else { - read_error::cond.raise(e) - } - }).in { - while keep_reading { - self.push_bytes(&mut buf, DEFAULT_BUF_SIZE) - } - } - return buf; - } -} - -impl<T: Reader> ReaderByteConversions for T { - fn read_le_uint_n(&mut self, nbytes: uint) -> u64 { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0u64, pos = 0, i = nbytes; - while i > 0 { - val += (self.read_u8() as u64) << pos; - pos += 8; - i -= 1; - } - val - } - - fn read_le_int_n(&mut self, nbytes: uint) -> i64 { - extend_sign(self.read_le_uint_n(nbytes), nbytes) - } - - fn read_be_uint_n(&mut self, nbytes: uint) -> u64 { - assert!(nbytes > 0 && nbytes <= 8); - - let mut val = 0u64, i = nbytes; - while i > 0 { - i -= 1; - val += (self.read_u8() as u64) << i * 8; - } - val - } - - fn read_be_int_n(&mut self, nbytes: uint) -> i64 { - extend_sign(self.read_be_uint_n(nbytes), nbytes) - } - - fn read_le_uint(&mut self) -> uint { - self.read_le_uint_n(uint::bytes) as uint - } - - fn read_le_int(&mut self) -> int { - self.read_le_int_n(int::bytes) as int - } - - fn read_be_uint(&mut self) -> uint { - self.read_be_uint_n(uint::bytes) as uint - } - - fn read_be_int(&mut self) -> int { - self.read_be_int_n(int::bytes) as int - } - - fn read_be_u64(&mut self) -> u64 { - self.read_be_uint_n(8) as u64 - } - - fn read_be_u32(&mut self) -> u32 { - self.read_be_uint_n(4) as u32 - } - - fn read_be_u16(&mut self) -> u16 { - self.read_be_uint_n(2) as u16 - } - - fn read_be_i64(&mut self) -> i64 { - self.read_be_int_n(8) as i64 - } - - fn read_be_i32(&mut self) -> i32 { - self.read_be_int_n(4) as i32 - } - - fn read_be_i16(&mut self) -> i16 { - self.read_be_int_n(2) as i16 - } - - fn read_be_f64(&mut self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_be_u64()) - } - } - - fn read_be_f32(&mut self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_be_u32()) - } - } - - fn read_le_u64(&mut self) -> u64 { - self.read_le_uint_n(8) as u64 - } - - fn read_le_u32(&mut self) -> u32 { - self.read_le_uint_n(4) as u32 - } - - fn read_le_u16(&mut self) -> u16 { - self.read_le_uint_n(2) as u16 - } - - fn read_le_i64(&mut self) -> i64 { - self.read_le_int_n(8) as i64 - } - - fn read_le_i32(&mut self) -> i32 { - self.read_le_int_n(4) as i32 - } - - fn read_le_i16(&mut self) -> i16 { - self.read_le_int_n(2) as i16 - } - - fn read_le_f64(&mut self) -> f64 { - unsafe { - cast::transmute::<u64, f64>(self.read_le_u64()) - } - } - - fn read_le_f32(&mut self) -> f32 { - unsafe { - cast::transmute::<u32, f32>(self.read_le_u32()) - } - } - - fn read_u8(&mut self) -> u8 { - match self.read_byte() { - Some(b) => b as u8, - None => 0 - } - } - - fn read_i8(&mut self) -> i8 { - match self.read_byte() { - Some(b) => b as i8, - None => 0 - } - } - -} - -impl<T: Writer> WriterByteConversions for T { - fn write_int(&mut self, n: int) { - int::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - - fn write_uint(&mut self, n: uint) { - uint::to_str_bytes(n, 10u, |bytes| self.write(bytes)) - } - - fn write_le_uint(&mut self, n: uint) { - u64_to_le_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - - fn write_le_int(&mut self, n: int) { - u64_to_le_bytes(n as u64, int::bytes, |v| self.write(v)) - } - - fn write_be_uint(&mut self, n: uint) { - u64_to_be_bytes(n as u64, uint::bytes, |v| self.write(v)) - } - - fn write_be_int(&mut self, n: int) { - u64_to_be_bytes(n as u64, int::bytes, |v| self.write(v)) - } - - fn write_be_u64_(&mut self, n: u64) { - u64_to_be_bytes(n, 8u, |v| self.write(v)) - } - - fn write_be_u32(&mut self, n: u32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - - fn write_be_u16(&mut self, n: u16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - - fn write_be_i64(&mut self, n: i64) { - u64_to_be_bytes(n as u64, 8u, |v| self.write(v)) - } - - fn write_be_i32(&mut self, n: i32) { - u64_to_be_bytes(n as u64, 4u, |v| self.write(v)) - } - - fn write_be_i16(&mut self, n: i16) { - u64_to_be_bytes(n as u64, 2u, |v| self.write(v)) - } - - fn write_be_f64(&mut self, f: f64) { - unsafe { - self.write_be_u64_(cast::transmute(f)) - } - } - - fn write_be_f32(&mut self, f: f32) { - unsafe { - self.write_be_u32(cast::transmute(f)) - } - } - - fn write_le_u64_(&mut self, n: u64) { - u64_to_le_bytes(n, 8u, |v| self.write(v)) - } - - fn write_le_u32(&mut self, n: u32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - - fn write_le_u16(&mut self, n: u16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - - fn write_le_i64(&mut self, n: i64) { - u64_to_le_bytes(n as u64, 8u, |v| self.write(v)) - } - - fn write_le_i32(&mut self, n: i32) { - u64_to_le_bytes(n as u64, 4u, |v| self.write(v)) - } - - fn write_le_i16(&mut self, n: i16) { - u64_to_le_bytes(n as u64, 2u, |v| self.write(v)) - } - - fn write_le_f64(&mut self, f: f64) { - unsafe { - self.write_le_u64_(cast::transmute(f)) - } - } - - fn write_le_f32(&mut self, f: f32) { - unsafe { - self.write_le_u32(cast::transmute(f)) - } - } - - fn write_u8(&mut self, n: u8) { - self.write([n]) - } - - fn write_i8(&mut self, n: i8) { - self.write([n as u8]) - } -} - -fn extend_sign(val: u64, nbytes: uint) -> i64 { - let shift = (8 - nbytes) * 8; - (val << shift) as i64 >> shift -} - -#[cfg(test)] -mod test { - use super::{ReaderUtil, ReaderByteConversions, WriterByteConversions}; - use u64; - use i32; - use option::{Some, None}; - use cell::Cell; - use rt::io::mem::{MemReader, MemWriter}; - use rt::io::mock::MockReader; - use rt::io::{read_error, placeholder_error}; - - #[test] - fn read_byte() { - let mut reader = MemReader::new(~[10]); - let byte = reader.read_byte(); - assert!(byte == Some(10)); - } - - #[test] - fn read_byte_0_bytes() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - Some(0) - } else { - buf[0] = 10; - Some(1) - } - } - }; - let byte = reader.read_byte(); - assert!(byte == Some(10)); - } - - #[test] - fn read_byte_eof() { - let mut reader = MockReader::new(); - reader.read = |_| None; - let byte = reader.read_byte(); - assert!(byte == None); - } - - #[test] - fn read_byte_error() { - let mut reader = MockReader::new(); - reader.read = |_| { - read_error::cond.raise(placeholder_error()); - None - }; - do read_error::cond.trap(|_| { - }).in { - let byte = reader.read_byte(); - assert!(byte == None); - } - } - - #[test] - fn read_bytes() { - let mut reader = MemReader::new(~[10, 11, 12, 13]); - let bytes = reader.read_bytes(4); - assert!(bytes == ~[10, 11, 12, 13]); - } - - #[test] - fn read_bytes_partial() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - buf[1] = 11; - Some(2) - } else { - buf[0] = 12; - buf[1] = 13; - Some(2) - } - } - }; - let bytes = reader.read_bytes(4); - assert!(bytes == ~[10, 11, 12, 13]); - } - - #[test] - fn read_bytes_eof() { - let mut reader = MemReader::new(~[10, 11]); - do read_error::cond.trap(|_| { - }).in { - assert!(reader.read_bytes(4) == ~[10, 11]); - } - } - - #[test] - fn push_bytes() { - let mut reader = MemReader::new(~[10, 11, 12, 13]); - let mut buf = ~[8, 9]; - reader.push_bytes(&mut buf, 4); - assert!(buf == ~[8, 9, 10, 11, 12, 13]); - } - - #[test] - fn push_bytes_partial() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - buf[1] = 11; - Some(2) - } else { - buf[0] = 12; - buf[1] = 13; - Some(2) - } - } - }; - let mut buf = ~[8, 9]; - reader.push_bytes(&mut buf, 4); - assert!(buf == ~[8, 9, 10, 11, 12, 13]); - } - - #[test] - fn push_bytes_eof() { - let mut reader = MemReader::new(~[10, 11]); - let mut buf = ~[8, 9]; - do read_error::cond.trap(|_| { - }).in { - reader.push_bytes(&mut buf, 4); - assert!(buf == ~[8, 9, 10, 11]); - } - } - - #[test] - fn push_bytes_error() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - Some(1) - } else { - read_error::cond.raise(placeholder_error()); - None - } - } - }; - let mut buf = ~[8, 9]; - do read_error::cond.trap(|_| { } ).in { - reader.push_bytes(&mut buf, 4); - } - assert!(buf == ~[8, 9, 10]); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn push_bytes_fail_reset_len() { - use unstable::finally::Finally; - - // push_bytes unsafely sets the vector length. This is testing that - // upon failure the length is reset correctly. - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - Some(1) - } else { - read_error::cond.raise(placeholder_error()); - None - } - } - }; - let buf = @mut ~[8, 9]; - do (|| { - reader.push_bytes(&mut *buf, 4); - }).finally { - // NB: Using rtassert here to trigger abort on failure since this is a should_fail test - rtassert!(*buf == ~[8, 9, 10]); - } - } - - #[test] - fn read_to_end() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - buf[1] = 11; - Some(2) - } else if *count == 1 { - *count = 2; - buf[0] = 12; - buf[1] = 13; - Some(2) - } else { - None - } - } - }; - let buf = reader.read_to_end(); - assert!(buf == ~[10, 11, 12, 13]); - } - - #[test] - #[should_fail] - #[ignore(cfg(windows))] - fn read_to_end_error() { - let mut reader = MockReader::new(); - let count = Cell(0); - reader.read = |buf| { - do count.with_mut_ref |count| { - if *count == 0 { - *count = 1; - buf[0] = 10; - buf[1] = 11; - Some(2) - } else { - read_error::cond.raise(placeholder_error()); - None - } - } - }; - let buf = reader.read_to_end(); - assert!(buf == ~[10, 11]); - } - - // XXX: Some problem with resolve here - /*#[test] - fn test_read_write_le() { - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - let mut writer = MemWriter::new(); - for uints.each |i| { - writer.write_le_u64(*i); - } - - let mut reader = MemReader::new(writer.inner()); - for uints.each |i| { - assert!(reader.read_le_u64() == *i); - } - } - - #[test] - fn test_read_write_be() { - let uints = [0, 1, 2, 42, 10_123, 100_123_456, u64::max_value]; - - let mut writer = MemWriter::new(); - for uints.each |i| { - writer.write_be_u64(*i); - } - - let mut reader = MemReader::new(writer.inner()); - for uints.each |i| { - assert!(reader.read_be_u64() == *i); - } - } - - #[test] - fn test_read_be_int_n() { - let ints = [i32::min_value, -123456, -42, -5, 0, 1, i32::max_value]; - - let mut writer = MemWriter::new(); - for ints.each |i| { - writer.write_be_i32(*i); - } - - let mut reader = MemReader::new(writer.inner()); - for ints.each |i| { - // this tests that the sign extension is working - // (comparing the values as i32 would not test this) - assert!(reader.read_be_int_n(4) == *i as i64); - } - } - - #[test] - fn test_read_f32() { - //big-endian floating-point 8.1250 - let buf = ~[0x41, 0x02, 0x00, 0x00]; - - let mut writer = MemWriter::new(); - writer.write(buf); - - let mut reader = MemReader::new(writer.inner()); - let f = reader.read_be_f32(); - assert!(f == 8.1250); - } - - #[test] - fn test_read_write_f32() { - let f:f32 = 8.1250; - - let mut writer = MemWriter::new(); - writer.write_be_f32(f); - writer.write_le_f32(f); - - let mut reader = MemReader::new(writer.inner()); - assert!(reader.read_be_f32() == 8.1250); - assert!(reader.read_le_f32() == 8.1250); - }*/ - -} diff --git a/src/libcore/rt/io/file.rs b/src/libcore/rt/io/file.rs deleted file mode 100644 index 1f61cf25fbd..00000000000 --- a/src/libcore/rt/io/file.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::support::PathLike; -use super::{Reader, Writer, Seek}; -use super::SeekStyle; - -/// # XXX -/// * Ugh, this is ridiculous. What is the best way to represent these options? -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, -} - -enum FileAccess { - Read, - Write, - ReadWrite -} - -pub struct FileStream; - -impl FileStream { - pub fn open<P: PathLike>(_path: &P, - _mode: FileMode, - _access: FileAccess - ) -> Option<FileStream> { - fail!() - } -} - -impl Reader for FileStream { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { - fail!() - } - - fn eof(&mut self) -> bool { - fail!() - } -} - -impl Writer for FileStream { - fn write(&mut self, _v: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl Seek for FileStream { - fn tell(&self) -> u64 { fail!() } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -#[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.to_bytes()); -} diff --git a/src/libcore/rt/io/flate.rs b/src/libcore/rt/io/flate.rs deleted file mode 100644 index db2683dc85d..00000000000 --- a/src/libcore/rt/io/flate.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Some various other I/O types - -// NOTE: These ultimately belong somewhere else - -use prelude::*; -use super::*; - -/// A Writer decorator that compresses using the 'deflate' scheme -pub struct DeflateWriter<W> { - inner_writer: W -} - -impl<W: Writer> DeflateWriter<W> { - pub fn new(inner_writer: W) -> DeflateWriter<W> { - DeflateWriter { - inner_writer: inner_writer - } - } -} - -impl<W: Writer> Writer for DeflateWriter<W> { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl<W: Writer> Decorator<W> for DeflateWriter<W> { - fn inner(self) -> W { - match self { - DeflateWriter { inner_writer: w } => w - } - } - - fn inner_ref<'a>(&'a self) -> &'a W { - match *self { - DeflateWriter { inner_writer: ref w } => w - } - } - - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut W { - match *self { - DeflateWriter { inner_writer: ref mut w } => w - } - } -} - -/// A Reader decorator that decompresses using the 'deflate' scheme -pub struct InflateReader<R> { - inner_reader: R -} - -impl<R: Reader> InflateReader<R> { - pub fn new(inner_reader: R) -> InflateReader<R> { - InflateReader { - inner_reader: inner_reader - } - } -} - -impl<R: Reader> Reader for InflateReader<R> { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl<R: Reader> Decorator<R> for InflateReader<R> { - fn inner(self) -> R { - match self { - InflateReader { inner_reader: r } => r - } - } - - fn inner_ref<'a>(&'a self) -> &'a R { - match *self { - InflateReader { inner_reader: ref r } => r - } - } - - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut R { - match *self { - InflateReader { inner_reader: ref mut r } => r - } - } -} - -#[cfg(test)] -mod test { - use prelude::*; - use super::*; - use super::super::mem::*; - use super::super::Decorator; - - #[test] - #[ignore] - fn smoke_test() { - let mem_writer = MemWriter::new(); - let mut deflate_writer = DeflateWriter::new(mem_writer); - let in_msg = "test"; - let in_bytes = in_msg.to_bytes(); - deflate_writer.write(in_bytes); - deflate_writer.flush(); - let buf = deflate_writer.inner().inner(); - let mem_reader = MemReader::new(buf); - let mut inflate_reader = InflateReader::new(mem_reader); - let mut out_bytes = [0, .. 100]; - let bytes_read = inflate_reader.read(out_bytes).get(); - assert_eq!(bytes_read, in_bytes.len()); - let out_msg = str::from_bytes(out_bytes); - assert!(in_msg == out_msg); - } -} diff --git a/src/libcore/rt/io/mem.rs b/src/libcore/rt/io/mem.rs deleted file mode 100644 index b2701c1fdc3..00000000000 --- a/src/libcore/rt/io/mem.rs +++ /dev/null @@ -1,221 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Readers and Writers for in-memory buffers -//! -//! # XXX -//! -//! * Should probably have something like this for strings. -//! * Should they implement Closable? Would take extra state. - -use prelude::*; -use super::*; -use cmp::min; - -/// Writes to an owned, growable byte vector -pub struct MemWriter { - buf: ~[u8] -} - -impl MemWriter { - pub fn new() -> MemWriter { MemWriter { buf: ~[] } } -} - -impl Writer for MemWriter { - fn write(&mut self, buf: &[u8]) { - self.buf.push_all(buf) - } - - fn flush(&mut self) { /* no-op */ } -} - -impl Seek for MemWriter { - fn tell(&self) -> u64 { self.buf.len() as u64 } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -impl Decorator<~[u8]> for MemWriter { - - fn inner(self) -> ~[u8] { - match self { - MemWriter { buf: buf } => buf - } - } - - fn inner_ref<'a>(&'a self) -> &'a ~[u8] { - match *self { - MemWriter { buf: ref buf } => buf - } - } - - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { - match *self { - MemWriter { buf: ref mut buf } => buf - } - } -} - -/// Reads from an owned byte vector -pub struct MemReader { - buf: ~[u8], - pos: uint -} - -impl MemReader { - pub fn new(buf: ~[u8]) -> MemReader { - MemReader { - buf: buf, - pos: 0 - } - } -} - -impl Reader for MemReader { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - { if self.eof() { return None; } } - - let write_len = min(buf.len(), self.buf.len() - self.pos); - { - let input = self.buf.slice(self.pos, self.pos + write_len); - let output = vec::mut_slice(buf, 0, write_len); - assert_eq!(input.len(), output.len()); - vec::bytes::copy_memory(output, input, write_len); - } - self.pos += write_len; - assert!(self.pos <= self.buf.len()); - - return Some(write_len); - } - - fn eof(&mut self) -> bool { self.pos == self.buf.len() } -} - -impl Seek for MemReader { - fn tell(&self) -> u64 { self.pos as u64 } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -impl Decorator<~[u8]> for MemReader { - - fn inner(self) -> ~[u8] { - match self { - MemReader { buf: buf, _ } => buf - } - } - - fn inner_ref<'a>(&'a self) -> &'a ~[u8] { - match *self { - MemReader { buf: ref buf, _ } => buf - } - } - - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut ~[u8] { - match *self { - MemReader { buf: ref mut buf, _ } => buf - } - } -} - - -/// Writes to a fixed-size byte slice -struct BufWriter<'self> { - buf: &'self mut [u8], - pos: uint -} - -impl<'self> BufWriter<'self> { - pub fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> { - BufWriter { - buf: buf, - pos: 0 - } - } -} - -impl<'self> Writer for BufWriter<'self> { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl<'self> Seek for BufWriter<'self> { - fn tell(&self) -> u64 { fail!() } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - - -/// Reads from a fixed-size byte slice -struct BufReader<'self> { - buf: &'self [u8], - pos: uint -} - -impl<'self> BufReader<'self> { - pub fn new<'a>(buf: &'a [u8]) -> BufReader<'a> { - BufReader { - buf: buf, - pos: 0 - } - } -} - -impl<'self> Reader for BufReader<'self> { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl<'self> Seek for BufReader<'self> { - fn tell(&self) -> u64 { fail!() } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -#[cfg(test)] -mod test { - use prelude::*; - use super::*; - - #[test] - fn test_mem_writer() { - let mut writer = MemWriter::new(); - assert_eq!(writer.tell(), 0); - writer.write([0]); - assert_eq!(writer.tell(), 1); - writer.write([1, 2, 3]); - writer.write([4, 5, 6, 7]); - assert_eq!(writer.tell(), 8); - assert_eq!(writer.inner(), ~[0, 1, 2, 3, 4, 5 , 6, 7]); - } - - #[test] - fn test_mem_reader() { - let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]); - let mut buf = []; - assert_eq!(reader.read(buf), Some(0)); - assert_eq!(reader.tell(), 0); - let mut buf = [0]; - assert_eq!(reader.read(buf), Some(1)); - assert_eq!(reader.tell(), 1); - assert_eq!(buf, [0]); - let mut buf = [0, ..4]; - assert_eq!(reader.read(buf), Some(4)); - assert_eq!(reader.tell(), 5); - assert_eq!(buf, [1, 2, 3, 4]); - assert_eq!(reader.read(buf), Some(3)); - assert_eq!(buf.slice(0, 3), [5, 6, 7]); - assert!(reader.eof()); - assert_eq!(reader.read(buf), None); - assert!(reader.eof()); - } -} diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs deleted file mode 100644 index 0ec51a3aa94..00000000000 --- a/src/libcore/rt/io/mod.rs +++ /dev/null @@ -1,504 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! Synchronous I/O - -This module defines the Rust interface for synchronous I/O. -It models byte-oriented input and output with the Reader and Writer traits. -Types that implement both `Reader` and `Writer` and called 'streams', -and automatically implement trait `Stream`. -Implementations are provided for common I/O streams like -file, TCP, UDP, Unix domain sockets. -Readers and Writers may be composed to add capabilities like string -parsing, encoding, and compression. - -This will likely live in core::io, not core::rt::io. - -# Examples - -Some examples of obvious things you might want to do - -* Read lines from stdin - - for stdin().each_line |line| { - println(line) - } - -* Read a complete file to a string, (converting newlines?) - - let contents = File::open("message.txt").read_to_str(); // read_to_str?? - -* Write a line to a file - - let file = File::open("message.txt", Create, Write); - file.write_line("hello, file!"); - -* Iterate over the lines of a file - - do File::open("message.txt").each_line |line| { - println(line) - } - -* Pull the lines of a file into a vector of strings - - let lines = File::open("message.txt").line_iter().to_vec(); - -* Make an simple HTTP request - - let socket = TcpStream::open("localhost:8080"); - socket.write_line("GET / HTTP/1.0"); - socket.write_line(""); - let response = socket.read_to_end(); - -* Connect based on URL? Requires thinking about where the URL type lives - and how to make protocol handlers extensible, e.g. the "tcp" protocol - yields a `TcpStream`. - - connect("tcp://localhost:8080"); - -# Terms - -* Reader - An I/O source, reads bytes into a buffer -* Writer - An I/O sink, writes bytes from a buffer -* Stream - Typical I/O sources like files and sockets are both Readers and Writers, - and are collectively referred to a `streams`. -* Decorator - A Reader or Writer that composes with others to add additional capabilities - such as encoding or decoding - -# Blocking and synchrony - -When discussing I/O you often hear the terms 'synchronous' and -'asynchronous', along with 'blocking' and 'non-blocking' compared and -contrasted. A synchronous I/O interface performs each I/O operation to -completion before proceeding to the next. Synchronous interfaces are -usually used in imperative style as a sequence of commands. An -asynchronous interface allows multiple I/O requests to be issued -simultaneously, without waiting for each to complete before proceeding -to the next. - -Asynchronous interfaces are used to achieve 'non-blocking' I/O. In -traditional single-threaded systems, performing a synchronous I/O -operation means that the program stops all activity (it 'blocks') -until the I/O is complete. Blocking is bad for performance when -there are other computations that could be done. - -Asynchronous interfaces are most often associated with the callback -(continuation-passing) style popularised by node.js. Such systems rely -on all computations being run inside an event loop which maintains a -list of all pending I/O events; when one completes the registered -callback is run and the code that made the I/O request continiues. -Such interfaces achieve non-blocking at the expense of being more -difficult to reason about. - -Rust's I/O interface is synchronous - easy to read - and non-blocking by default. - -Remember that Rust tasks are 'green threads', lightweight threads that -are multiplexed onto a single operating system thread. If that system -thread blocks then no other task may proceed. Rust tasks are -relatively cheap to create, so as long as other tasks are free to -execute then non-blocking code may be written by simply creating a new -task. - -When discussing blocking in regards to Rust's I/O model, we are -concerned with whether performing I/O blocks other Rust tasks from -proceeding. In other words, when a task calls `read`, it must then -wait (or 'sleep', or 'block') until the call to `read` is complete. -During this time, other tasks may or may not be executed, depending on -how `read` is implemented. - - -Rust's default I/O implementation is non-blocking; by cooperating -directly with the task scheduler it arranges to never block progress -of *other* tasks. Under the hood, Rust uses asynchronous I/O via a -per-scheduler (and hence per-thread) event loop. Synchronous I/O -requests are implemented by descheduling the running task and -performing an asynchronous request; the task is only resumed once the -asynchronous request completes. - -For blocking (but possibly more efficient) implementations, look -in the `io::native` module. - -# Error Handling - -I/O is an area where nearly every operation can result in unexpected -errors. It should allow errors to be handled efficiently. -It needs to be convenient to use I/O when you don't care -about dealing with specific errors. - -Rust's I/O employs a combination of techniques to reduce boilerplate -while still providing feedback about errors. The basic strategy: - -* Errors are fatal by default, resulting in task failure -* Errors raise the `io_error` conditon which provides an opportunity to inspect - an IoError object containing details. -* Return values must have a sensible null or zero value which is returned - if a condition is handled successfully. This may be an `Option`, an empty - vector, or other designated error value. -* Common traits are implemented for `Option`, e.g. `impl<R: Reader> Reader for Option<R>`, - so that nullable values do not have to be 'unwrapped' before use. - -These features combine in the API to allow for expressions like -`File::new("diary.txt").write_line("met a girl")` without having to -worry about whether "diary.txt" exists or whether the write -succeeds. As written, if either `new` or `write_line` encounters -an error the task will fail. - -If you wanted to handle the error though you might write - - let mut error = None; - do io_error::cond(|e: IoError| { - error = Some(e); - }).in { - File::new("diary.txt").write_line("met a girl"); - } - - if error.is_some() { - println("failed to write my diary"); - } - -XXX: Need better condition handling syntax - -In this case the condition handler will have the opportunity to -inspect the IoError raised by either the call to `new` or the call to -`write_line`, but then execution will continue. - -So what actually happens if `new` encounters an error? To understand -that it's important to know that what `new` returns is not a `File` -but an `Option<File>`. If the file does not open, and the condition -is handled, then `new` will simply return `None`. Because there is an -implementation of `Writer` (the trait required ultimately required for -types to implement `write_line`) there is no need to inspect or unwrap -the `Option<File>` and we simply call `write_line` on it. If `new` -returned a `None` then the followup call to `write_line` will also -raise an error. - -## Concerns about this strategy - -This structure will encourage a programming style that is prone -to errors similar to null pointer dereferences. -In particular code written to ignore errors and expect conditions to be unhandled -will start passing around null or zero objects when wrapped in a condition handler. - -* XXX: How should we use condition handlers that return values? -* XXX: Should EOF raise default conditions when EOF is not an error? - -# Issues withi/o scheduler affinity, work stealing, task pinning - -# Resource management - -* `close` vs. RAII - -# Paths, URLs and overloaded constructors - - - -# Scope - -In scope for core - -* Url? - -Some I/O things don't belong in core - - - url - - net - `fn connect` - - http - - flate - -Out of scope - -* Async I/O. We'll probably want it eventually - - -# XXX Questions and issues - -* Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose. - Overloading would be nice. -* Add overloading for Path and &str and Url &str -* stdin/err/out -* print, println, etc. -* fsync -* relationship with filesystem querying, Directory, File types etc. -* Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic? -* Can Port and Chan be implementations of a generic Reader<T>/Writer<T>? -* Trait for things that are both readers and writers, Stream? -* How to handle newline conversion -* String conversion -* File vs. FileStream? File is shorter but could also be used for getting file info - - maybe File is for general file querying and *also* has a static `open` method -* open vs. connect for generic stream opening -* Do we need `close` at all? dtors might be good enough -* How does I/O relate to the Iterator trait? -* std::base64 filters -* Using conditions is a big unknown since we don't have much experience with them -* Too many uses of OtherIoError - -*/ - -use prelude::*; - -// Reexports -pub use self::stdio::stdin; -pub use self::stdio::stdout; -pub use self::stdio::stderr; -pub use self::stdio::print; -pub use self::stdio::println; - -pub use self::file::FileStream; -pub use self::net::ip::IpAddr; -pub use self::net::tcp::TcpListener; -pub use self::net::tcp::TcpStream; -pub use self::net::udp::UdpStream; - -// Some extension traits that all Readers and Writers get. -pub use self::extensions::ReaderUtil; -pub use self::extensions::ReaderByteConversions; -pub use self::extensions::WriterByteConversions; - -/// Synchronous, non-blocking file I/O. -pub mod file; - -/// Synchronous, non-blocking network I/O. -pub mod net { - pub mod tcp; - pub mod udp; - pub mod ip; - #[cfg(unix)] - pub mod unix; - pub mod http; -} - -/// Readers and Writers for memory buffers and strings. -pub mod mem; - -/// Non-blocking access to stdin, stdout, stderr -pub mod stdio; - -/// Implementations for Option -mod option; - -/// Basic stream compression. XXX: Belongs with other flate code -pub mod flate; - -/// Interop between byte streams and pipes. Not sure where it belongs -pub mod comm_adapters; - -/// Extension traits -mod extensions; - -/// Non-I/O things needed by the I/O module -mod support; - -/// Thread-blocking implementations -pub mod native { - /// Posix file I/O - pub mod file; - /// # XXX - implement this - pub mod stdio { } - /// Sockets - /// # XXX - implement this - pub mod net { - pub mod tcp { } - pub mod udp { } - #[cfg(unix)] - pub mod unix { } - } -} - -/// Mock implementations for testing -mod mock; - -/// The default buffer size for various I/O operations -/// XXX: Not pub -pub static DEFAULT_BUF_SIZE: uint = 1024 * 64; - -/// The type passed to I/O condition handlers to indicate error -/// -/// # XXX -/// -/// Is something like this sufficient? It's kind of archaic -pub struct IoError { - kind: IoErrorKind, - desc: &'static str, - detail: Option<~str> -} - -#[deriving(Eq)] -pub enum IoErrorKind { - PreviousIoError, - OtherIoError, - EndOfFile, - FileNotFound, - PermissionDenied, - ConnectionFailed, - Closed, - ConnectionRefused, - ConnectionReset, - BrokenPipe -} - -// XXX: Can't put doc comments on macros -// Raised by `I/O` operations on error. -condition! { - // FIXME (#6009): uncomment `pub` after expansion support lands. - /*pub*/ io_error: super::IoError -> (); -} - -// XXX: Can't put doc comments on macros -// Raised by `read` on error -condition! { - // FIXME (#6009): uncomment `pub` after expansion support lands. - /*pub*/ read_error: super::IoError -> (); -} - -pub trait Reader { - /// Read bytes, up to the length of `buf` and place them in `buf`. - /// Returns the number of bytes read. The number of bytes read my - /// be less than the number requested, even 0. Returns `None` on EOF. - /// - /// # Failure - /// - /// Raises the `read_error` condition on error. If the condition - /// is handled then no guarantee is made about the number of bytes - /// read and the contents of `buf`. If the condition is handled - /// returns `None` (XXX see below). - /// - /// # XXX - /// - /// * Should raise_default error on eof? - /// * If the condition is handled it should still return the bytes read, - /// in which case there's no need to return Option - but then you *have* - /// to install a handler to detect eof. - /// - /// This doesn't take a `len` argument like the old `read`. - /// Will people often need to slice their vectors to call this - /// and will that be annoying? - /// Is it actually possible for 0 bytes to be read successfully? - fn read(&mut self, buf: &mut [u8]) -> Option<uint>; - - /// Return whether the Reader has reached the end of the stream. - /// - /// # Example - /// - /// let reader = FileStream::new() - /// while !reader.eof() { - /// println(reader.read_line()); - /// } - /// - /// # Failue - /// - /// Returns `true` on failure. - fn eof(&mut self) -> bool; -} - -pub trait Writer { - /// Write the given buffer - /// - /// # Failure - /// - /// Raises the `io_error` condition on error - fn write(&mut self, buf: &[u8]); - - /// Flush output - fn flush(&mut self); -} - -pub trait Stream: Reader + Writer { } - -pub enum SeekStyle { - /// Seek from the beginning of the stream - SeekSet, - /// Seek from the end of the stream - SeekEnd, - /// Seek from the current position - SeekCur, -} - -/// # XXX -/// * Are `u64` and `i64` the right choices? -pub trait Seek { - fn tell(&self) -> u64; - - /// Seek to an offset in a stream - /// - /// A successful seek clears the EOF indicator. - /// - /// # XXX - /// - /// * What is the behavior when seeking past the end of a stream? - fn seek(&mut self, pos: i64, style: SeekStyle); -} - -/// A listener is a value that listens for connections -pub trait Listener<S> { - /// Wait for and accept an incoming connection - /// - /// Returns `None` on timeout. - /// - /// # Failure - /// - /// Raises `io_error` condition. If the condition is handled, - /// then `accept` returns `None`. - fn accept(&mut self) -> Option<S>; -} - -/// Common trait for decorator types. -/// -/// Provides accessors to get the inner, 'decorated' values. The I/O library -/// uses decorators to add functionality like compression and encryption to I/O -/// streams. -/// -/// # XXX -/// -/// Is this worth having a trait for? May be overkill -pub trait Decorator<T> { - /// Destroy the decorator and extract the decorated value - /// - /// # XXX - /// - /// Because this takes `self' one could never 'undecorate' a Reader/Writer - /// that has been boxed. Is that ok? This feature is mostly useful for - /// extracting the buffer from MemWriter - fn inner(self) -> T; - - /// Take an immutable reference to the decorated value - fn inner_ref<'a>(&'a self) -> &'a T; - - /// Take a mutable reference to the decorated value - fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T; -} - -pub fn standard_error(kind: IoErrorKind) -> IoError { - match kind { - PreviousIoError => { - IoError { - kind: PreviousIoError, - desc: "Failing due to a previous I/O error", - detail: None - } - } - EndOfFile => { - IoError { - kind: EndOfFile, - desc: "End of file", - detail: None - } - } - _ => fail!() - } -} - -pub fn placeholder_error() -> IoError { - IoError { - kind: OtherIoError, - desc: "Placeholder error. You shouldn't be seeing this", - detail: None - } -} \ No newline at end of file diff --git a/src/libcore/rt/io/native/file.rs b/src/libcore/rt/io/native/file.rs deleted file mode 100644 index 31c90336a24..00000000000 --- a/src/libcore/rt/io/native/file.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Blocking posix-based file I/O - -use prelude::*; -use super::super::*; -use libc::{c_int, FILE}; - -#[allow(non_camel_case_types)] -pub type fd_t = c_int; - -// Make this a newtype so we can't do I/O on arbitrary integers -pub struct FileDesc(fd_t); - -impl FileDesc { - /// Create a `FileDesc` from an open C file descriptor. - /// - /// The `FileDesc` takes ownership of the file descriptor - /// and will close it upon destruction. - pub fn new(_fd: fd_t) -> FileDesc { fail!() } -} - -impl Reader for FileDesc { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl Writer for FileDesc { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl Seek for FileDesc { - fn tell(&self) -> u64 { fail!() } - - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} - -pub struct CFile(*FILE); - -impl CFile { - /// Create a `CFile` from an open `FILE` pointer. - /// - /// The `CFile` takes ownership of the file descriptor - /// and will close it upon destruction. - pub fn new(_file: *FILE) -> CFile { fail!() } -} - -impl Reader for CFile { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl Writer for CFile { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -impl Seek for CFile { - fn tell(&self) -> u64 { fail!() } - fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} diff --git a/src/libcore/rt/io/net/http.rs b/src/libcore/rt/io/net/http.rs deleted file mode 100644 index c693cfaab67..00000000000 --- a/src/libcore/rt/io/net/http.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Simple HTTP client and server - -// XXX This should not be in core - -struct HttpServer; - -#[cfg(test)] -mod test { - use unstable::run_in_bare_thread; - - #[test] #[ignore] - fn smoke_test() { - do run_in_bare_thread { - } - - do run_in_bare_thread { - } - } -} diff --git a/src/libcore/rt/io/net/ip.rs b/src/libcore/rt/io/net/ip.rs deleted file mode 100644 index df1dfe4d38a..00000000000 --- a/src/libcore/rt/io/net/ip.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -pub enum IpAddr { - Ipv4(u8, u8, u8, u8, u16), - Ipv6 -} diff --git a/src/libcore/rt/io/net/tcp.rs b/src/libcore/rt/io/net/tcp.rs deleted file mode 100644 index f7c03c13a58..00000000000 --- a/src/libcore/rt/io/net/tcp.rs +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use option::{Option, Some, None}; -use result::{Ok, Err}; -use rt::io::net::ip::IpAddr; -use rt::io::{Reader, Writer, Listener}; -use rt::io::{io_error, read_error, EndOfFile}; -use rt::rtio::{IoFactory, IoFactoryObject, - RtioTcpListener, RtioTcpListenerObject, - RtioTcpStream, RtioTcpStreamObject}; -use rt::local::Local; - -pub struct TcpStream { - rtstream: ~RtioTcpStreamObject -} - -impl TcpStream { - fn new(s: ~RtioTcpStreamObject) -> TcpStream { - TcpStream { - rtstream: s - } - } - - pub fn connect(addr: IpAddr) -> Option<TcpStream> { - let stream = unsafe { - rtdebug!("borrowing io to connect"); - let io = Local::unsafe_borrow::<IoFactoryObject>(); - rtdebug!("about to connect"); - (*io).tcp_connect(addr) - }; - - match stream { - Ok(s) => { - Some(TcpStream::new(s)) - } - Err(ioerr) => { - rtdebug!("failed to connect: %?", ioerr); - io_error::cond.raise(ioerr); - return None; - } - } - } -} - -impl Reader for TcpStream { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - let bytes_read = self.rtstream.read(buf); - match bytes_read { - Ok(read) => Some(read), - 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!() } -} - -impl Writer for TcpStream { - fn write(&mut self, buf: &[u8]) { - let res = self.rtstream.write(buf); - match res { - Ok(_) => (), - Err(ioerr) => { - io_error::cond.raise(ioerr); - } - } - } - - fn flush(&mut self) { fail!() } -} - -pub struct TcpListener { - rtlistener: ~RtioTcpListenerObject, -} - -impl TcpListener { - pub fn bind(addr: IpAddr) -> Option<TcpListener> { - let listener = unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - (*io).tcp_bind(addr) - }; - match listener { - Ok(l) => { - Some(TcpListener { - rtlistener: l - }) - } - Err(ioerr) => { - io_error::cond.raise(ioerr); - return None; - } - } - } -} - -impl Listener<TcpStream> for TcpListener { - fn accept(&mut self) -> Option<TcpStream> { - let rtstream = self.rtlistener.accept(); - match rtstream { - Ok(s) => { - Some(TcpStream::new(s)) - } - Err(ioerr) => { - io_error::cond.raise(ioerr); - return None; - } - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use int; - use cell::Cell; - use rt::test::*; - use rt::io::net::ip::Ipv4; - use rt::io::*; - - #[test] #[ignore] - fn bind_error() { - do run_in_newsched_task { - let mut called = false; - do io_error::cond.trap(|e| { - assert!(e.kind == PermissionDenied); - called = true; - }).in { - let addr = Ipv4(0, 0, 0, 0, 1); - let listener = TcpListener::bind(addr); - assert!(listener.is_none()); - } - assert!(called); - } - } - - #[test] - fn connect_error() { - do run_in_newsched_task { - let mut called = false; - do io_error::cond.trap(|e| { - assert!(e.kind == ConnectionRefused); - called = true; - }).in { - let addr = Ipv4(0, 0, 0, 0, 1); - let stream = TcpStream::connect(addr); - assert!(stream.is_none()); - } - assert!(called); - } - } - - #[test] - fn smoke_test() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - let mut stream = listener.accept(); - let mut buf = [0]; - stream.read(buf); - assert!(buf[0] == 99); - } - - do spawntask_immediately { - let mut stream = TcpStream::connect(addr); - stream.write([99]); - } - } - } - - #[test] - fn read_eof() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - let mut stream = listener.accept(); - let mut buf = [0]; - let nread = stream.read(buf); - assert!(nread.is_none()); - } - - do spawntask_immediately { - let _stream = TcpStream::connect(addr); - // Close - } - } - } - - #[test] - fn read_eof_twice() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - let mut stream = listener.accept(); - let mut buf = [0]; - let nread = stream.read(buf); - assert!(nread.is_none()); - let nread = stream.read(buf); - assert!(nread.is_none()); - } - - do spawntask_immediately { - let _stream = TcpStream::connect(addr); - // Close - } - } - } - - #[test] - fn write_close() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - let mut stream = listener.accept(); - let buf = [0]; - loop { - let mut stop = false; - do io_error::cond.trap(|e| { - // NB: ECONNRESET on linux, EPIPE on mac - assert!(e.kind == ConnectionReset || e.kind == BrokenPipe); - stop = true; - }).in { - stream.write(buf); - } - if stop { break } - } - } - - do spawntask_immediately { - let _stream = TcpStream::connect(addr); - // Close - } - } - } - - #[test] - fn multiple_connect_serial() { - do run_in_newsched_task { - let addr = next_test_ip4(); - let max = 10; - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - for max.times { - let mut stream = listener.accept(); - let mut buf = [0]; - stream.read(buf); - assert_eq!(buf[0], 99); - } - } - - do spawntask_immediately { - for max.times { - let mut stream = TcpStream::connect(addr); - stream.write([99]); - } - } - } - } - - #[test] - fn multiple_connect_interleaved_greedy_schedule() { - do run_in_newsched_task { - let addr = next_test_ip4(); - static MAX: int = 10; - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - for int::range(0, MAX) |i| { - let stream = Cell(listener.accept()); - rtdebug!("accepted"); - // Start another task to handle the connection - do spawntask_immediately { - let mut stream = stream.take(); - let mut buf = [0]; - stream.read(buf); - assert!(buf[0] == i as u8); - rtdebug!("read"); - } - } - } - - connect(0, addr); - - fn connect(i: int, addr: IpAddr) { - if i == MAX { return } - - do spawntask_immediately { - rtdebug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - rtdebug!("writing"); - stream.write([i as u8]); - } - } - } - } - - #[test] - fn multiple_connect_interleaved_lazy_schedule() { - do run_in_newsched_task { - let addr = next_test_ip4(); - static MAX: int = 10; - - do spawntask_immediately { - let mut listener = TcpListener::bind(addr); - for int::range(0, MAX) |_| { - let stream = Cell(listener.accept()); - rtdebug!("accepted"); - // Start another task to handle the connection - do spawntask_later { - let mut stream = stream.take(); - let mut buf = [0]; - stream.read(buf); - assert!(buf[0] == 99); - rtdebug!("read"); - } - } - } - - connect(0, addr); - - fn connect(i: int, addr: IpAddr) { - if i == MAX { return } - - do spawntask_later { - rtdebug!("connecting"); - let mut stream = TcpStream::connect(addr); - // Connect again before writing - connect(i + 1, addr); - rtdebug!("writing"); - stream.write([99]); - } - } - } - } - -} diff --git a/src/libcore/rt/io/net/udp.rs b/src/libcore/rt/io/net/udp.rs deleted file mode 100644 index bb5457e334d..00000000000 --- a/src/libcore/rt/io/net/udp.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::super::*; -use super::ip::IpAddr; - -pub struct UdpStream; - -impl UdpStream { - pub fn connect(_addr: IpAddr) -> Option<UdpStream> { - fail!() - } -} - -impl Reader for UdpStream { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl Writer for UdpStream { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -pub struct UdpListener; - -impl UdpListener { - pub fn bind(_addr: IpAddr) -> Option<UdpListener> { - fail!() - } -} - -impl Listener<UdpStream> for UdpListener { - fn accept(&mut self) -> Option<UdpStream> { fail!() } -} diff --git a/src/libcore/rt/io/net/unix.rs b/src/libcore/rt/io/net/unix.rs deleted file mode 100644 index b85b7dd059d..00000000000 --- a/src/libcore/rt/io/net/unix.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::super::*; -use super::super::support::PathLike; - -pub struct UnixStream; - -impl UnixStream { - pub fn connect<P: PathLike>(_path: &P) -> Option<UnixStream> { - fail!() - } -} - -impl Reader for UnixStream { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -impl Writer for UnixStream { - fn write(&mut self, _v: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -pub struct UnixListener; - -impl UnixListener { - pub fn bind<P: PathLike>(_path: &P) -> Option<UnixListener> { - fail!() - } -} - -impl Listener<UnixStream> for UnixListener { - fn accept(&mut self) -> Option<UnixStream> { fail!() } -} diff --git a/src/libcore/rt/io/option.rs b/src/libcore/rt/io/option.rs deleted file mode 100644 index d71ef55d3ad..00000000000 --- a/src/libcore/rt/io/option.rs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementations of I/O traits for the Option type -//! -//! I/O constructors return option types to allow errors to be handled. -//! These implementations allow e.g. `Option<FileStream>` to be used -//! as a `Reader` without unwrapping the option first. -//! -//! # XXX Seek and Close - -use option::*; -use super::{Reader, Writer, Listener}; -use super::{standard_error, PreviousIoError, io_error, read_error, IoError}; - -fn prev_io_error() -> IoError { - standard_error(PreviousIoError) -} - -impl<W: Writer> Writer for Option<W> { - fn write(&mut self, buf: &[u8]) { - match *self { - Some(ref mut writer) => writer.write(buf), - None => io_error::cond.raise(prev_io_error()) - } - } - - fn flush(&mut self) { - match *self { - Some(ref mut writer) => writer.flush(), - None => io_error::cond.raise(prev_io_error()) - } - } -} - -impl<R: Reader> Reader for Option<R> { - fn read(&mut self, buf: &mut [u8]) -> Option<uint> { - match *self { - Some(ref mut reader) => reader.read(buf), - None => { - read_error::cond.raise(prev_io_error()); - None - } - } - } - - fn eof(&mut self) -> bool { - match *self { - Some(ref mut reader) => reader.eof(), - None => { - io_error::cond.raise(prev_io_error()); - true - } - } - } -} - -impl<L: Listener<S>, S> Listener<S> for Option<L> { - fn accept(&mut self) -> Option<S> { - match *self { - Some(ref mut listener) => listener.accept(), - None => { - io_error::cond.raise(prev_io_error()); - None - } - } - } -} - -#[cfg(test)] -mod test { - use option::*; - use super::super::mem::*; - use rt::test::*; - use super::super::{PreviousIoError, io_error, read_error}; - - #[test] - fn test_option_writer() { - do run_in_newsched_task { - let mut writer: Option<MemWriter> = Some(MemWriter::new()); - writer.write([0, 1, 2]); - writer.flush(); - assert_eq!(writer.unwrap().inner(), ~[0, 1, 2]); - } - } - - #[test] - fn test_option_writer_error() { - do run_in_newsched_task { - let mut writer: Option<MemWriter> = None; - - let mut called = false; - do io_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).in { - writer.write([0, 0, 0]); - } - assert!(called); - - let mut called = false; - do io_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).in { - writer.flush(); - } - assert!(called); - } - } - - #[test] - fn test_option_reader() { - do run_in_newsched_task { - let mut reader: Option<MemReader> = Some(MemReader::new(~[0, 1, 2, 3])); - let mut buf = [0, 0]; - reader.read(buf); - assert_eq!(buf, [0, 1]); - assert!(!reader.eof()); - } - } - - #[test] - fn test_option_reader_error() { - let mut reader: Option<MemReader> = None; - let mut buf = []; - - let mut called = false; - do read_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).in { - reader.read(buf); - } - assert!(called); - - let mut called = false; - do io_error::cond.trap(|err| { - assert_eq!(err.kind, PreviousIoError); - called = true; - }).in { - assert!(reader.eof()); - } - assert!(called); - } -} diff --git a/src/libcore/rt/io/stdio.rs b/src/libcore/rt/io/stdio.rs deleted file mode 100644 index 247fe954408..00000000000 --- a/src/libcore/rt/io/stdio.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use super::{Reader, Writer}; - -pub fn stdin() -> StdReader { fail!() } - -pub fn stdout() -> StdWriter { fail!() } - -pub fn stderr() -> StdReader { fail!() } - -pub fn print(_s: &str) { fail!() } - -pub fn println(_s: &str) { fail!() } - -pub enum StdStream { - StdIn, - StdOut, - StdErr -} - -pub struct StdReader; - -impl StdReader { - pub fn new(_stream: StdStream) -> StdReader { fail!() } -} - -impl Reader for StdReader { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } - - fn eof(&mut self) -> bool { fail!() } -} - -pub struct StdWriter; - -impl StdWriter { - pub fn new(_stream: StdStream) -> StdWriter { fail!() } -} - -impl Writer for StdWriter { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - diff --git a/src/libcore/rt/io/support.rs b/src/libcore/rt/io/support.rs deleted file mode 100644 index 7bace5d6df2..00000000000 --- a/src/libcore/rt/io/support.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use path::*; - -pub trait PathLike { - fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T; -} - -impl<'self> PathLike for &'self str { - fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T { - f(*self) - } -} - -impl PathLike for Path { - fn path_as_str<T>(&self, f: &fn(&str) -> T) -> T { - let s = self.to_str(); - f(s) - } -} - -#[cfg(test)] -mod test { - use path::*; - use super::PathLike; - - #[test] - fn path_like_smoke_test() { - let expected = "/home"; - let path = Path(expected); - path.path_as_str(|p| assert!(p == expected)); - path.path_as_str(|p| assert!(p == expected)); - } -} diff --git a/src/libcore/rt/local_heap.rs b/src/libcore/rt/local_heap.rs deleted file mode 100644 index 6bf228a1b22..00000000000 --- a/src/libcore/rt/local_heap.rs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! The local, garbage collected heap - -use libc::{c_void, uintptr_t, size_t}; -use ops::Drop; - -type MemoryRegion = c_void; -type BoxedRegion = c_void; - -pub type OpaqueBox = c_void; -pub type TypeDesc = c_void; - -pub struct LocalHeap { - memory_region: *MemoryRegion, - boxed_region: *BoxedRegion -} - -impl LocalHeap { - pub fn new() -> LocalHeap { - unsafe { - // Don't need synchronization for the single-threaded local heap - let synchronized = false as uintptr_t; - // XXX: These usually come from the environment - let detailed_leaks = false as uintptr_t; - let poison_on_free = false as uintptr_t; - let region = rust_new_memory_region(synchronized, detailed_leaks, poison_on_free); - assert!(region.is_not_null()); - let boxed = rust_new_boxed_region(region, poison_on_free); - assert!(boxed.is_not_null()); - LocalHeap { - memory_region: region, - boxed_region: boxed - } - } - } - - pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox { - unsafe { - return rust_boxed_region_malloc(self.boxed_region, td, size as size_t); - } - } - - pub fn free(&mut self, box: *OpaqueBox) { - unsafe { - return rust_boxed_region_free(self.boxed_region, box); - } - } -} - -impl Drop for LocalHeap { - fn finalize(&self) { - unsafe { - rust_delete_boxed_region(self.boxed_region); - rust_delete_memory_region(self.memory_region); - } - } -} - -extern { - fn rust_new_memory_region(synchronized: uintptr_t, - detailed_leaks: uintptr_t, - poison_on_free: uintptr_t) -> *MemoryRegion; - fn rust_delete_memory_region(region: *MemoryRegion); - fn rust_new_boxed_region(region: *MemoryRegion, - poison_on_free: uintptr_t) -> *BoxedRegion; - fn rust_delete_boxed_region(region: *BoxedRegion); - fn rust_boxed_region_malloc(region: *BoxedRegion, - td: *TypeDesc, - size: size_t) -> *OpaqueBox; - fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox); -} diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs deleted file mode 100644 index 2fac1df01a4..00000000000 --- a/src/libcore/rt/mod.rs +++ /dev/null @@ -1,243 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! The Rust Runtime, including the task scheduler and I/O - -The `rt` module provides the private runtime infrastructure necessary -to support core language features like the exchange and local heap, -the garbage collector, logging, local data and unwinding. It also -implements the default task scheduler and task model. Initialization -routines are provided for setting up runtime resources in common -configurations, including that used by `rustc` when generating -executables. - -It is intended that the features provided by `rt` can be factored in a -way such that the core library can be built with different 'profiles' -for different use cases, e.g. excluding the task scheduler. A number -of runtime features though are critical to the functioning of the -language and an implementation must be provided regardless of the -execution environment. - -Of foremost importance is the global exchange heap, in the module -`global_heap`. Very little practical Rust code can be written without -access to the global heap. Unlike most of `rt` the global heap is -truly a global resource and generally operates independently of the -rest of the runtime. - -All other runtime features are task-local, including the local heap, -the garbage collector, local storage, logging and the stack unwinder. - -The relationship between `rt` and the rest of the core library is -not entirely clear yet and some modules will be moving into or -out of `rt` as development proceeds. - -Several modules in `core` are clients of `rt`: - -* `core::task` - The user-facing interface to the Rust task model. -* `core::task::local_data` - The interface to local data. -* `core::gc` - The garbage collector. -* `core::unstable::lang` - Miscellaneous lang items, some of which rely on `core::rt`. -* `core::condition` - Uses local data. -* `core::cleanup` - Local heap destruction. -* `core::io` - In the future `core::io` will use an `rt` implementation. -* `core::logging` -* `core::pipes` -* `core::comm` -* `core::stackwalk` - -*/ - -#[doc(hidden)]; - -use ptr::Ptr; - -/// The global (exchange) heap. -pub mod global_heap; - -/// Implementations of language-critical runtime features like @. -pub mod task; - -/// The coroutine task scheduler, built on the `io` event loop. -mod sched; - -/// Synchronous I/O. -#[path = "io/mod.rs"] -pub mod io; - -/// The EventLoop and internal synchronous I/O interface. -mod rtio; - -/// libuv and default rtio implementation. -#[path = "uv/mod.rs"] -pub mod uv; - -/// The Local trait for types that are accessible via thread-local -/// or task-local storage. -pub mod local; - -/// A parallel work-stealing deque. -mod work_queue; - -/// A parallel queue. -mod message_queue; - -/// Stack segments and caching. -mod stack; - -/// CPU context swapping. -mod context; - -/// Bindings to system threading libraries. -mod thread; - -/// The runtime configuration, read from environment variables -pub mod env; - -/// The local, managed heap -mod local_heap; - -/// The Logger trait and implementations -pub mod logging; - -/// Tools for testing the runtime -pub mod test; - -/// Reference counting -pub mod rc; - -/// A simple single-threaded channel type for passing buffered data between -/// scheduler and task context -pub mod tube; - -/// Simple reimplementation of core::comm -pub mod comm; - -// FIXME #5248 shouldn't be pub -/// The runtime needs to be able to put a pointer into thread-local storage. -pub mod local_ptr; - -// FIXME #5248: The import in `sched` doesn't resolve unless this is pub! -/// Bindings to pthread/windows thread-local storage. -pub mod thread_local_storage; - - -/// Set up a default runtime configuration, given compiler-supplied arguments. -/// -/// This is invoked by the `start` _language item_ (unstable::lang) to -/// run a Rust executable. -/// -/// # Arguments -/// -/// * `argc` & `argv` - The argument vector. On Unix this information is used -/// by os::args. -/// * `crate_map` - Runtime information about the executing crate, mostly for logging -/// -/// # Return value -/// -/// The return value is used as the process return code. 0 on success, 101 on error. -pub fn start(_argc: int, _argv: **u8, crate_map: *u8, main: ~fn()) -> int { - - use self::sched::{Scheduler, Coroutine}; - use self::uv::uvio::UvEventLoop; - - init(crate_map); - - let loop_ = ~UvEventLoop::new(); - let mut sched = ~Scheduler::new(loop_); - let main_task = ~Coroutine::new(&mut sched.stack_pool, main); - - sched.enqueue_task(main_task); - sched.run(); - - return 0; -} - -/// One-time runtime initialization. Currently all this does is set up logging -/// based on the RUST_LOG environment variable. -pub fn init(crate_map: *u8) { - logging::init(crate_map); -} - -/// Possible contexts in which Rust code may be executing. -/// Different runtime services are available depending on context. -/// Mostly used for determining if we're using the new scheduler -/// or the old scheduler. -#[deriving(Eq)] -pub enum RuntimeContext { - // Only the exchange heap is available - GlobalContext, - // The scheduler may be accessed - SchedulerContext, - // Full task services, e.g. local heap, unwinding - TaskContext, - // Running in an old-style task - OldTaskContext -} - -/// Determine the current RuntimeContext -pub fn context() -> RuntimeContext { - - use task::rt::rust_task; - use self::local::Local; - use self::sched::Scheduler; - - // XXX: Hitting TLS twice to check if the scheduler exists - // then to check for the task is not good for perf - if unsafe { rust_try_get_task().is_not_null() } { - return OldTaskContext; - } else { - if Local::exists::<Scheduler>() { - let context = ::cell::empty_cell(); - do Local::borrow::<Scheduler> |sched| { - if sched.in_task_context() { - context.put_back(TaskContext); - } else { - context.put_back(SchedulerContext); - } - } - return context.take(); - } else { - return GlobalContext; - } - } - - pub extern { - #[rust_stack] - fn rust_try_get_task() -> *rust_task; - } -} - -#[test] -fn test_context() { - use unstable::run_in_bare_thread; - use self::sched::{Scheduler, Coroutine}; - use rt::uv::uvio::UvEventLoop; - use cell::Cell; - use rt::local::Local; - - assert_eq!(context(), OldTaskContext); - do run_in_bare_thread { - assert_eq!(context(), GlobalContext); - let mut sched = ~UvEventLoop::new_scheduler(); - let task = ~do Coroutine::new(&mut sched.stack_pool) { - assert_eq!(context(), TaskContext); - let sched = Local::take::<Scheduler>(); - do sched.deschedule_running_task_and_then() |task| { - assert_eq!(context(), SchedulerContext); - let task = Cell(task); - do Local::borrow::<Scheduler> |sched| { - sched.enqueue_task(task.take()); - } - } - }; - sched.enqueue_task(task); - sched.run(); - } -} diff --git a/src/libcore/rt/rtio.rs b/src/libcore/rt/rtio.rs deleted file mode 100644 index 4b5eda22ff5..00000000000 --- a/src/libcore/rt/rtio.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use option::*; -use result::*; - -use rt::io::IoError; -use super::io::net::ip::IpAddr; -use rt::uv::uvio; - -// XXX: ~object doesn't work currently so these are some placeholder -// types to use instead -pub type EventLoopObject = uvio::UvEventLoop; -pub type IoFactoryObject = uvio::UvIoFactory; -pub type RtioTcpStreamObject = uvio::UvTcpStream; -pub type RtioTcpListenerObject = uvio::UvTcpListener; - -pub trait EventLoop { - fn run(&mut self); - fn callback(&mut self, ~fn()); - fn callback_ms(&mut self, ms: u64, ~fn()); - /// The asynchronous I/O services. Not all event loops may provide one - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject>; -} - -pub trait IoFactory { - fn tcp_connect(&mut self, addr: IpAddr) -> Result<~RtioTcpStreamObject, IoError>; - fn tcp_bind(&mut self, addr: IpAddr) -> Result<~RtioTcpListenerObject, IoError>; -} - -pub trait RtioTcpListener { - fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError>; -} - -pub trait RtioTcpStream { - fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError>; - fn write(&mut self, buf: &[u8]) -> Result<(), IoError>; -} diff --git a/src/libcore/rt/stack.rs b/src/libcore/rt/stack.rs deleted file mode 100644 index ec56e65931c..00000000000 --- a/src/libcore/rt/stack.rs +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use container::Container; -use ptr::Ptr; -use vec; -use ops::Drop; -use libc::{c_uint, uintptr_t}; - -pub struct StackSegment { - buf: ~[u8], - valgrind_id: c_uint -} - -pub impl StackSegment { - fn new(size: uint) -> StackSegment { - unsafe { - // Crate a block of uninitialized values - let mut stack = vec::with_capacity(size); - vec::raw::set_len(&mut stack, size); - - let mut stk = StackSegment { - buf: stack, - valgrind_id: 0 - }; - - // XXX: Using the FFI to call a C macro. Slow - stk.valgrind_id = rust_valgrind_stack_register(stk.start(), stk.end()); - return stk; - } - } - - /// Point to the low end of the allocated stack - fn start(&self) -> *uint { - vec::raw::to_ptr(self.buf) as *uint - } - - /// Point one word beyond the high end of the allocated stack - fn end(&self) -> *uint { - vec::raw::to_ptr(self.buf).offset(self.buf.len()) as *uint - } -} - -impl Drop for StackSegment { - fn finalize(&self) { - unsafe { - // XXX: Using the FFI to call a C macro. Slow - rust_valgrind_stack_deregister(self.valgrind_id); - } - } -} - -pub struct StackPool(()); - -impl StackPool { - pub fn new() -> StackPool { StackPool(()) } - - fn take_segment(&self, min_size: uint) -> StackSegment { - StackSegment::new(min_size) - } - - fn give_segment(&self, _stack: StackSegment) { - } -} - -extern { - fn rust_valgrind_stack_register(start: *uintptr_t, end: *uintptr_t) -> c_uint; - fn rust_valgrind_stack_deregister(id: c_uint); -} diff --git a/src/libcore/rt/task.rs b/src/libcore/rt/task.rs deleted file mode 100644 index 0314137fc7f..00000000000 --- a/src/libcore/rt/task.rs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Language-level runtime services that should reasonably expected -//! to be available 'everywhere'. Local heaps, GC, unwinding, -//! local storage, and logging. Even a 'freestanding' Rust would likely want -//! to implement this. - -use prelude::*; -use libc::{c_void, uintptr_t}; -use cast::transmute; -use super::sched::Scheduler; -use rt::local::Local; -use super::local_heap::LocalHeap; -use rt::logging::StdErrLogger; - -pub struct Task { - heap: LocalHeap, - gc: GarbageCollector, - storage: LocalStorage, - logger: StdErrLogger, - unwinder: Option<Unwinder>, - destroyed: bool -} - -pub struct GarbageCollector; -pub struct LocalStorage(*c_void, Option<~fn(*c_void)>); - -pub struct Unwinder { - unwinding: bool, -} - -impl Task { - pub fn new() -> Task { - Task { - heap: LocalHeap::new(), - gc: GarbageCollector, - storage: LocalStorage(ptr::null(), None), - logger: StdErrLogger, - unwinder: Some(Unwinder { unwinding: false }), - destroyed: false - } - } - - pub fn without_unwinding() -> Task { - Task { - heap: LocalHeap::new(), - gc: GarbageCollector, - storage: LocalStorage(ptr::null(), None), - logger: StdErrLogger, - unwinder: None, - destroyed: false - } - } - - pub fn run(&mut self, f: &fn()) { - // This is just an assertion that `run` was called unsafely - // and this instance of Task is still accessible. - do Local::borrow::<Task> |task| { - assert!(ptr::ref_eq(task, self)); - } - - match self.unwinder { - Some(ref mut unwinder) => { - // If there's an unwinder then set up the catch block - unwinder.try(f); - } - None => { - // Otherwise, just run the body - f() - } - } - self.destroy(); - } - - /// Must be called manually before finalization to clean up - /// thread-local resources. Some of the routines here expect - /// Task to be available recursively so this must be - /// called unsafely, without removing Task from - /// thread-local-storage. - fn destroy(&mut self) { - // This is just an assertion that `destroy` was called unsafely - // and this instance of Task is still accessible. - do Local::borrow::<Task> |task| { - assert!(ptr::ref_eq(task, self)); - } - match self.storage { - LocalStorage(ptr, Some(ref dtor)) => { - (*dtor)(ptr) - } - _ => () - } - self.destroyed = true; - } -} - -impl Drop for Task { - fn finalize(&self) { assert!(self.destroyed) } -} - -// Just a sanity check to make sure we are catching a Rust-thrown exception -static UNWIND_TOKEN: uintptr_t = 839147; - -impl Unwinder { - pub fn try(&mut self, f: &fn()) { - use sys::Closure; - - unsafe { - let closure: Closure = transmute(f); - let code = transmute(closure.code); - let env = transmute(closure.env); - - let token = rust_try(try_fn, code, env); - assert!(token == 0 || token == UNWIND_TOKEN); - } - - extern fn try_fn(code: *c_void, env: *c_void) { - unsafe { - let closure: Closure = Closure { - code: transmute(code), - env: transmute(env), - }; - let closure: &fn() = transmute(closure); - closure(); - } - } - - extern { - #[rust_stack] - fn rust_try(f: *u8, code: *c_void, data: *c_void) -> uintptr_t; - } - } - - pub fn begin_unwind(&mut self) -> ! { - self.unwinding = true; - unsafe { - rust_begin_unwind(UNWIND_TOKEN); - return transmute(()); - } - extern { - fn rust_begin_unwind(token: uintptr_t); - } - } -} - -#[cfg(test)] -mod test { - use rt::test::*; - - #[test] - fn local_heap() { - do run_in_newsched_task() { - let a = @5; - let b = a; - assert!(*a == 5); - assert!(*b == 5); - } - } - - #[test] - fn tls() { - use local_data::*; - do run_in_newsched_task() { - unsafe { - fn key(_x: @~str) { } - local_data_set(key, @~"data"); - assert!(*local_data_get(key).get() == ~"data"); - fn key2(_x: @~str) { } - local_data_set(key2, @~"data"); - assert!(*local_data_get(key2).get() == ~"data"); - } - } - } - - #[test] - fn unwind() { - do run_in_newsched_task() { - let result = spawntask_try(||()); - assert!(result.is_ok()); - let result = spawntask_try(|| fail!()); - assert!(result.is_err()); - } - } - - #[test] - fn rng() { - do run_in_newsched_task() { - use rand::{rng, Rng}; - let mut r = rng(); - let _ = r.next(); - } - } - - #[test] - fn logging() { - do run_in_newsched_task() { - info!("here i am. logging in a newsched task"); - } - } - - #[test] - fn comm_oneshot() { - use comm::*; - - do run_in_newsched_task { - let (port, chan) = oneshot(); - send_one(chan, 10); - assert!(recv_one(port) == 10); - } - } - - #[test] - fn comm_stream() { - use comm::*; - - do run_in_newsched_task() { - let (port, chan) = stream(); - chan.send(10); - assert!(port.recv() == 10); - } - } -} - diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs deleted file mode 100644 index c60ae2bfeff..00000000000 --- a/src/libcore/rt/test.rs +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use uint; -use option::*; -use cell::Cell; -use result::{Result, Ok, Err}; -use super::io::net::ip::{IpAddr, Ipv4}; -use rt::task::Task; -use rt::thread::Thread; -use rt::local::Local; - -/// Creates a new scheduler in a new thread and runs a task in it, -/// then waits for the scheduler to exit. Failure of the task -/// will abort the process. -pub fn run_in_newsched_task(f: ~fn()) { - use super::sched::*; - use unstable::run_in_bare_thread; - use rt::uv::uvio::UvEventLoop; - - let f = Cell(f); - - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f.take()); - sched.enqueue_task(task); - sched.run(); - } -} - -/// Test tasks will abort on failure instead of unwinding -pub fn spawntask(f: ~fn()) { - use super::sched::*; - - let mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); - do sched.switch_running_tasks_and_then(task) |task| { - let task = Cell(task); - let sched = Local::take::<Scheduler>(); - sched.schedule_new_task(task.take()); - } -} - -/// Create a new task and run it right now. Aborts on failure -pub fn spawntask_immediately(f: ~fn()) { - use super::sched::*; - - let mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); - do sched.switch_running_tasks_and_then(task) |task| { - let task = Cell(task); - do Local::borrow::<Scheduler> |sched| { - sched.enqueue_task(task.take()); - } - } -} - -/// Create a new task and run it right now. Aborts on failure -pub fn spawntask_later(f: ~fn()) { - use super::sched::*; - - let mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); - - sched.enqueue_task(task); - Local::put(sched); -} - -/// Spawn a task and either run it immediately or run it later -pub fn spawntask_random(f: ~fn()) { - use super::sched::*; - use rand::{Rand, rng}; - - let mut rng = rng(); - let run_now: bool = Rand::rand(&mut rng); - - let mut sched = Local::take::<Scheduler>(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f); - - if run_now { - do sched.switch_running_tasks_and_then(task) |task| { - let task = Cell(task); - do Local::borrow::<Scheduler> |sched| { - sched.enqueue_task(task.take()); - } - } - } else { - sched.enqueue_task(task); - Local::put(sched); - } -} - - -/// Spawn a task and wait for it to finish, returning whether it completed successfully or failed -pub fn spawntask_try(f: ~fn()) -> Result<(), ()> { - use cell::Cell; - use super::sched::*; - use task; - use unstable::finally::Finally; - - // Our status variables will be filled in from the scheduler context - let mut failed = false; - let failed_ptr: *mut bool = &mut failed; - - // Switch to the scheduler - let f = Cell(Cell(f)); - let sched = Local::take::<Scheduler>(); - do sched.deschedule_running_task_and_then() |old_task| { - let old_task = Cell(old_task); - let f = f.take(); - let mut sched = Local::take::<Scheduler>(); - let new_task = ~do Coroutine::new(&mut sched.stack_pool) { - do (|| { - (f.take())() - }).finally { - // Check for failure then resume the parent task - unsafe { *failed_ptr = task::failing(); } - let sched = Local::take::<Scheduler>(); - do sched.switch_running_tasks_and_then(old_task.take()) |new_task| { - let new_task = Cell(new_task); - do Local::borrow::<Scheduler> |sched| { - sched.enqueue_task(new_task.take()); - } - } - } - }; - - sched.resume_task_immediately(new_task); - } - - if !failed { Ok(()) } else { Err(()) } -} - -// Spawn a new task in a new scheduler and return a thread handle. -pub fn spawntask_thread(f: ~fn()) -> Thread { - use rt::sched::*; - use rt::uv::uvio::UvEventLoop; - - let f = Cell(f); - let thread = do Thread::start { - let mut sched = ~UvEventLoop::new_scheduler(); - let task = ~Coroutine::with_task(&mut sched.stack_pool, - ~Task::without_unwinding(), - f.take()); - sched.enqueue_task(task); - sched.run(); - }; - return thread; -} - -/// Get a port number, starting at 9600, for use in tests -pub fn next_test_port() -> u16 { - unsafe { - return rust_dbg_next_port() as u16; - } - extern { - fn rust_dbg_next_port() -> ::libc::uintptr_t; - } -} - -/// Get a unique localhost:port pair starting at 9600 -pub fn next_test_ip4() -> IpAddr { - Ipv4(127, 0, 0, 1, next_test_port()) -} - -/// Get a constant that represents the number of times to repeat stress tests. Default 1. -pub fn stress_factor() -> uint { - use os::getenv; - - match getenv("RUST_RT_STRESS") { - Some(val) => uint::from_str(val).get(), - None => 1 - } -} - diff --git a/src/libcore/rt/thread.rs b/src/libcore/rt/thread.rs deleted file mode 100644 index 0f1ae09bd94..00000000000 --- a/src/libcore/rt/thread.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use libc; -use ops::Drop; - -#[allow(non_camel_case_types)] // runtime type -type raw_thread = libc::c_void; - -pub struct Thread { - main: ~fn(), - raw_thread: *raw_thread -} - -pub impl Thread { - fn start(main: ~fn()) -> Thread { - fn substart(main: &~fn()) -> *raw_thread { - unsafe { rust_raw_thread_start(main) } - } - let raw = substart(&main); - Thread { - main: main, - raw_thread: raw - } - } -} - -impl Drop for Thread { - fn finalize(&self) { - unsafe { rust_raw_thread_join_delete(self.raw_thread) } - } -} - -extern { - pub unsafe fn rust_raw_thread_start(f: &(~fn())) -> *raw_thread; - pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread); -} diff --git a/src/libcore/rt/thread_local_storage.rs b/src/libcore/rt/thread_local_storage.rs deleted file mode 100644 index 7187d2db41c..00000000000 --- a/src/libcore/rt/thread_local_storage.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use libc::c_void; -#[cfg(unix)] -use libc::c_int; -#[cfg(unix)] -use ptr::null; -#[cfg(windows)] -use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL}; - -#[cfg(unix)] -pub type Key = pthread_key_t; - -#[cfg(unix)] -pub unsafe fn create(key: &mut Key) { - assert_eq!(0, pthread_key_create(key, null())); -} - -#[cfg(unix)] -pub unsafe fn set(key: Key, value: *mut c_void) { - assert_eq!(0, pthread_setspecific(key, value)); -} - -#[cfg(unix)] -pub unsafe fn get(key: Key) -> *mut c_void { - pthread_getspecific(key) -} - -#[cfg(target_os="macos")] -#[allow(non_camel_case_types)] // foreign type -type pthread_key_t = ::libc::c_ulong; - -#[cfg(target_os="linux")] -#[cfg(target_os="freebsd")] -#[cfg(target_os="android")] -#[allow(non_camel_case_types)] // foreign type -type pthread_key_t = ::libc::c_uint; - -#[cfg(unix)] -extern { - #[fast_ffi] - fn pthread_key_create(key: *mut pthread_key_t, dtor: *u8) -> c_int; - #[fast_ffi] - fn pthread_setspecific(key: pthread_key_t, value: *mut c_void) -> c_int; - #[fast_ffi] - fn pthread_getspecific(key: pthread_key_t) -> *mut c_void; -} - -#[cfg(windows)] -pub type Key = DWORD; - -#[cfg(windows)] -pub unsafe fn create(key: &mut Key) { - static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; - *key = unsafe { TlsAlloc() }; - assert!(*key != TLS_OUT_OF_INDEXES); -} - -#[cfg(windows)] -pub unsafe fn set(key: Key, value: *mut c_void) { - unsafe { assert!(0 != TlsSetValue(key, value)) } -} - -#[cfg(windows)] -pub unsafe fn get(key: Key) -> *mut c_void { - TlsGetValue(key) -} - -#[cfg(windows)] -#[abi = "stdcall"] -extern "stdcall" { - fn TlsAlloc() -> DWORD; - fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; - fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID; -} - -#[test] -fn tls_smoke_test() { - use cast::transmute; - unsafe { - let mut key = 0; - let value = ~20; - create(&mut key); - set(key, transmute(value)); - let value: ~int = transmute(get(key)); - assert_eq!(value, ~20); - let value = ~30; - set(key, transmute(value)); - let value: ~int = transmute(get(key)); - assert_eq!(value, ~30); - } -} diff --git a/src/libcore/rt/uv/file.rs b/src/libcore/rt/uv/file.rs deleted file mode 100644 index 2d145055097..00000000000 --- a/src/libcore/rt/uv/file.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use ptr::null; -use libc::c_void; -use rt::uv::{Request, NativeHandle, Loop, FsCallback}; -use rt::uv::uvll; -use rt::uv::uvll::*; - -pub struct FsRequest(*uvll::uv_fs_t); -impl Request for FsRequest; - -impl FsRequest { - fn new() -> 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) - } - - fn delete(self) { - unsafe { free_req(self.native_handle() as *c_void) } - } - - fn open(&mut self, _loop_: &Loop, _cb: FsCallback) { - } - - fn close(&mut self, _loop_: &Loop, _cb: FsCallback) { - } -} - -impl NativeHandle<*uvll::uv_fs_t> for FsRequest { - fn from_native_handle(handle: *uvll:: uv_fs_t) -> FsRequest { - FsRequest(handle) - } - fn native_handle(&self) -> *uvll::uv_fs_t { - match self { &FsRequest(ptr) => ptr } - } -} diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs deleted file mode 100644 index 2bd657fd864..00000000000 --- a/src/libcore/rt/uv/mod.rs +++ /dev/null @@ -1,420 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -Bindings to libuv, along with the default implementation of `core::rt::rtio`. - -UV types consist of the event loop (Loop), Watchers, Requests and -Callbacks. - -Watchers and Requests encapsulate pointers to uv *handles*, which have -subtyping relationships with each other. This subtyping is reflected -in the bindings with explicit or implicit coercions. For example, an -upcast from TcpWatcher to StreamWatcher is done with -`tcp_watcher.as_stream()`. In other cases a callback on a specific -type of watcher will be passed a watcher of a supertype. - -Currently all use of Request types (connect/write requests) are -encapsulated in the bindings and don't need to be dealt with by the -caller. - -# Safety note - -Due to the complex lifecycle of uv handles, as well as compiler bugs, -this module is not memory safe and requires explicit memory management, -via `close` and `delete` methods. - -*/ - -use container::Container; -use option::*; -use str::raw::from_c_str; -use to_str::ToStr; -use ptr::Ptr; -use libc; -use vec; -use ptr; -use cast; -use str; -use libc::{c_void, c_int, size_t, malloc, free}; -use cast::transmute; -use ptr::null; -use unstable::finally::Finally; - -use rt::io::IoError; - -#[cfg(test)] use unstable::run_in_bare_thread; - -pub use self::file::FsRequest; -pub use self::net::{StreamWatcher, TcpWatcher}; -pub use self::idle::IdleWatcher; -pub use self::timer::TimerWatcher; - -/// The implementation of `rtio` for libuv -pub mod uvio; - -/// C bindings to libuv -pub mod uvll; - -pub mod file; -pub mod net; -pub mod idle; -pub mod timer; - -/// XXX: Loop(*handle) is buggy with destructors. Normal structs -/// with dtors may not be destructured, but tuple structs can, -/// but the results are not correct. -pub struct Loop { - handle: *uvll::uv_loop_t -} - -/// The trait implemented by uv 'watchers' (handles). Watchers are -/// non-owning wrappers around the uv handles and are not completely -/// safe - there may be multiple instances for a single underlying -/// handle. Watchers are generally created, then `start`ed, `stop`ed -/// and `close`ed, but due to their complex life cycle may not be -/// entirely memory safe if used in unanticipated patterns. -pub trait Watcher { } - -pub trait Request { } - -/// A type that wraps a native handle -pub trait NativeHandle<T> { - pub fn from_native_handle(T) -> Self; - pub fn native_handle(&self) -> T; -} - -pub impl Loop { - fn new() -> Loop { - let handle = unsafe { uvll::loop_new() }; - assert!(handle.is_not_null()); - NativeHandle::from_native_handle(handle) - } - - fn run(&mut self) { - unsafe { uvll::run(self.native_handle()) }; - } - - fn close(&mut self) { - unsafe { uvll::loop_delete(self.native_handle()) }; - } -} - -impl NativeHandle<*uvll::uv_loop_t> for Loop { - fn from_native_handle(handle: *uvll::uv_loop_t) -> Loop { - Loop { handle: handle } - } - fn native_handle(&self) -> *uvll::uv_loop_t { - self.handle - } -} - -// XXX: The uv alloc callback also has a *uv_handle_t arg -pub type AllocCallback = ~fn(uint) -> Buf; -pub type ReadCallback = ~fn(StreamWatcher, int, Buf, Option<UvError>); -pub type NullCallback = ~fn(); -pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>); -pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>); -pub type FsCallback = ~fn(FsRequest, Option<UvError>); -pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>); - - -/// Callbacks used by StreamWatchers, set as custom data on the foreign handle -struct WatcherData { - read_cb: Option<ReadCallback>, - write_cb: Option<ConnectionCallback>, - connect_cb: Option<ConnectionCallback>, - close_cb: Option<NullCallback>, - alloc_cb: Option<AllocCallback>, - idle_cb: Option<IdleCallback>, - timer_cb: Option<TimerCallback> -} - -pub trait WatcherInterop { - fn event_loop(&self) -> Loop; - fn install_watcher_data(&mut self); - fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData; - fn drop_watcher_data(&mut self); -} - -impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W { - /// Get the uv event loop from a Watcher - pub fn event_loop(&self) -> Loop { - unsafe { - let handle = self.native_handle(); - let loop_ = uvll::get_loop_for_uv_handle(handle); - NativeHandle::from_native_handle(loop_) - } - } - - pub fn install_watcher_data(&mut self) { - unsafe { - let data = ~WatcherData { - read_cb: None, - write_cb: None, - connect_cb: None, - close_cb: None, - alloc_cb: None, - idle_cb: None, - timer_cb: None - }; - let data = transmute::<~WatcherData, *c_void>(data); - uvll::set_data_for_uv_handle(self.native_handle(), data); - } - } - - pub fn get_watcher_data<'r>(&'r mut self) -> &'r mut WatcherData { - unsafe { - let data = uvll::get_data_for_uv_handle(self.native_handle()); - let data = transmute::<&*c_void, &mut ~WatcherData>(&data); - return &mut **data; - } - } - - pub fn drop_watcher_data(&mut self) { - unsafe { - let data = uvll::get_data_for_uv_handle(self.native_handle()); - let _data = transmute::<*c_void, ~WatcherData>(data); - uvll::set_data_for_uv_handle(self.native_handle(), null::<()>()); - } - } -} - -// XXX: Need to define the error constants like EOF so they can be -// compared to the UvError type - -pub struct UvError(uvll::uv_err_t); - -pub impl UvError { - - fn name(&self) -> ~str { - unsafe { - let inner = match self { &UvError(ref a) => a }; - let name_str = uvll::err_name(inner); - assert!(name_str.is_not_null()); - from_c_str(name_str) - } - } - - fn desc(&self) -> ~str { - unsafe { - let inner = match self { &UvError(ref a) => a }; - let desc_str = uvll::strerror(inner); - assert!(desc_str.is_not_null()); - from_c_str(desc_str) - } - } - - fn is_eof(&self) -> bool { - self.code == uvll::EOF - } -} - -impl ToStr for UvError { - fn to_str(&self) -> ~str { - fmt!("%s: %s", self.name(), self.desc()) - } -} - -#[test] -fn error_smoke_test() { - let err = uvll::uv_err_t { code: 1, sys_errno_: 1 }; - let err: UvError = UvError(err); - assert_eq!(err.to_str(), ~"EOF: end of file"); -} - -pub fn last_uv_error<H, W: Watcher + NativeHandle<*H>>(watcher: &W) -> UvError { - unsafe { - let loop_ = watcher.event_loop(); - UvError(uvll::last_error(loop_.native_handle())) - } -} - -pub fn uv_error_to_io_error(uverr: UvError) -> IoError { - - // XXX: Could go in str::raw - unsafe fn c_str_to_static_slice(s: *libc::c_char) -> &'static str { - let s = s as *u8; - let mut curr = s, len = 0u; - while *curr != 0u8 { - len += 1u; - curr = ptr::offset(s, len); - } - - str::raw::buf_as_slice(s, len, |d| cast::transmute(d)) - } - - - unsafe { - // Importing error constants - use rt::uv::uvll::*; - use rt::io::*; - - // uv error descriptions are static - let c_desc = uvll::strerror(&*uverr); - let desc = c_str_to_static_slice(c_desc); - - let kind = match uverr.code { - UNKNOWN => OtherIoError, - OK => OtherIoError, - EOF => EndOfFile, - EACCES => PermissionDenied, - ECONNREFUSED => ConnectionRefused, - ECONNRESET => ConnectionReset, - EPIPE => BrokenPipe, - _ => { - rtdebug!("uverr.code %u", uverr.code as uint); - // XXX: Need to map remaining uv error types - OtherIoError - } - }; - - IoError { - kind: kind, - desc: desc, - detail: None - } - } -} - -/// Given a uv handle, convert a callback status to a UvError -// XXX: Follow the pattern below by parameterizing over T: Watcher, not T -pub fn status_to_maybe_uv_error<T>(handle: *T, status: c_int) -> Option<UvError> { - if status != -1 { - None - } else { - unsafe { - rtdebug!("handle: %x", handle as uint); - let loop_ = uvll::get_loop_for_uv_handle(handle); - rtdebug!("loop: %x", loop_ as uint); - let err = uvll::last_error(loop_); - Some(UvError(err)) - } - } -} - -/// The uv buffer type -pub type Buf = uvll::uv_buf_t; - -/// Borrow a slice to a Buf -pub fn slice_to_uv_buf(v: &[u8]) -> Buf { - let data = vec::raw::to_ptr(v); - unsafe { uvll::buf_init(data, v.len()) } -} - -// XXX: Do these conversions without copying - -/// Transmute an owned vector to a Buf -pub fn vec_to_uv_buf(v: ~[u8]) -> Buf { - unsafe { - let data = malloc(v.len() as size_t) as *u8; - assert!(data.is_not_null()); - do vec::as_imm_buf(v) |b, l| { - let data = data as *mut u8; - ptr::copy_memory(data, b, l) - } - uvll::buf_init(data, v.len()) - } -} - -/// Transmute a Buf that was once a ~[u8] back to ~[u8] -pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> { - if !(buf.len == 0 && buf.base.is_null()) { - let v = unsafe { vec::from_buf(buf.base, buf.len as uint) }; - unsafe { free(buf.base as *c_void) }; - return Some(v); - } else { - // No buffer - rtdebug!("No buffer!"); - return None; - } -} - -#[test] -fn test_slice_to_uv_buf() { - let slice = [0, .. 20]; - let buf = slice_to_uv_buf(slice); - - assert!(buf.len == 20); - - unsafe { - let base = transmute::<*u8, *mut u8>(buf.base); - (*base) = 1; - (*ptr::mut_offset(base, 1)) = 2; - } - - assert!(slice[0] == 1); - assert!(slice[1] == 2); -} - - -#[test] -fn loop_smoke_test() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - loop_.run(); - loop_.close(); - } -} - -#[test] -#[ignore(reason = "valgrind - loop destroyed before watcher?")] -fn idle_new_then_close() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let idle_watcher = { IdleWatcher::new(&mut loop_) }; - idle_watcher.close(||()); - } -} - -#[test] -fn idle_smoke_test() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let mut idle_watcher = { IdleWatcher::new(&mut loop_) }; - let mut count = 10; - let count_ptr: *mut int = &mut count; - do idle_watcher.start |idle_watcher, status| { - let mut idle_watcher = idle_watcher; - assert!(status.is_none()); - if unsafe { *count_ptr == 10 } { - idle_watcher.stop(); - idle_watcher.close(||()); - } else { - unsafe { *count_ptr = *count_ptr + 1; } - } - } - loop_.run(); - loop_.close(); - assert_eq!(count, 10); - } -} - -#[test] -fn idle_start_stop_start() { - do run_in_bare_thread { - let mut loop_ = Loop::new(); - let mut idle_watcher = { IdleWatcher::new(&mut loop_) }; - do idle_watcher.start |idle_watcher, status| { - let mut idle_watcher = idle_watcher; - assert!(status.is_none()); - idle_watcher.stop(); - do idle_watcher.start |idle_watcher, status| { - assert!(status.is_none()); - let mut idle_watcher = idle_watcher; - idle_watcher.stop(); - idle_watcher.close(||()); - } - } - loop_.run(); - loop_.close(); - } -} diff --git a/src/libcore/rt/uv/net.rs b/src/libcore/rt/uv/net.rs deleted file mode 100644 index 68b871e6b31..00000000000 --- a/src/libcore/rt/uv/net.rs +++ /dev/null @@ -1,436 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; -use libc::{size_t, ssize_t, c_int, c_void}; -use rt::uv::uvll; -use rt::uv::uvll::*; -use rt::uv::{AllocCallback, ConnectionCallback, ReadCallback}; -use rt::uv::{Loop, Watcher, Request, UvError, Buf, NativeHandle, NullCallback, - status_to_maybe_uv_error}; -use rt::io::net::ip::{IpAddr, Ipv4, Ipv6}; -use rt::uv::last_uv_error; - -fn ip4_as_uv_ip4<T>(addr: IpAddr, f: &fn(*sockaddr_in) -> T) -> T { - match addr { - Ipv4(a, b, c, d, p) => { - unsafe { - let addr = malloc_ip4_addr(fmt!("%u.%u.%u.%u", - a as uint, - b as uint, - c as uint, - d as uint), p as int); - do (|| { - f(addr) - }).finally { - free_ip4_addr(addr); - } - } - } - Ipv6 => fail!() - } -} - -// uv_stream t is the parent class of uv_tcp_t, uv_pipe_t, uv_tty_t -// and uv_file_t -pub struct StreamWatcher(*uvll::uv_stream_t); -impl Watcher for StreamWatcher { } - -pub impl StreamWatcher { - - fn read_start(&mut self, alloc: AllocCallback, cb: ReadCallback) { - { - let data = self.get_watcher_data(); - data.alloc_cb = Some(alloc); - data.read_cb = Some(cb); - } - - let handle = self.native_handle(); - unsafe { uvll::read_start(handle, alloc_cb, read_cb); } - - extern fn alloc_cb(stream: *uvll::uv_stream_t, suggested_size: size_t) -> Buf { - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream); - let data = stream_watcher.get_watcher_data(); - let alloc_cb = data.alloc_cb.get_ref(); - return (*alloc_cb)(suggested_size as uint); - } - - extern fn read_cb(stream: *uvll::uv_stream_t, nread: ssize_t, buf: Buf) { - rtdebug!("buf addr: %x", buf.base as uint); - rtdebug!("buf len: %d", buf.len as int); - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(stream); - let data = stream_watcher.get_watcher_data(); - let cb = data.read_cb.get_ref(); - let status = status_to_maybe_uv_error(stream, nread as c_int); - (*cb)(stream_watcher, nread as int, buf, status); - } - } - - fn read_stop(&mut self) { - // It would be nice to drop the alloc and read callbacks here, - // but read_stop may be called from inside one of them and we - // would end up freeing the in-use environment - let handle = self.native_handle(); - unsafe { uvll::read_stop(handle); } - } - - fn write(&mut self, buf: Buf, cb: ConnectionCallback) { - { - let data = self.get_watcher_data(); - assert!(data.write_cb.is_none()); - data.write_cb = Some(cb); - } - - let req = WriteRequest::new(); - let bufs = [buf]; - unsafe { - assert!(0 == uvll::write(req.native_handle(), - self.native_handle(), - bufs, write_cb)); - } - - extern fn write_cb(req: *uvll::uv_write_t, status: c_int) { - let write_request: WriteRequest = NativeHandle::from_native_handle(req); - let mut stream_watcher = write_request.stream(); - write_request.delete(); - let cb = { - let data = stream_watcher.get_watcher_data(); - let cb = data.write_cb.swap_unwrap(); - cb - }; - let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); - cb(stream_watcher, status); - } - } - - fn accept(&mut self, stream: StreamWatcher) { - let self_handle = self.native_handle() as *c_void; - let stream_handle = stream.native_handle() as *c_void; - unsafe { - assert_eq!(0, uvll::accept(self_handle, stream_handle)); - } - } - - fn close(self, cb: NullCallback) { - { - let mut this = self; - let data = this.get_watcher_data(); - assert!(data.close_cb.is_none()); - data.close_cb = Some(cb); - } - - unsafe { uvll::close(self.native_handle(), close_cb); } - - extern fn close_cb(handle: *uvll::uv_stream_t) { - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - { - let data = stream_watcher.get_watcher_data(); - data.close_cb.swap_unwrap()(); - } - stream_watcher.drop_watcher_data(); - unsafe { free_handle(handle as *c_void) } - } - } -} - -impl NativeHandle<*uvll::uv_stream_t> for StreamWatcher { - fn from_native_handle( - handle: *uvll::uv_stream_t) -> StreamWatcher { - StreamWatcher(handle) - } - fn native_handle(&self) -> *uvll::uv_stream_t { - match self { &StreamWatcher(ptr) => ptr } - } -} - -pub struct TcpWatcher(*uvll::uv_tcp_t); -impl Watcher for TcpWatcher { } - -pub impl TcpWatcher { - fn new(loop_: &mut Loop) -> TcpWatcher { - unsafe { - let handle = malloc_handle(UV_TCP); - assert!(handle.is_not_null()); - assert_eq!(0, uvll::tcp_init(loop_.native_handle(), handle)); - let mut watcher: TcpWatcher = NativeHandle::from_native_handle(handle); - watcher.install_watcher_data(); - return watcher; - } - } - - fn bind(&mut self, address: IpAddr) -> Result<(), UvError> { - match address { - Ipv4(*) => { - do ip4_as_uv_ip4(address) |addr| { - let result = unsafe { - uvll::tcp_bind(self.native_handle(), addr) - }; - if result == 0 { - Ok(()) - } else { - Err(last_uv_error(self)) - } - } - } - _ => fail!() - } - } - - fn connect(&mut self, address: IpAddr, cb: ConnectionCallback) { - unsafe { - assert!(self.get_watcher_data().connect_cb.is_none()); - self.get_watcher_data().connect_cb = Some(cb); - - let connect_handle = ConnectRequest::new().native_handle(); - match address { - Ipv4(*) => { - do ip4_as_uv_ip4(address) |addr| { - rtdebug!("connect_t: %x", connect_handle as uint); - assert!(0 == uvll::tcp_connect(connect_handle, - self.native_handle(), - addr, connect_cb)); - } - } - _ => fail!() - } - - extern fn connect_cb(req: *uvll::uv_connect_t, status: c_int) { - rtdebug!("connect_t: %x", req as uint); - let connect_request: ConnectRequest = NativeHandle::from_native_handle(req); - let mut stream_watcher = connect_request.stream(); - connect_request.delete(); - let cb: ConnectionCallback = { - let data = stream_watcher.get_watcher_data(); - data.connect_cb.swap_unwrap() - }; - let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); - cb(stream_watcher, status); - } - } - } - - fn listen(&mut self, cb: ConnectionCallback) { - { - let data = self.get_watcher_data(); - assert!(data.connect_cb.is_none()); - data.connect_cb = Some(cb); - } - - unsafe { - static BACKLOG: c_int = 128; // XXX should be configurable - // XXX: This can probably fail - assert!(0 == uvll::listen(self.native_handle(), - BACKLOG, connection_cb)); - } - - extern fn connection_cb(handle: *uvll::uv_stream_t, status: c_int) { - rtdebug!("connection_cb"); - let mut stream_watcher: StreamWatcher = NativeHandle::from_native_handle(handle); - let data = stream_watcher.get_watcher_data(); - let cb = data.connect_cb.get_ref(); - let status = status_to_maybe_uv_error(handle, status); - (*cb)(stream_watcher, status); - } - } - - fn as_stream(&self) -> StreamWatcher { - NativeHandle::from_native_handle(self.native_handle() as *uvll::uv_stream_t) - } -} - -impl NativeHandle<*uvll::uv_tcp_t> for TcpWatcher { - fn from_native_handle(handle: *uvll::uv_tcp_t) -> TcpWatcher { - TcpWatcher(handle) - } - fn native_handle(&self) -> *uvll::uv_tcp_t { - match self { &TcpWatcher(ptr) => ptr } - } -} - -// uv_connect_t is a subclass of uv_req_t -struct ConnectRequest(*uvll::uv_connect_t); -impl Request for ConnectRequest { } - -impl ConnectRequest { - - fn new() -> ConnectRequest { - let connect_handle = unsafe { - malloc_req(UV_CONNECT) - }; - assert!(connect_handle.is_not_null()); - let connect_handle = connect_handle as *uvll::uv_connect_t; - ConnectRequest(connect_handle) - } - - fn stream(&self) -> StreamWatcher { - unsafe { - let stream_handle = uvll::get_stream_handle_from_connect_req(self.native_handle()); - NativeHandle::from_native_handle(stream_handle) - } - } - - fn delete(self) { - unsafe { free_req(self.native_handle() as *c_void) } - } -} - -impl NativeHandle<*uvll::uv_connect_t> for ConnectRequest { - fn from_native_handle( - handle: *uvll:: uv_connect_t) -> ConnectRequest { - ConnectRequest(handle) - } - fn native_handle(&self) -> *uvll::uv_connect_t { - match self { &ConnectRequest(ptr) => ptr } - } -} - -pub struct WriteRequest(*uvll::uv_write_t); - -impl Request for WriteRequest { } - -pub impl WriteRequest { - - fn new() -> WriteRequest { - let write_handle = unsafe { - malloc_req(UV_WRITE) - }; - assert!(write_handle.is_not_null()); - let write_handle = write_handle as *uvll::uv_write_t; - WriteRequest(write_handle) - } - - fn stream(&self) -> StreamWatcher { - unsafe { - let stream_handle = uvll::get_stream_handle_from_write_req(self.native_handle()); - NativeHandle::from_native_handle(stream_handle) - } - } - - fn delete(self) { - unsafe { free_req(self.native_handle() as *c_void) } - } -} - -impl NativeHandle<*uvll::uv_write_t> for WriteRequest { - fn from_native_handle(handle: *uvll:: uv_write_t) -> WriteRequest { - WriteRequest(handle) - } - fn native_handle(&self) -> *uvll::uv_write_t { - match self { &WriteRequest(ptr) => ptr } - } -} - - -#[cfg(test)] -mod test { - use super::*; - use util::ignore; - use cell::Cell; - use vec; - use unstable::run_in_bare_thread; - use rt::thread::Thread; - use rt::test::*; - use rt::uv::{Loop, AllocCallback}; - use rt::uv::{vec_from_uv_buf, vec_to_uv_buf, slice_to_uv_buf}; - - #[test] - fn connect_close() { - do run_in_bare_thread() { - let mut loop_ = Loop::new(); - let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; - // Connect to a port where nobody is listening - let addr = next_test_ip4(); - do tcp_watcher.connect(addr) |stream_watcher, status| { - rtdebug!("tcp_watcher.connect!"); - assert!(status.is_some()); - assert_eq!(status.get().name(), ~"ECONNREFUSED"); - stream_watcher.close(||()); - } - loop_.run(); - loop_.close(); - } - } - - #[test] - fn listen() { - do run_in_bare_thread() { - static MAX: int = 10; - let mut loop_ = Loop::new(); - let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) }; - let addr = next_test_ip4(); - server_tcp_watcher.bind(addr); - let loop_ = loop_; - rtdebug!("listening"); - do server_tcp_watcher.listen |server_stream_watcher, status| { - rtdebug!("listened!"); - assert!(status.is_none()); - let mut server_stream_watcher = server_stream_watcher; - let mut loop_ = loop_; - let client_tcp_watcher = TcpWatcher::new(&mut loop_); - let mut client_tcp_watcher = client_tcp_watcher.as_stream(); - server_stream_watcher.accept(client_tcp_watcher); - let count_cell = Cell(0); - let server_stream_watcher = server_stream_watcher; - rtdebug!("starting read"); - let alloc: AllocCallback = |size| { - vec_to_uv_buf(vec::from_elem(size, 0)) - }; - do client_tcp_watcher.read_start(alloc) - |stream_watcher, nread, buf, status| { - - rtdebug!("i'm reading!"); - let buf = vec_from_uv_buf(buf); - let mut count = count_cell.take(); - if status.is_none() { - rtdebug!("got %d bytes", nread); - let buf = buf.unwrap(); - for buf.slice(0, nread as uint).each |byte| { - assert!(*byte == count as u8); - rtdebug!("%u", *byte as uint); - count += 1; - } - } else { - assert_eq!(count, MAX); - do stream_watcher.close { - server_stream_watcher.close(||()); - } - } - count_cell.put_back(count); - } - } - - let _client_thread = do Thread::start { - rtdebug!("starting client thread"); - let mut loop_ = Loop::new(); - let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; - do tcp_watcher.connect(addr) |stream_watcher, status| { - rtdebug!("connecting"); - assert!(status.is_none()); - let mut stream_watcher = stream_watcher; - let msg = ~[0, 1, 2, 3, 4, 5, 6 ,7 ,8, 9]; - let buf = slice_to_uv_buf(msg); - let msg_cell = Cell(msg); - do stream_watcher.write(buf) |stream_watcher, status| { - rtdebug!("writing"); - assert!(status.is_none()); - let msg_cell = Cell(msg_cell.take()); - stream_watcher.close(||ignore(msg_cell.take())); - } - } - loop_.run(); - loop_.close(); - }; - - let mut loop_ = loop_; - loop_.run(); - loop_.close(); - } - } -} diff --git a/src/libcore/rt/uv/uvio.rs b/src/libcore/rt/uv/uvio.rs deleted file mode 100644 index cacd67314eb..00000000000 --- a/src/libcore/rt/uv/uvio.rs +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use option::*; -use result::*; -use ops::Drop; -use cell::{Cell, empty_cell}; -use cast::transmute; -use clone::Clone; -use rt::io::IoError; -use rt::io::net::ip::IpAddr; -use rt::uv::*; -use rt::uv::idle::IdleWatcher; -use rt::rtio::*; -use rt::sched::Scheduler; -use rt::io::{standard_error, OtherIoError}; -use rt::tube::Tube; -use rt::local::Local; - -#[cfg(test)] use container::Container; -#[cfg(test)] use uint; -#[cfg(test)] use unstable::run_in_bare_thread; -#[cfg(test)] use rt::test::*; - -pub struct UvEventLoop { - uvio: UvIoFactory -} - -pub impl UvEventLoop { - fn new() -> UvEventLoop { - UvEventLoop { - uvio: UvIoFactory(Loop::new()) - } - } - - /// A convenience constructor - fn new_scheduler() -> Scheduler { - Scheduler::new(~UvEventLoop::new()) - } -} - -impl Drop for UvEventLoop { - fn finalize(&self) { - // XXX: Need mutable finalizer - let this = unsafe { - transmute::<&UvEventLoop, &mut UvEventLoop>(self) - }; - this.uvio.uv_loop().close(); - } -} - -impl EventLoop for UvEventLoop { - - fn run(&mut self) { - self.uvio.uv_loop().run(); - } - - fn callback(&mut self, f: ~fn()) { - let mut idle_watcher = IdleWatcher::new(self.uvio.uv_loop()); - do idle_watcher.start |idle_watcher, status| { - assert!(status.is_none()); - let mut idle_watcher = idle_watcher; - idle_watcher.stop(); - idle_watcher.close(||()); - f(); - } - } - - fn callback_ms(&mut self, ms: u64, f: ~fn()) { - let mut timer = TimerWatcher::new(self.uvio.uv_loop()); - do timer.start(ms, 0) |timer, status| { - assert!(status.is_none()); - timer.close(||()); - f(); - } - } - - fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { - Some(&mut self.uvio) - } -} - -#[test] -fn test_callback_run_once() { - do run_in_bare_thread { - let mut event_loop = UvEventLoop::new(); - let mut count = 0; - let count_ptr: *mut int = &mut count; - do event_loop.callback { - unsafe { *count_ptr += 1 } - } - event_loop.run(); - assert_eq!(count, 1); - } -} - -pub struct UvIoFactory(Loop); - -pub impl UvIoFactory { - fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { - match self { &UvIoFactory(ref mut ptr) => ptr } - } -} - -impl IoFactory for UvIoFactory { - // Connect to an address and return a new stream - // NB: This blocks the task waiting on the connection. - // It would probably be better to return a future - fn tcp_connect(&mut self, addr: IpAddr) -> Result<~RtioTcpStreamObject, IoError> { - // Create a cell in the task to hold the result. We will fill - // the cell before resuming the task. - let result_cell = empty_cell(); - let result_cell_ptr: *Cell<Result<~RtioTcpStreamObject, IoError>> = &result_cell; - - let scheduler = Local::take::<Scheduler>(); - assert!(scheduler.in_task_context()); - - // Block this task and take ownership, switch to scheduler context - do scheduler.deschedule_running_task_and_then |task| { - - rtdebug!("connect: entered scheduler context"); - do Local::borrow::<Scheduler> |scheduler| { - assert!(!scheduler.in_task_context()); - } - let mut tcp_watcher = TcpWatcher::new(self.uv_loop()); - let task_cell = Cell(task); - - // Wait for a connection - do tcp_watcher.connect(addr) |stream_watcher, status| { - rtdebug!("connect: in connect callback"); - if status.is_none() { - rtdebug!("status is none"); - let res = Ok(~UvTcpStream { watcher: stream_watcher }); - - // Store the stream in the task's stack - unsafe { (*result_cell_ptr).put_back(res); } - - // Context switch - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } else { - rtdebug!("status is some"); - let task_cell = Cell(task_cell.take()); - do stream_watcher.close { - let res = Err(uv_error_to_io_error(status.get())); - unsafe { (*result_cell_ptr).put_back(res); } - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - }; - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } - - fn tcp_bind(&mut self, addr: IpAddr) -> Result<~RtioTcpListenerObject, IoError> { - let mut watcher = TcpWatcher::new(self.uv_loop()); - match watcher.bind(addr) { - Ok(_) => Ok(~UvTcpListener::new(watcher)), - Err(uverr) => { - let scheduler = Local::take::<Scheduler>(); - do scheduler.deschedule_running_task_and_then |task| { - let task_cell = Cell(task); - do watcher.as_stream().close { - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - Err(uv_error_to_io_error(uverr)) - } - } - } -} - -// FIXME #6090: Prefer newtype structs but Drop doesn't work -pub struct UvTcpListener { - watcher: TcpWatcher, - listening: bool, - incoming_streams: Tube<Result<~RtioTcpStreamObject, IoError>> -} - -impl UvTcpListener { - fn new(watcher: TcpWatcher) -> UvTcpListener { - UvTcpListener { - watcher: watcher, - listening: false, - incoming_streams: Tube::new() - } - } - - fn watcher(&self) -> TcpWatcher { self.watcher } -} - -impl Drop for UvTcpListener { - fn finalize(&self) { - let watcher = self.watcher(); - let scheduler = Local::take::<Scheduler>(); - do scheduler.deschedule_running_task_and_then |task| { - let task_cell = Cell(task); - do watcher.as_stream().close { - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - } -} - -impl RtioTcpListener for UvTcpListener { - - fn accept(&mut self) -> Result<~RtioTcpStreamObject, IoError> { - rtdebug!("entering listen"); - - if self.listening { - return self.incoming_streams.recv(); - } - - self.listening = true; - - let server_tcp_watcher = self.watcher(); - let incoming_streams_cell = Cell(self.incoming_streams.clone()); - - let incoming_streams_cell = Cell(incoming_streams_cell.take()); - let mut server_tcp_watcher = server_tcp_watcher; - do server_tcp_watcher.listen |server_stream_watcher, status| { - let maybe_stream = if status.is_none() { - let mut server_stream_watcher = server_stream_watcher; - let mut loop_ = server_stream_watcher.event_loop(); - let client_tcp_watcher = TcpWatcher::new(&mut loop_); - let client_tcp_watcher = client_tcp_watcher.as_stream(); - // XXX: Need's to be surfaced in interface - server_stream_watcher.accept(client_tcp_watcher); - Ok(~UvTcpStream { watcher: client_tcp_watcher }) - } else { - Err(standard_error(OtherIoError)) - }; - - let mut incoming_streams = incoming_streams_cell.take(); - incoming_streams.send(maybe_stream); - incoming_streams_cell.put_back(incoming_streams); - } - - return self.incoming_streams.recv(); - } -} - -// FIXME #6090: Prefer newtype structs but Drop doesn't work -pub struct UvTcpStream { - watcher: StreamWatcher -} - -impl UvTcpStream { - fn watcher(&self) -> StreamWatcher { self.watcher } -} - -impl Drop for UvTcpStream { - fn finalize(&self) { - rtdebug!("closing tcp stream"); - let watcher = self.watcher(); - let scheduler = Local::take::<Scheduler>(); - do scheduler.deschedule_running_task_and_then |task| { - let task_cell = Cell(task); - do watcher.close { - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - } -} - -impl RtioTcpStream for UvTcpStream { - fn read(&mut self, buf: &mut [u8]) -> Result<uint, IoError> { - let result_cell = empty_cell(); - let result_cell_ptr: *Cell<Result<uint, IoError>> = &result_cell; - - let scheduler = Local::take::<Scheduler>(); - assert!(scheduler.in_task_context()); - let watcher = self.watcher(); - let buf_ptr: *&mut [u8] = &buf; - do scheduler.deschedule_running_task_and_then |task| { - rtdebug!("read: entered scheduler context"); - do Local::borrow::<Scheduler> |scheduler| { - assert!(!scheduler.in_task_context()); - } - let mut watcher = watcher; - let task_cell = Cell(task); - // XXX: We shouldn't reallocate these callbacks every - // call to read - let alloc: AllocCallback = |_| unsafe { - slice_to_uv_buf(*buf_ptr) - }; - do watcher.read_start(alloc) |watcher, nread, _buf, status| { - - // Stop reading so that no read callbacks are - // triggered before the user calls `read` again. - // XXX: Is there a performance impact to calling - // stop here? - let mut watcher = watcher; - watcher.read_stop(); - - let result = if status.is_none() { - assert!(nread >= 0); - Ok(nread as uint) - } else { - Err(uv_error_to_io_error(status.unwrap())) - }; - - unsafe { (*result_cell_ptr).put_back(result); } - - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } - - fn write(&mut self, buf: &[u8]) -> Result<(), IoError> { - let result_cell = empty_cell(); - let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell; - let scheduler = Local::take::<Scheduler>(); - assert!(scheduler.in_task_context()); - let watcher = self.watcher(); - let buf_ptr: *&[u8] = &buf; - do scheduler.deschedule_running_task_and_then |task| { - let mut watcher = watcher; - let task_cell = Cell(task); - let buf = unsafe { slice_to_uv_buf(*buf_ptr) }; - do watcher.write(buf) |_watcher, status| { - let result = if status.is_none() { - Ok(()) - } else { - Err(uv_error_to_io_error(status.unwrap())) - }; - - unsafe { (*result_cell_ptr).put_back(result); } - - let scheduler = Local::take::<Scheduler>(); - scheduler.resume_task_immediately(task_cell.take()); - } - } - - assert!(!result_cell.is_empty()); - return result_cell.take(); - } -} - -#[test] -fn test_simple_io_no_connect() { - do run_in_newsched_task { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let addr = next_test_ip4(); - let maybe_chan = (*io).tcp_connect(addr); - assert!(maybe_chan.is_err()); - } - } -} - -#[test] -fn test_simple_tcp_server_and_client() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - // Start the server first so it's listening when we connect - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut listener = (*io).tcp_bind(addr).unwrap(); - let mut stream = listener.accept().unwrap(); - let mut buf = [0, .. 2048]; - let nread = stream.read(buf).unwrap(); - assert_eq!(nread, 8); - for uint::range(0, nread) |i| { - rtdebug!("%u", buf[i] as uint); - assert_eq!(buf[i], i as u8); - } - } - } - - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut stream = (*io).tcp_connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - } - } - } -} - -#[test] #[ignore(reason = "busted")] -fn test_read_and_block() { - do run_in_newsched_task { - let addr = next_test_ip4(); - - do spawntask_immediately { - let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() }; - let mut listener = unsafe { (*io).tcp_bind(addr).unwrap() }; - let mut stream = listener.accept().unwrap(); - let mut buf = [0, .. 2048]; - - let expected = 32; - let mut current = 0; - let mut reads = 0; - - while current < expected { - let nread = stream.read(buf).unwrap(); - for uint::range(0, nread) |i| { - let val = buf[i] as uint; - assert_eq!(val, current % 8); - current += 1; - } - reads += 1; - - let scheduler = Local::take::<Scheduler>(); - // Yield to the other task in hopes that it - // will trigger a read callback while we are - // not ready for it - do scheduler.deschedule_running_task_and_then |task| { - let task = Cell(task); - do Local::borrow::<Scheduler> |scheduler| { - scheduler.enqueue_task(task.take()); - } - } - } - - // Make sure we had multiple reads - assert!(reads > 1); - } - - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut stream = (*io).tcp_connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - } - } - - } -} - -#[test] -fn test_read_read_read() { - do run_in_newsched_task { - let addr = next_test_ip4(); - static MAX: uint = 500000; - - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut listener = (*io).tcp_bind(addr).unwrap(); - let mut stream = listener.accept().unwrap(); - let buf = [1, .. 2048]; - let mut total_bytes_written = 0; - while total_bytes_written < MAX { - stream.write(buf); - total_bytes_written += buf.len(); - } - } - } - - do spawntask_immediately { - unsafe { - let io = Local::unsafe_borrow::<IoFactoryObject>(); - let mut stream = (*io).tcp_connect(addr).unwrap(); - let mut buf = [0, .. 2048]; - let mut total_bytes_read = 0; - while total_bytes_read < MAX { - let nread = stream.read(buf).unwrap(); - rtdebug!("read %u bytes", nread as uint); - total_bytes_read += nread; - for uint::range(0, nread) |i| { - assert_eq!(buf[i], 1); - } - } - rtdebug!("read %u bytes total", total_bytes_read as uint); - } - } - } -} diff --git a/src/libcore/rt/uv/uvll.rs b/src/libcore/rt/uv/uvll.rs deleted file mode 100644 index ddc9040d730..00000000000 --- a/src/libcore/rt/uv/uvll.rs +++ /dev/null @@ -1,452 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - * Low-level bindings to the libuv library. - * - * This module contains a set of direct, 'bare-metal' wrappers around - * the libuv C-API. - * - * We're not bothering yet to redefine uv's structs as Rust structs - * because they are quite large and change often between versions. - * The maintenance burden is just too high. Instead we use the uv's - * `uv_handle_size` and `uv_req_size` to find the correct size of the - * structs and allocate them on the heap. This can be revisited later. - * - * There are also a collection of helper functions to ease interacting - * with the low-level API. - * - * As new functionality, existant in uv.h, is added to the rust stdlib, - * the mappings should be added in this module. - */ - -#[allow(non_camel_case_types)]; // C types - -use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t}; -use libc::{malloc, free}; -use prelude::*; - -pub static UNKNOWN: c_int = -1; -pub static OK: c_int = 0; -pub static EOF: c_int = 1; -pub static EADDRINFO: c_int = 2; -pub static EACCES: c_int = 3; -pub static ECONNREFUSED: c_int = 12; -pub static ECONNRESET: c_int = 13; -pub static EPIPE: c_int = 36; - -pub struct uv_err_t { - code: c_int, - sys_errno_: c_int -} - -pub struct uv_buf_t { - base: *u8, - len: libc::size_t, -} - -pub type uv_handle_t = c_void; -pub type uv_loop_t = c_void; -pub type uv_idle_t = c_void; -pub type uv_tcp_t = c_void; -pub type uv_connect_t = c_void; -pub type uv_write_t = c_void; -pub type uv_async_t = c_void; -pub type uv_timer_t = c_void; -pub type uv_stream_t = c_void; -pub type uv_fs_t = c_void; - -pub type uv_idle_cb = *u8; - -pub type sockaddr_in = c_void; -pub type sockaddr_in6 = c_void; - -#[deriving(Eq)] -pub enum uv_handle_type { - UV_UNKNOWN_HANDLE, - UV_ASYNC, - UV_CHECK, - UV_FS_EVENT, - UV_FS_POLL, - UV_HANDLE, - UV_IDLE, - UV_NAMED_PIPE, - UV_POLL, - UV_PREPARE, - UV_PROCESS, - UV_STREAM, - UV_TCP, - UV_TIMER, - UV_TTY, - UV_UDP, - UV_SIGNAL, - UV_FILE, - UV_HANDLE_TYPE_MAX -} - -#[deriving(Eq)] -pub enum uv_req_type { - UV_UNKNOWN_REQ, - UV_REQ, - UV_CONNECT, - UV_WRITE, - UV_SHUTDOWN, - UV_UDP_SEND, - UV_FS, - UV_WORK, - UV_GETADDRINFO, - UV_REQ_TYPE_MAX -} - -pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void { - assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX); - let size = rust_uv_handle_size(handle as uint); - let p = malloc(size); - assert!(p.is_not_null()); - return p; -} - -pub unsafe fn free_handle(v: *c_void) { - free(v) -} - -pub unsafe fn malloc_req(req: uv_req_type) -> *c_void { - assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX); - let size = rust_uv_req_size(req as uint); - let p = malloc(size); - assert!(p.is_not_null()); - return p; -} - -pub unsafe fn free_req(v: *c_void) { - free(v) -} - -#[test] -fn handle_sanity_check() { - unsafe { - assert_eq!(UV_HANDLE_TYPE_MAX as uint, rust_uv_handle_type_max()); - } -} - -#[test] -fn request_sanity_check() { - unsafe { - assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max()); - } -} - -pub unsafe fn loop_new() -> *c_void { - return rust_uv_loop_new(); -} - -pub unsafe fn loop_delete(loop_handle: *c_void) { - rust_uv_loop_delete(loop_handle); -} - -pub unsafe fn run(loop_handle: *c_void) { - rust_uv_run(loop_handle); -} - -pub unsafe fn close<T>(handle: *T, cb: *u8) { - rust_uv_close(handle as *c_void, cb); -} - -pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *c_void) { - rust_uv_walk(loop_handle, cb, arg); -} - -pub unsafe fn idle_new() -> *uv_idle_t { - rust_uv_idle_new() -} - -pub unsafe fn idle_delete(handle: *uv_idle_t) { - rust_uv_idle_delete(handle) -} - -pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int { - rust_uv_idle_init(loop_handle, handle) -} - -pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int { - rust_uv_idle_start(handle, cb) -} - -pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int { - rust_uv_idle_stop(handle) -} - -pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int { - return rust_uv_tcp_init(loop_handle, handle); -} - -// FIXME ref #2064 -pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in, - after_connect_cb: *u8) -> c_int { - return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - addr_ptr: *sockaddr_in6, - after_connect_cb: *u8) -> c_int { - return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, - after_connect_cb, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int { - return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr); -} -// FIXME ref #2064 -pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int { - return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr); -} - -pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in) -> c_int { - return rust_uv_tcp_getpeername(tcp_handle_ptr, name); -} - -pub unsafe fn tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_in6) ->c_int { - return rust_uv_tcp_getpeername6(tcp_handle_ptr, name); -} - -pub unsafe fn listen<T>(stream: *T, backlog: c_int, cb: *u8) -> c_int { - return rust_uv_listen(stream as *c_void, backlog, cb); -} - -pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int { - return rust_uv_accept(server as *c_void, client as *c_void); -} - -pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int { - let buf_ptr = vec::raw::to_ptr(buf_in); - let buf_cnt = buf_in.len() as i32; - return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb); -} -pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int { - return rust_uv_read_start(stream as *c_void, on_alloc, on_read); -} - -pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int { - return rust_uv_read_stop(stream as *c_void); -} - -pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t { - return rust_uv_last_error(loop_handle); -} - -pub unsafe fn strerror(err: *uv_err_t) -> *c_char { - return rust_uv_strerror(err); -} -pub unsafe fn err_name(err: *uv_err_t) -> *c_char { - return rust_uv_err_name(err); -} - -pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int { - return rust_uv_async_init(loop_handle, async_handle, cb); -} - -pub unsafe fn async_send(async_handle: *uv_async_t) { - return rust_uv_async_send(async_handle); -} -pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t { - let out_buf = uv_buf_t { base: ptr::null(), len: 0 as size_t }; - let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf); - rust_uv_buf_init(out_buf_ptr, input, len as size_t); - return out_buf; -} - -pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int { - return rust_uv_timer_init(loop_ptr, timer_ptr); -} -pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64, - repeat: u64) -> c_int { - return rust_uv_timer_start(timer_ptr, cb, timeout, repeat); -} -pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int { - return rust_uv_timer_stop(timer_ptr); -} - -pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in { - do str::as_c_str(ip) |ip_buf| { - rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int) - } -} -pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 { - do str::as_c_str(ip) |ip_buf| { - rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int) - } -} - -pub unsafe fn free_ip4_addr(addr: *sockaddr_in) { - rust_uv_free_ip4_addr(addr); -} - -pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) { - rust_uv_free_ip6_addr(addr); -} - -// data access helpers -pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void { - return rust_uv_get_loop_for_uv_handle(handle as *c_void); -} -pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t { - return rust_uv_get_stream_handle_from_connect_req(connect); -} -pub unsafe fn get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t { - return rust_uv_get_stream_handle_from_write_req(write_req); -} -pub unsafe fn get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void { - rust_uv_get_data_for_uv_loop(loop_ptr) -} -pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) { - rust_uv_set_data_for_uv_loop(loop_ptr, data); -} -pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *c_void { - return rust_uv_get_data_for_uv_handle(handle as *c_void); -} -pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) { - rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void); -} -pub unsafe fn get_data_for_req<T>(req: *T) -> *c_void { - return rust_uv_get_data_for_req(req as *c_void); -} -pub unsafe fn set_data_for_req<T, U>(req: *T, data: *U) { - rust_uv_set_data_for_req(req as *c_void, data as *c_void); -} -pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 { - return rust_uv_get_base_from_buf(buf); -} -pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t { - return rust_uv_get_len_from_buf(buf); -} -pub unsafe fn malloc_buf_base_of(suggested_size: size_t) -> *u8 { - return rust_uv_malloc_buf_base_of(suggested_size); -} -pub unsafe fn free_base_of_buf(buf: uv_buf_t) { - rust_uv_free_base_of_buf(buf); -} - -pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str { - let err = last_error(uv_loop); - let err_ptr = ptr::to_unsafe_ptr(&err); - let err_name = str::raw::from_c_str(err_name(err_ptr)); - let err_msg = str::raw::from_c_str(strerror(err_ptr)); - return fmt!("LIBUV ERROR: name: %s msg: %s", - err_name, err_msg); -} - -pub unsafe fn get_last_err_data(uv_loop: *c_void) -> uv_err_data { - let err = last_error(uv_loop); - let err_ptr = ptr::to_unsafe_ptr(&err); - let err_name = str::raw::from_c_str(err_name(err_ptr)); - let err_msg = str::raw::from_c_str(strerror(err_ptr)); - uv_err_data { err_name: err_name, err_msg: err_msg } -} - -pub struct uv_err_data { - err_name: ~str, - err_msg: ~str, -} - -extern { - - fn rust_uv_handle_size(type_: uintptr_t) -> size_t; - fn rust_uv_req_size(type_: uintptr_t) -> size_t; - fn rust_uv_handle_type_max() -> uintptr_t; - fn rust_uv_req_type_max() -> uintptr_t; - - // libuv public API - fn rust_uv_loop_new() -> *c_void; - fn rust_uv_loop_delete(lp: *c_void); - fn rust_uv_run(loop_handle: *c_void); - fn rust_uv_close(handle: *c_void, cb: *u8); - fn rust_uv_walk(loop_handle: *c_void, cb: *u8, arg: *c_void); - - fn rust_uv_idle_new() -> *uv_idle_t; - fn rust_uv_idle_delete(handle: *uv_idle_t); - fn rust_uv_idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int; - fn rust_uv_idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int; - fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int; - - fn rust_uv_async_send(handle: *uv_async_t); - fn rust_uv_async_init(loop_handle: *c_void, - async_handle: *uv_async_t, - cb: *u8) -> c_int; - fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int; - // FIXME ref #2604 .. ? - fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t); - fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t; - // FIXME ref #2064 - fn rust_uv_strerror(err: *uv_err_t) -> *c_char; - // FIXME ref #2064 - fn rust_uv_err_name(err: *uv_err_t) -> *c_char; - fn rust_uv_ip4_addrp(ip: *u8, port: c_int) -> *sockaddr_in; - fn rust_uv_ip6_addrp(ip: *u8, port: c_int) -> *sockaddr_in6; - fn rust_uv_free_ip4_addr(addr: *sockaddr_in); - fn rust_uv_free_ip6_addr(addr: *sockaddr_in6); - fn rust_uv_ip4_name(src: *sockaddr_in, dst: *u8, size: size_t) -> c_int; - fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: size_t) -> c_int; - fn rust_uv_ip4_port(src: *sockaddr_in) -> c_uint; - fn rust_uv_ip6_port(src: *sockaddr_in6) -> c_uint; - // FIXME ref #2064 - fn rust_uv_tcp_connect(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, - addr: *sockaddr_in) -> c_int; - // FIXME ref #2064 - fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, addr: *sockaddr_in) -> c_int; - // FIXME ref #2064 - fn rust_uv_tcp_connect6(connect_ptr: *uv_connect_t, - tcp_handle_ptr: *uv_tcp_t, - after_cb: *u8, - addr: *sockaddr_in6) -> c_int; - // FIXME ref #2064 - fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, addr: *sockaddr_in6) -> c_int; - fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, - name: *sockaddr_in) -> c_int; - fn rust_uv_tcp_getpeername6(tcp_handle_ptr: *uv_tcp_t, - name: *sockaddr_in6) ->c_int; - fn rust_uv_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int; - fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int; - fn rust_uv_write(req: *c_void, - stream: *c_void, - buf_in: *uv_buf_t, - buf_cnt: c_int, - cb: *u8) -> c_int; - fn rust_uv_read_start(stream: *c_void, - on_alloc: *u8, - on_read: *u8) -> c_int; - fn rust_uv_read_stop(stream: *c_void) -> c_int; - fn rust_uv_timer_init(loop_handle: *c_void, - timer_handle: *uv_timer_t) -> c_int; - fn rust_uv_timer_start(timer_handle: *uv_timer_t, - cb: *u8, - timeout: libc::uint64_t, - repeat: libc::uint64_t) -> c_int; - fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int; - - fn rust_uv_malloc_buf_base_of(sug_size: size_t) -> *u8; - fn rust_uv_free_base_of_buf(buf: uv_buf_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; - fn rust_uv_get_loop_for_uv_handle(handle: *c_void) -> *c_void; - fn rust_uv_get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void; - fn rust_uv_set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void); - fn rust_uv_get_data_for_uv_handle(handle: *c_void) -> *c_void; - fn rust_uv_set_data_for_uv_handle(handle: *c_void, data: *c_void); - fn rust_uv_get_data_for_req(req: *c_void) -> *c_void; - fn rust_uv_set_data_for_req(req: *c_void, data: *c_void); - fn rust_uv_get_base_from_buf(buf: uv_buf_t) -> *u8; - fn rust_uv_get_len_from_buf(buf: uv_buf_t) -> size_t; -} diff --git a/src/libcore/rt/work_queue.rs b/src/libcore/rt/work_queue.rs deleted file mode 100644 index e9eb663392b..00000000000 --- a/src/libcore/rt/work_queue.rs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use container::Container; -use option::*; -use vec::OwnedVector; -use unstable::sync::{Exclusive, exclusive}; -use cell::Cell; -use kinds::Owned; -use clone::Clone; - -pub struct WorkQueue<T> { - // XXX: Another mystery bug fixed by boxing this lock - priv queue: ~Exclusive<~[T]> -} - -pub impl<T: Owned> WorkQueue<T> { - fn new() -> WorkQueue<T> { - WorkQueue { - queue: ~exclusive(~[]) - } - } - - fn push(&mut self, value: T) { - let value = Cell(value); - self.queue.with(|q| q.unshift(value.take()) ); - } - - fn pop(&mut self) -> Option<T> { - do self.queue.with |q| { - if !q.is_empty() { - Some(q.shift()) - } else { - None - } - } - } - - fn steal(&mut self) -> Option<T> { - do self.queue.with |q| { - if !q.is_empty() { - Some(q.pop()) - } else { - None - } - } - } - - fn is_empty(&self) -> bool { - self.queue.with_imm(|q| q.is_empty() ) - } -} - -impl<T> Clone for WorkQueue<T> { - fn clone(&self) -> WorkQueue<T> { - WorkQueue { - queue: self.queue.clone() - } - } -} |
