about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-10-29 09:36:47 -0700
committerbors <bors@rust-lang.org>2013-10-29 09:36:47 -0700
commit52f42f16387d0142944f376ea31c554c9caa2189 (patch)
treee6e4d20d5c8d43c280d6c9ba02c063fe1ae11b2c /src/libstd
parente6650c87a3800264a043b7f129e6a4841c4cc3f7 (diff)
parent201cab84e8f12ec73131ac4908e6779b277449a2 (diff)
downloadrust-52f42f16387d0142944f376ea31c554c9caa2189.tar.gz
rust-52f42f16387d0142944f376ea31c554c9caa2189.zip
auto merge of #10058 : alexcrichton/rust/uv-crate, r=brson
This is one of the final steps needed to complete #9128. It still needs a little bit of polish before closing that issue, but it's in a pretty much "done" state now.

The idea here is that the entire event loop implementation using libuv is now housed in `librustuv` as a completely separate library. This library is then injected (via `extern mod rustv`) into executable builds (similarly to how libstd is injected, tunable via `#[no_uv]`) to bring in the "rust blessed event loop implementation."

Codegen-wise, there is a new `event_loop_factory` language item which is tagged on a function with 0 arguments returning `~EventLoop`. This function's symbol is then inserted into the crate map for an executable crate, and if there is no definition of the `event_loop_factory` language item then the value is null.

What this means is that embedding rust as a library in another language just got a little harder. Libraries don't have crate maps, which means that there's no way to find the event loop implementation to spin up the runtime. That being said, it's always possible to build the runtime manually. This request also makes more runtime components public which should probably be public anyway. This new public-ness should allow custom scheduler setups everywhere regardless of whether you follow the `rt::start `path.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/rt/crate_map.rs38
-rw-r--r--src/libstd/rt/io/net/tcp.rs6
-rw-r--r--src/libstd/rt/mod.rs54
-rw-r--r--src/libstd/rt/sched.rs17
-rw-r--r--src/libstd/rt/test.rs7
-rw-r--r--src/libstd/rt/uv/uvio.rs6
-rw-r--r--src/libstd/select.rs4
-rw-r--r--src/libstd/std.rs7
-rw-r--r--src/libstd/task/mod.rs4
-rw-r--r--src/libstd/task/spawn.rs14
-rw-r--r--src/libstd/unstable/mod.rs2
11 files changed, 106 insertions, 53 deletions
diff --git a/src/libstd/rt/crate_map.rs b/src/libstd/rt/crate_map.rs
index dd71426938d..16b41276788 100644
--- a/src/libstd/rt/crate_map.rs
+++ b/src/libstd/rt/crate_map.rs
@@ -12,6 +12,8 @@ use container::MutableSet;
 use hashmap::HashSet;
 use option::{Some, None, Option};
 use vec::ImmutableVector;
+#[cfg(not(stage0))]
+use rt::rtio::EventLoop;
 
 // Need to tell the linker on OS X to not barf on undefined symbols
 // and instead look them up at runtime, which we need to resolve
@@ -25,18 +27,32 @@ pub struct ModEntry<'self> {
     log_level: *mut u32
 }
 
+#[cfg(stage0)]
 pub struct CrateMap<'self> {
