2013-02-03 20:15:43 -06:00
|
|
|
// 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::*;
|
2013-05-17 12:45:09 -05:00
|
|
|
|
|
|
|
use super::io::net::ip::IpAddr;
|
|
|
|
use super::uv::*;
|
|
|
|
use super::rtio::*;
|
2013-02-03 20:15:43 -06:00
|
|
|
use ops::Drop;
|
2013-05-17 12:45:09 -05:00
|
|
|
use old_iter::CopyableIter;
|
2013-02-03 20:15:43 -06:00
|
|
|
use cell::{Cell, empty_cell};
|
|
|
|
use cast::transmute;
|
2013-05-17 12:45:09 -05:00
|
|
|
use super::sched::{Scheduler, local_sched};
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-05-12 19:34:15 -05:00
|
|
|
#[cfg(test)] use container::Container;
|
2013-02-03 20:15:43 -06:00
|
|
|
#[cfg(test)] use uint;
|
2013-04-20 03:16:06 -05:00
|
|
|
#[cfg(test)] use unstable::run_in_bare_thread;
|
2013-05-17 12:45:09 -05:00
|
|
|
#[cfg(test)] use super::test::*;
|
2013-02-03 20:15:43 -06:00
|
|
|
|
|
|
|
pub struct UvEventLoop {
|
|
|
|
uvio: UvIoFactory
|
|
|
|
}
|
|
|
|
|
|
|
|
pub impl UvEventLoop {
|
2013-03-21 21:07:54 -05:00
|
|
|
fn new() -> UvEventLoop {
|
2013-02-03 20:15:43 -06:00
|
|
|
UvEventLoop {
|
|
|
|
uvio: UvIoFactory(Loop::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// A convenience constructor
|
2013-03-21 21:07:54 -05:00
|
|
|
fn new_scheduler() -> Scheduler {
|
2013-02-03 20:15:43 -06:00
|
|
|
Scheduler::new(~UvEventLoop::new())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for UvEventLoop {
|
|
|
|
fn finalize(&self) {
|
|
|
|
// XXX: Need mutable finalizer
|
2013-05-10 17:15:06 -05:00
|
|
|
let this = unsafe {
|
2013-02-03 20:15:43 -06:00
|
|
|
transmute::<&UvEventLoop, &mut UvEventLoop>(self)
|
|
|
|
};
|
2013-05-10 17:15:06 -05:00
|
|
|
this.uvio.uv_loop().close();
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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| {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(status.is_none());
|
2013-02-03 20:15:43 -06:00
|
|
|
let mut idle_watcher = idle_watcher;
|
|
|
|
idle_watcher.stop();
|
2013-05-17 12:45:09 -05:00
|
|
|
idle_watcher.close();
|
2013-05-11 02:42:16 -05:00
|
|
|
f();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-10 15:11:35 -05:00
|
|
|
fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> {
|
|
|
|
Some(&mut self.uvio)
|
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[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();
|
2013-05-17 12:45:09 -05:00
|
|
|
assert!(count == 1);
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct UvIoFactory(Loop);
|
|
|
|
|
|
|
|
pub impl UvIoFactory {
|
2013-04-10 15:11:35 -05:00
|
|
|
fn uv_loop<'a>(&'a mut self) -> &'a mut Loop {
|
|
|
|
match self { &UvIoFactory(ref mut ptr) => ptr }
|
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2013-05-17 12:45:09 -05:00
|
|
|
fn connect(&mut self, addr: IpAddr) -> Option<~StreamObject> {
|
2013-02-03 20:15:43 -06:00
|
|
|
// Create a cell in the task to hold the result. We will fill
|
|
|
|
// the cell before resuming the task.
|
|
|
|
let result_cell = empty_cell();
|
2013-05-17 12:45:09 -05:00
|
|
|
let result_cell_ptr: *Cell<Option<~StreamObject>> = &result_cell;
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
let scheduler = local_sched::take();
|
2013-04-15 18:00:15 -05:00
|
|
|
assert!(scheduler.in_task_context());
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-04-15 18:00:15 -05:00
|
|
|
// Block this task and take ownership, switch to scheduler context
|
2013-04-15 18:19:01 -05:00
|
|
|
do scheduler.deschedule_running_task_and_then |task| {
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-04-15 18:00:15 -05:00
|
|
|
rtdebug!("connect: entered scheduler context");
|
2013-05-17 12:45:09 -05:00
|
|
|
do local_sched::borrow |scheduler| {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(!scheduler.in_task_context());
|
2013-04-15 18:19:01 -05:00
|
|
|
}
|
2013-04-15 18:00:15 -05:00
|
|
|
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");
|
2013-05-17 12:45:09 -05:00
|
|
|
let maybe_stream = if status.is_none() {
|
2013-04-15 18:00:15 -05:00
|
|
|
rtdebug!("status is none");
|
2013-05-17 12:45:09 -05:00
|
|
|
Some(~UvStream(stream_watcher))
|
2013-04-15 18:00:15 -05:00
|
|
|
} else {
|
|
|
|
rtdebug!("status is some");
|
2013-05-17 12:45:09 -05:00
|
|
|
stream_watcher.close(||());
|
|
|
|
None
|
2013-04-15 18:00:15 -05:00
|
|
|
};
|
2013-05-17 12:45:09 -05:00
|
|
|
|
|
|
|
// Store the stream in the task's stack
|
|
|
|
unsafe { (*result_cell_ptr).put_back(maybe_stream); }
|
|
|
|
|
|
|
|
// Context switch
|
|
|
|
let scheduler = local_sched::take();
|
|
|
|
scheduler.resume_task_immediately(task_cell.take());
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(!result_cell.is_empty());
|
2013-02-03 20:15:43 -06:00
|
|
|
return result_cell.take();
|
|
|
|
}
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
fn bind(&mut self, addr: IpAddr) -> Option<~TcpListenerObject> {
|
2013-02-03 20:15:43 -06:00
|
|
|
let mut watcher = TcpWatcher::new(self.uv_loop());
|
2013-05-17 12:45:09 -05:00
|
|
|
watcher.bind(addr);
|
|
|
|
return Some(~UvTcpListener(watcher));
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
pub struct UvTcpListener(TcpWatcher);
|
2013-02-03 20:15:43 -06:00
|
|
|
|
|
|
|
impl UvTcpListener {
|
2013-05-17 12:45:09 -05:00
|
|
|
fn watcher(&self) -> TcpWatcher {
|
|
|
|
match self { &UvTcpListener(w) => w }
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
fn close(&self) {
|
|
|
|
// XXX: Need to wait until close finishes before returning
|
|
|
|
self.watcher().as_stream().close(||());
|
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for UvTcpListener {
|
|
|
|
fn finalize(&self) {
|
2013-05-17 12:45:09 -05:00
|
|
|
// XXX: Again, this never gets called. Use .close() instead
|
|
|
|
//self.watcher().as_stream().close(||());
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
impl TcpListener for UvTcpListener {
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
fn listen(&mut self) -> Option<~StreamObject> {
|
2013-02-03 20:15:43 -06:00
|
|
|
rtdebug!("entering listen");
|
2013-05-17 12:45:09 -05:00
|
|
|
let result_cell = empty_cell();
|
|
|
|
let result_cell_ptr: *Cell<Option<~StreamObject>> = &result_cell;
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
let server_tcp_watcher = self.watcher();
|
2013-04-15 18:00:15 -05:00
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
let scheduler = local_sched::take();
|
|
|
|
assert!(scheduler.in_task_context());
|
2013-04-15 18:00:15 -05:00
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
do scheduler.deschedule_running_task_and_then |task| {
|
|
|
|
let task_cell = Cell(task);
|
|
|
|
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_ = loop_from_watcher(&server_stream_watcher);
|
|
|
|
let client_tcp_watcher = TcpWatcher::new(&mut loop_).as_stream();
|
|
|
|
// XXX: Needs to be surfaced in interface
|
|
|
|
server_stream_watcher.accept(client_tcp_watcher);
|
|
|
|
Some(~UvStream::new(client_tcp_watcher))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
unsafe { (*result_cell_ptr).put_back(maybe_stream); }
|
2013-04-15 18:00:15 -05:00
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
rtdebug!("resuming task from listen");
|
|
|
|
// Context switch
|
|
|
|
let scheduler = local_sched::take();
|
|
|
|
scheduler.resume_task_immediately(task_cell.take());
|
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
assert!(!result_cell.is_empty());
|
|
|
|
return result_cell.take();
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
pub struct UvStream(StreamWatcher);
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
impl UvStream {
|
|
|
|
fn new(watcher: StreamWatcher) -> UvStream {
|
|
|
|
UvStream(watcher)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn watcher(&self) -> StreamWatcher {
|
|
|
|
match self { &UvStream(w) => w }
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX: finalize isn't working for ~UvStream???
|
|
|
|
fn close(&self) {
|
|
|
|
// XXX: Need to wait until this finishes before returning
|
|
|
|
self.watcher().close(||());
|
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
impl Drop for UvStream {
|
2013-02-03 20:15:43 -06:00
|
|
|
fn finalize(&self) {
|
2013-05-17 12:45:09 -05:00
|
|
|
rtdebug!("closing stream");
|
|
|
|
//self.watcher().close(||());
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
impl Stream for UvStream {
|
|
|
|
fn read(&mut self, buf: &mut [u8]) -> Result<uint, ()> {
|
2013-02-03 20:15:43 -06:00
|
|
|
let result_cell = empty_cell();
|
2013-05-17 12:45:09 -05:00
|
|
|
let result_cell_ptr: *Cell<Result<uint, ()>> = &result_cell;
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
let scheduler = local_sched::take();
|
2013-04-15 18:00:15 -05:00
|
|
|
assert!(scheduler.in_task_context());
|
|
|
|
let watcher = self.watcher();
|
|
|
|
let buf_ptr: *&mut [u8] = &buf;
|
2013-04-15 18:19:01 -05:00
|
|
|
do scheduler.deschedule_running_task_and_then |task| {
|
2013-04-15 18:00:15 -05:00
|
|
|
rtdebug!("read: entered scheduler context");
|
2013-05-17 12:45:09 -05:00
|
|
|
do local_sched::borrow |scheduler| {
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(!scheduler.in_task_context());
|
2013-04-15 18:19:01 -05:00
|
|
|
}
|
2013-04-15 18:00:15 -05:00
|
|
|
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?
|
2013-02-03 20:15:43 -06:00
|
|
|
let mut watcher = watcher;
|
2013-04-15 18:00:15 -05:00
|
|
|
watcher.read_stop();
|
|
|
|
|
|
|
|
let result = if status.is_none() {
|
|
|
|
assert!(nread >= 0);
|
|
|
|
Ok(nread as uint)
|
|
|
|
} else {
|
2013-05-17 12:45:09 -05:00
|
|
|
Err(())
|
2013-02-03 20:15:43 -06:00
|
|
|
};
|
2013-04-15 18:00:15 -05:00
|
|
|
|
|
|
|
unsafe { (*result_cell_ptr).put_back(result); }
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
let scheduler = local_sched::take();
|
2013-04-15 18:00:15 -05:00
|
|
|
scheduler.resume_task_immediately(task_cell.take());
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(!result_cell.is_empty());
|
2013-02-03 20:15:43 -06:00
|
|
|
return result_cell.take();
|
|
|
|
}
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
fn write(&mut self, buf: &[u8]) -> Result<(), ()> {
|
2013-02-03 20:15:43 -06:00
|
|
|
let result_cell = empty_cell();
|
2013-05-17 12:45:09 -05:00
|
|
|
let result_cell_ptr: *Cell<Result<(), ()>> = &result_cell;
|
|
|
|
let scheduler = local_sched::take();
|
2013-04-15 18:00:15 -05:00
|
|
|
assert!(scheduler.in_task_context());
|
|
|
|
let watcher = self.watcher();
|
|
|
|
let buf_ptr: *&[u8] = &buf;
|
2013-04-15 18:19:01 -05:00
|
|
|
do scheduler.deschedule_running_task_and_then |task| {
|
2013-04-15 18:00:15 -05:00
|
|
|
let mut watcher = watcher;
|
|
|
|
let task_cell = Cell(task);
|
2013-05-17 12:45:09 -05:00
|
|
|
let buf = unsafe { &*buf_ptr };
|
|
|
|
// XXX: OMGCOPIES
|
|
|
|
let buf = buf.to_vec();
|
2013-04-15 18:00:15 -05:00
|
|
|
do watcher.write(buf) |_watcher, status| {
|
|
|
|
let result = if status.is_none() {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
2013-05-17 12:45:09 -05:00
|
|
|
Err(())
|
2013-04-15 18:00:15 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
unsafe { (*result_cell_ptr).put_back(result); }
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
let scheduler = local_sched::take();
|
2013-04-15 18:00:15 -05:00
|
|
|
scheduler.resume_task_immediately(task_cell.take());
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-28 20:39:09 -05:00
|
|
|
assert!(!result_cell.is_empty());
|
2013-02-03 20:15:43 -06:00
|
|
|
return result_cell.take();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_simple_io_no_connect() {
|
2013-04-20 03:55:10 -05:00
|
|
|
do run_in_newsched_task {
|
2013-05-17 12:45:09 -05:00
|
|
|
let io = unsafe { local_sched::unsafe_borrow_io() };
|
|
|
|
let addr = next_test_ip4();
|
|
|
|
let maybe_chan = io.connect(addr);
|
|
|
|
assert!(maybe_chan.is_none());
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_simple_tcp_server_and_client() {
|
2013-04-20 03:55:10 -05:00
|
|
|
do run_in_newsched_task {
|
2013-04-20 04:41:30 -05:00
|
|
|
let addr = next_test_ip4();
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-04-20 03:55:10 -05:00
|
|
|
// Start the server first so it's listening when we connect
|
2013-04-23 17:11:28 -05:00
|
|
|
do spawntask_immediately {
|
2013-04-18 21:32:32 -05:00
|
|
|
unsafe {
|
2013-05-17 12:45:09 -05:00
|
|
|
let io = local_sched::unsafe_borrow_io();
|
|
|
|
let mut listener = io.bind(addr).unwrap();
|
|
|
|
let mut stream = listener.listen().unwrap();
|
2013-04-18 21:32:32 -05:00
|
|
|
let mut buf = [0, .. 2048];
|
|
|
|
let nread = stream.read(buf).unwrap();
|
2013-05-17 12:45:09 -05:00
|
|
|
assert!(nread == 8);
|
2013-04-18 21:32:32 -05:00
|
|
|
for uint::range(0, nread) |i| {
|
|
|
|
rtdebug!("%u", buf[i] as uint);
|
2013-05-17 12:45:09 -05:00
|
|
|
assert!(buf[i] == i as u8);
|
2013-04-18 21:32:32 -05:00
|
|
|
}
|
2013-05-17 12:45:09 -05:00
|
|
|
stream.close();
|
|
|
|
listener.close();
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
2013-04-20 03:55:10 -05:00
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-04-23 17:11:28 -05:00
|
|
|
do spawntask_immediately {
|
2013-04-20 03:55:10 -05:00
|
|
|
unsafe {
|
2013-05-17 12:45:09 -05:00
|
|
|
let io = local_sched::unsafe_borrow_io();
|
|
|
|
let mut stream = io.connect(addr).unwrap();
|
2013-04-20 03:55:10 -05:00
|
|
|
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
|
2013-05-17 12:45:09 -05:00
|
|
|
stream.close();
|
2013-04-20 03:55:10 -05:00
|
|
|
}
|
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test] #[ignore(reason = "busted")]
|
|
|
|
fn test_read_and_block() {
|
2013-04-20 03:55:10 -05:00
|
|
|
do run_in_newsched_task {
|
2013-04-20 04:41:30 -05:00
|
|
|
let addr = next_test_ip4();
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-04-23 17:11:28 -05:00
|
|
|
do spawntask_immediately {
|
2013-05-17 12:45:09 -05:00
|
|
|
let io = unsafe { local_sched::unsafe_borrow_io() };
|
|
|
|
let mut listener = io.bind(addr).unwrap();
|
|
|
|
let mut stream = listener.listen().unwrap();
|
2013-04-15 18:00:15 -05:00
|
|
|
let mut buf = [0, .. 2048];
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-04-15 18:00:15 -05:00
|
|
|
let expected = 32;
|
|
|
|
let mut current = 0;
|
|
|
|
let mut reads = 0;
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-04-15 18:00:15 -05:00
|
|
|
while current < expected {
|
|
|
|
let nread = stream.read(buf).unwrap();
|
|
|
|
for uint::range(0, nread) |i| {
|
|
|
|
let val = buf[i] as uint;
|
2013-05-17 12:45:09 -05:00
|
|
|
assert!(val == current % 8);
|
2013-04-15 18:00:15 -05:00
|
|
|
current += 1;
|
|
|
|
}
|
|
|
|
reads += 1;
|
|
|
|
|
2013-05-17 12:45:09 -05:00
|
|
|
let scheduler = local_sched::take();
|
2013-04-15 18:00:15 -05:00
|
|
|
// Yield to the other task in hopes that it
|
|
|
|
// will trigger a read callback while we are
|
|
|
|
// not ready for it
|
2013-04-15 18:19:01 -05:00
|
|
|
do scheduler.deschedule_running_task_and_then |task| {
|
|
|
|
let task = Cell(task);
|
2013-05-17 12:45:09 -05:00
|
|
|
do local_sched::borrow |scheduler| {
|
|
|
|
scheduler.task_queue.push_back(task.take());
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-15 18:00:15 -05:00
|
|
|
// Make sure we had multiple reads
|
|
|
|
assert!(reads > 1);
|
2013-05-17 12:45:09 -05:00
|
|
|
|
|
|
|
stream.close();
|
|
|
|
listener.close();
|
2013-04-20 03:55:10 -05:00
|
|
|
}
|
|
|
|
|
2013-04-23 17:11:28 -05:00
|
|
|
do spawntask_immediately {
|
2013-05-17 12:45:09 -05:00
|
|
|
let io = unsafe { local_sched::unsafe_borrow_io() };
|
|
|
|
let mut stream = io.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]);
|
|
|
|
stream.close();
|
2013-04-20 03:55:10 -05:00
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-20 04:16:21 -05:00
|
|
|
#[test]
|
2013-02-03 20:15:43 -06:00
|
|
|
fn test_read_read_read() {
|
2013-04-20 03:55:10 -05:00
|
|
|
do run_in_newsched_task {
|
2013-04-20 04:41:30 -05:00
|
|
|
let addr = next_test_ip4();
|
2013-04-20 18:15:32 -05:00
|
|
|
static MAX: uint = 500000;
|
2013-04-23 22:41:00 -05:00
|
|
|
|
2013-04-23 17:11:28 -05:00
|
|
|
do spawntask_immediately {
|
2013-04-20 04:16:21 -05:00
|
|
|
unsafe {
|
2013-05-17 12:45:09 -05:00
|
|
|
let io = local_sched::unsafe_borrow_io();
|
|
|
|
let mut listener = io.bind(addr).unwrap();
|
|
|
|
let mut stream = listener.listen().unwrap();
|
2013-05-12 19:34:15 -05:00
|
|
|
let buf = [1, .. 2048];
|
2013-04-20 04:16:21 -05:00
|
|
|
let mut total_bytes_written = 0;
|
|
|
|
while total_bytes_written < MAX {
|
|
|
|
stream.write(buf);
|
|
|
|
total_bytes_written += buf.len();
|
|
|
|
}
|
2013-05-17 12:45:09 -05:00
|
|
|
stream.close();
|
|
|
|
listener.close();
|
2013-04-20 04:16:21 -05:00
|
|
|
}
|
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
|
2013-04-23 17:11:28 -05:00
|
|
|
do spawntask_immediately {
|
2013-05-17 12:45:09 -05:00
|
|
|
let io = unsafe { local_sched::unsafe_borrow_io() };
|
|
|
|
let mut stream = io.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!(buf[i] == 1);
|
2013-04-22 21:20:31 -05:00
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
2013-05-17 12:45:09 -05:00
|
|
|
rtdebug!("read %u bytes total", total_bytes_read as uint);
|
|
|
|
stream.close();
|
2013-04-20 03:55:10 -05:00
|
|
|
}
|
2013-02-03 20:15:43 -06:00
|
|
|
}
|
|
|
|
}
|