-     priv version: i32,
-     priv entries: &'self [ModEntry<'self>],
-     priv children: &'self [&'self CrateMap<'self>]
+    version: i32,
+    entries: &'self [ModEntry<'self>],
+    children: &'self [&'self CrateMap<'self>]
+}
+
+#[cfg(not(stage0))]
+pub struct CrateMap<'self> {
+    version: i32,
+    entries: &'self [ModEntry<'self>],
+    children: &'self [&'self CrateMap<'self>],
+    event_loop_factory: Option<extern "C" fn() -> ~EventLoop>,
 }
 
 #[cfg(not(windows))]
 pub fn get_crate_map() -> Option<&'static CrateMap<'static>> {
     extern {
+        #[cfg(stage0)]
         #[weak_linkage]
         #[link_name = "_rust_crate_map_toplevel"]
         static CRATE_MAP: CrateMap<'static>;
+
+        #[cfg(not(stage0))]
+        #[crate_map]
+        static CRATE_MAP: CrateMap<'static>;
     }
 
     let ptr: (*CrateMap) = &'static CRATE_MAP;
@@ -108,6 +124,7 @@ pub fn iter_crate_map<'a>(crate_map: &'a CrateMap<'a>, f: &fn(&ModEntry)) {
 
 #[cfg(test)]
 mod tests {
+    use option::None;
     use rt::crate_map::{CrateMap, ModEntry, iter_crate_map};
 
     #[test]
@@ -121,13 +138,15 @@ mod tests {
         let child_crate = CrateMap {
             version: 2,
             entries: entries,
-            children: []
+            children: [],
+            event_loop_factory: None,
         };
 
         let root_crate = CrateMap {
             version: 2,
             entries: [],
-            children: [&child_crate, &child_crate]
+            children: [&child_crate, &child_crate],
+            event_loop_factory: None,
         };
 
         let mut cnt = 0;
@@ -150,7 +169,8 @@ mod tests {
                 ModEntry { name: "c::m1", log_level: &mut level2},
                 ModEntry { name: "c::m2", log_level: &mut level3},
             ],
-            children: []
+            children: [],
+            event_loop_factory: None,
         };
 
         let child_crate1 = CrateMap {
@@ -158,7 +178,8 @@ mod tests {
             entries: [
                 ModEntry { name: "t::f1", log_level: &mut 1},
             ],
-            children: [&child_crate2]
+            children: [&child_crate2],
+            event_loop_factory: None,
         };
 
         let root_crate = CrateMap {
@@ -166,7 +187,8 @@ mod tests {
             entries: [
                 ModEntry { name: "t::f2", log_level: &mut 0},
             ],
-            children: [&child_crate1]
+            children: [&child_crate1],
+            event_loop_factory: None,
         };
 
         let mut cnt = 0;
diff --git a/src/libstd/rt/io/net/tcp.rs b/src/libstd/rt/io/net/tcp.rs
index 6314c0755a0..fb7c6766fd8 100644
--- a/src/libstd/rt/io/net/tcp.rs
+++ b/src/libstd/rt/io/net/tcp.rs
@@ -383,7 +383,8 @@ mod test {
                         //     on windows
                         assert!(e.kind == ConnectionReset ||
                                 e.kind == BrokenPipe ||
-                                e.kind == ConnectionAborted);
+                                e.kind == ConnectionAborted,
+                                "unknown error: {:?}", e);
                         stop = true;
                     }).inside {
                         stream.write(buf);
@@ -420,7 +421,8 @@ mod test {
                         //     on windows
                         assert!(e.kind == ConnectionReset ||
                                 e.kind == BrokenPipe ||
-                                e.kind == ConnectionAborted);
+                                e.kind == ConnectionAborted,
+                                "unknown error: {:?}", e);
                         stop = true;
                     }).inside {
                         stream.write(buf);
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index eaaf8c43281..d8d07f14021 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -68,7 +68,6 @@ use rt::sched::{Scheduler, Shutdown};
 use rt::sleeper_list::SleeperList;
 use rt::task::UnwindResult;
 use rt::task::{Task, SchedTask, GreenTask, Sched};
-use rt::uv::uvio::UvEventLoop;
 use unstable::atomics::{AtomicInt, AtomicBool, SeqCst};
 use unstable::sync::UnsafeArc;
 use vec::{OwnedVector, MutableVector, ImmutableVector};
@@ -87,15 +86,13 @@ pub use self::util::set_exit_status;
 // method...
 pub use self::util::default_sched_threads;
 
+// Re-export of the functionality in the kill module
+pub use self::kill::{KillHandle, BlockedTask};
+
 // XXX: these probably shouldn't be public...
 #[doc(hidden)]
 pub mod shouldnt_be_public {
-    pub use super::sched::Scheduler;
-    pub use super::kill::KillHandle;
-    pub use super::thread::Thread;
-    pub use super::work_queue::WorkQueue;
     pub use super::select::SelectInner;
-    pub use super::rtio::EventLoop;
     pub use super::select::{SelectInner, SelectPortInner};
     pub use super::local_ptr::maybe_tls_key;
 }
@@ -116,15 +113,16 @@ pub mod task;
 mod kill;
 
 /// The coroutine task scheduler, built on the `io` event loop.
-mod sched;
+pub mod sched;
 
 /// Synchronous I/O.
 pub mod io;
 
 /// The EventLoop and internal synchronous I/O interface.
-mod rtio;
+pub mod rtio;
 
 /// libuv and default rtio implementation.
+#[cfg(stage0)]
 pub mod uv;
 
 /// The Local trait for types that are accessible via thread-local
@@ -132,10 +130,10 @@ pub mod uv;
 pub mod local;
 
 /// A parallel work-stealing deque.
-mod work_queue;
+pub mod work_queue;
 
 /// A parallel queue.
-mod message_queue;
+pub mod message_queue;
 
 /// A mostly lock-free multi-producer, single consumer queue.
 mod mpsc_queue;
@@ -144,7 +142,7 @@ mod mpsc_queue;
 mod mpmc_bounded_queue;
 
 /// A parallel data structure for tracking sleeping schedulers.
-mod sleeper_list;
+pub mod sleeper_list;
 
 /// Stack segments and caching.
 pub mod stack;
@@ -153,7 +151,7 @@ pub mod stack;
 mod context;
 
 /// Bindings to system threading libraries.
-mod thread;
+pub mod thread;
 
 /// The runtime configuration, read from environment variables.
 pub mod env;
@@ -289,7 +287,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
         rtdebug!("inserting a regular scheduler");
 
         // Every scheduler is driven by an I/O event loop.
-        let loop_ = ~UvEventLoop::new() as ~rtio::EventLoop;
+        let loop_ = new_event_loop();
         let mut sched = ~Scheduler::new(loop_,
                                         work_queue.clone(),
                                         work_queues.clone(),
@@ -313,7 +311,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
         // set.
         let work_queue = WorkQueue::new();
 
-        let main_loop = ~UvEventLoop::new() as ~rtio::EventLoop;
+        let main_loop = new_event_loop();
         let mut main_sched = ~Scheduler::new_special(main_loop,
                                                      work_queue,
                                                      work_queues.clone(),
@@ -327,7 +325,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
         // waking up schedulers for work stealing; since this is a
         // non-work-stealing scheduler it should not be adding itself
         // to the list.
-        main_handle.send_shutdown();
+        main_handle.send(Shutdown);
         Some(main_sched)
     } else {
         None
@@ -464,3 +462,29 @@ pub fn in_green_task_context() -> bool {
         }
     }
 }
+
+#[cfg(stage0)]
+pub fn new_event_loop() -> ~rtio::EventLoop {
+    use rt::uv::uvio::UvEventLoop;
+    ~UvEventLoop::new() as ~rtio::EventLoop
+}
+
+#[cfg(not(stage0))]
+pub fn new_event_loop() -> ~rtio::EventLoop {
+    #[fixed_stack_segment]; #[allow(cstack)];
+
+    match crate_map::get_crate_map() {
+        None => {}
+        Some(map) => {
+            match map.event_loop_factory {
+                None => {}
+                Some(factory) => return factory()
+            }
+        }
+    }
+
+    // If the crate map didn't specify a factory to create an event loop, then
+    // instead just use a basic event loop missing all I/O services to at least
+    // get the scheduler running.
+    return basic::event_loop();
+}
diff --git a/src/libstd/rt/sched.rs b/src/libstd/rt/sched.rs
index 93056314b14..fd4dab60ff3 100644
--- a/src/libstd/rt/sched.rs
+++ b/src/libstd/rt/sched.rs
@@ -529,7 +529,7 @@ impl Scheduler {
 
         match self.sleeper_list.casual_pop() {
             Some(handle) => {
-                        let mut handle = handle;
+                let mut handle = handle;
                 handle.send(Wake)
             }
             None => { (/* pass */) }
@@ -800,12 +800,6 @@ impl SchedHandle {
         self.queue.push(msg);
         self.remote.fire();
     }
-    pub fn send_task_from_friend(&mut self, friend: ~Task) {
-        self.send(TaskFromFriend(friend));
-    }
-    pub fn send_shutdown(&mut self) {
-        self.send(Shutdown);
-    }
 }
 
 struct CleanupJob {
@@ -1001,7 +995,6 @@ mod test {
 
     #[test]
     fn test_schedule_home_states() {
-
         use rt::sleeper_list::SleeperList;
         use rt::work_queue::WorkQueue;
         use rt::sched::Shutdown;
@@ -1248,15 +1241,15 @@ mod test {
         use comm::{GenericPort, GenericChan};
 
         do run_in_mt_newsched_task {
-                let (end_port, end_chan) = oneshot();
+            let (end_port, end_chan) = oneshot();
 
             let n_tasks = 10;
             let token = 2000;
 
-                let (p, ch1) = stream();
+            let (p, ch1) = stream();
             let mut p = p;
-                ch1.send((token, end_chan));
-                let mut i = 2;
+            ch1.send((token, end_chan));
+            let mut i = 2;
             while i <= n_tasks {
                 let (next_p, ch) = stream();
                 let imm_i = i;
diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs
index 5f78b9fc959..55a8db89d3c 100644
--- a/src/libstd/rt/test.rs
+++ b/src/libstd/rt/test.rs
@@ -24,13 +24,12 @@ use rand;
 use result::{Result, Ok, Err};
 use rt::basic;
 use rt::comm::oneshot;
-use rt::rtio::EventLoop;
+use rt::new_event_loop;
 use rt::sched::Scheduler;
 use rt::sleeper_list::SleeperList;
 use rt::task::Task;
 use rt::task::UnwindResult;
 use rt::thread::Thread;
-use rt::uv::uvio::UvEventLoop;
 use rt::work_queue::WorkQueue;
 use unstable::{run_in_bare_thread};
 use vec::{OwnedVector, MutableVector, ImmutableVector};
@@ -40,7 +39,7 @@ pub fn new_test_uv_sched() -> Scheduler {
     let queue = WorkQueue::new();
     let queues = ~[queue.clone()];
 
-    let mut sched = Scheduler::new(~UvEventLoop::new() as ~EventLoop,
+    let mut sched = Scheduler::new(new_event_loop(),
                                    queue,
                                    queues,
                                    SleeperList::new());
@@ -237,7 +236,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) {
         }
 
         for i in range(0u, nthreads) {
-            let loop_ = ~UvEventLoop::new() as ~EventLoop;
+            let loop_ = new_event_loop();
             let mut sched = ~Scheduler::new(loop_,
                                             work_queues[i].clone(),
                                             work_queues.clone(),
diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs
index bd8466a7925..2d3ecbbd689 100644
--- a/src/libstd/rt/uv/uvio.rs
+++ b/src/libstd/rt/uv/uvio.rs
@@ -236,6 +236,12 @@ impl EventLoop for UvEventLoop {
     }
 }
 
+#[cfg(not(stage0))]
+#[lang = "event_loop_factory"]
+pub extern "C" fn new_loop() -> ~EventLoop {
+    ~UvEventLoop::new() as ~EventLoop
+}
+
 pub struct UvPausibleIdleCallback {
     priv watcher: IdleWatcher,
     priv idle_flag: bool,
diff --git a/src/libstd/select.rs b/src/libstd/select.rs
index 75b09187f04..f5dc98c57b6 100644
--- a/src/libstd/select.rs
+++ b/src/libstd/select.rs
@@ -18,7 +18,9 @@ use option::*;
 // use either::{Either, Left, Right};
 // use rt::kill::BlockedTask;
 use rt::local::Local;
-use rt::shouldnt_be_public::{EventLoop, Scheduler, SelectInner, SelectPortInner};
+use rt::rtio::EventLoop;
+use rt::sched::Scheduler;
+use rt::shouldnt_be_public::{SelectInner, SelectPortInner};
 use task;
 use unstable::finally::Finally;
 use vec::{OwnedVector, MutableVector};
diff --git a/src/libstd/std.rs b/src/libstd/std.rs
index 069a390f010..3a96cfb1171 100644
--- a/src/libstd/std.rs
+++ b/src/libstd/std.rs
@@ -69,8 +69,13 @@ they contained the following prologue:
 #[deny(non_camel_case_types)];
 #[deny(missing_doc)];
 
+// When testing libstd, bring in libuv as the I/O backend so tests can print
+// things and all of the std::rt::io tests have an I/O interface to run on top
+// of
+#[cfg(test)] extern mod rustuv(vers = "0.9-pre");
+
 // Make extra accessible for benchmarking
-#[cfg(test)] extern mod extra(vers="0.9-pre");
+#[cfg(test)] extern mod extra(vers = "0.9-pre");
 
 // Make std testable by not duplicating lang items. See #2912
 #[cfg(test)] extern mod realstd(name = "std");
diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs
index 8efa185bbbd..023ba6f7108 100644
--- a/src/libstd/task/mod.rs
+++ b/src/libstd/task/mod.rs
@@ -578,7 +578,7 @@ pub fn deschedule() {
     //! Yield control to the task scheduler
 
     use rt::local::Local;
-    use rt::shouldnt_be_public::Scheduler;
+    use rt::sched::Scheduler;
 
     // FIXME(#7544): Optimize this, since we know we won't block.
     let sched: ~Scheduler = Local::take();
@@ -1094,7 +1094,7 @@ fn test_try_fail() {
 
 #[cfg(test)]
 fn get_sched_id() -> int {
-    do Local::borrow |sched: &mut ::rt::shouldnt_be_public::Scheduler| {
+    do Local::borrow |sched: &mut ::rt::sched::Scheduler| {
         sched.sched_id() as int
     }
 }
diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs
index 235e67048f6..a08bf8f3147 100644
--- a/src/libstd/task/spawn.rs
+++ b/src/libstd/task/spawn.rs
@@ -80,13 +80,14 @@ use comm::{Chan, GenericChan, oneshot};
 use container::MutableMap;
 use hashmap::{HashSet, HashSetMoveIterator};
 use local_data;
-use rt::in_green_task_context;
 use rt::local::Local;
-use rt::shouldnt_be_public::{Scheduler, KillHandle, WorkQueue, Thread, EventLoop};
+use rt::sched::{Scheduler, Shutdown, TaskFromFriend};
 use rt::task::{Task, Sched};
 use rt::task::{UnwindReasonLinked, UnwindReasonStr};
 use rt::task::{UnwindResult, Success, Failure};
-use rt::uv::uvio::UvEventLoop;
+use rt::thread::Thread;
+use rt::work_queue::WorkQueue;
+use rt::{in_green_task_context, new_event_loop, KillHandle};
 use send_str::IntoSendStr;
 use task::SingleThreaded;
 use task::TaskOpts;
@@ -617,8 +618,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
             let work_queue = WorkQueue::new();
 
             // Create a new scheduler to hold the new task
-            let new_loop = ~UvEventLoop::new() as ~EventLoop;
-            let mut new_sched = ~Scheduler::new_special(new_loop,
+            let mut new_sched = ~Scheduler::new_special(new_event_loop(),
                                                         work_queue,
                                                         (*sched).work_queues.clone(),
                                                         (*sched).sleeper_list.clone(),
@@ -627,7 +627,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
             let mut new_sched_handle = new_sched.make_handle();
 
             // Allow the scheduler to exit when the pinned task exits
-            new_sched_handle.send_shutdown();
+            new_sched_handle.send(Shutdown);
 
             // Pin the new task to the new scheduler
             let new_task = if opts.watched {
@@ -665,7 +665,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
                 debug!("enqueing join_task");
                 // Now tell the original scheduler to join with this thread
                 // by scheduling a thread-joining task on the original scheduler
-                orig_sched_handle.send_task_from_friend(join_task);
+                orig_sched_handle.send(TaskFromFriend(join_task));
 
                 // NB: We can't simply send a message from here to another task
                 // because this code isn't running in a task and message passing doesn't
diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs
index 835b16996b5..484ddde6d3c 100644
--- a/src/libstd/unstable/mod.rs
+++ b/src/libstd/unstable/mod.rs
@@ -37,7 +37,7 @@ a normal large stack.
 */
 pub fn run_in_bare_thread(f: ~fn()) {
     use cell::Cell;
-    use rt::shouldnt_be_public::Thread;
+    use rt::thread::Thread;
 
     let f_cell = Cell::new(f);
     let (port, chan) = comm::stream();