2012-12-03 18:48:01 -06:00
|
|
|
// 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.
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
//! A process-wide libuv event loop for library use.
|
2012-04-17 14:05:04 -05:00
|
|
|
|
2012-09-19 20:20:01 -05:00
|
|
|
#[forbid(deprecated_mode)];
|
|
|
|
|
2012-09-04 13:23:53 -05:00
|
|
|
use ll = uv_ll;
|
|
|
|
use iotask = uv_iotask;
|
|
|
|
use get_gl = get;
|
2012-12-13 15:05:22 -06:00
|
|
|
use uv_iotask::{IoTask, spawn_iotask};
|
2012-12-23 16:41:37 -06:00
|
|
|
|
|
|
|
use core::either::{Left, Right};
|
|
|
|
use core::libc;
|
2013-01-20 01:38:17 -06:00
|
|
|
use core::pipes::{Port, Chan, SharedChan, select2i};
|
|
|
|
use core::private::global::{global_data_clone_create,
|
|
|
|
global_data_clone};
|
|
|
|
use core::private::weak_task::weaken_task;
|
2012-12-23 16:41:37 -06:00
|
|
|
use core::str;
|
2013-01-20 01:38:17 -06:00
|
|
|
use core::task::{task, SingleThreaded, spawn};
|
2012-12-23 16:41:37 -06:00
|
|
|
use core::task;
|
|
|
|
use core::vec;
|
2013-01-20 01:38:17 -06:00
|
|
|
use core::clone::Clone;
|
|
|
|
use core::option::{Some, None};
|
2012-04-17 14:05:04 -05:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Race-free helper to get access to a global task where a libuv
|
|
|
|
* loop is running.
|
|
|
|
*
|
|
|
|
* Use `uv::hl::interact` to do operations against the global
|
|
|
|
* loop that this function returns.
|
|
|
|
*
|
|
|
|
* # Return
|
|
|
|
*
|
|
|
|
* * A `hl::high_level_loop` that encapsulates communication with the global
|
|
|
|
* loop.
|
|
|
|
*/
|
2012-10-01 19:26:50 -05:00
|
|
|
pub fn get() -> IoTask {
|
2012-08-01 19:30:05 -05:00
|
|
|
return get_monitor_task_gl();
|
2012-04-19 01:49:20 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
2012-08-29 19:41:38 -05:00
|
|
|
fn get_monitor_task_gl() -> IoTask unsafe {
|
2012-05-24 23:38:48 -05:00
|
|
|
|
2013-01-20 01:38:17 -06:00
|
|
|
type MonChan = Chan<IoTask>;
|
2012-05-24 23:38:48 -05:00
|
|
|
|
2013-01-20 01:38:17 -06:00
|
|
|
struct GlobalIoTask(IoTask);
|
2012-05-24 23:38:48 -05:00
|
|
|
|
2013-01-20 01:38:17 -06:00
|
|
|
impl GlobalIoTask: Clone {
|
|
|
|
fn clone(&self) -> GlobalIoTask {
|
|
|
|
GlobalIoTask((**self).clone())
|
|
|
|
}
|
|
|
|
}
|
2012-05-24 23:38:48 -05:00
|
|
|
|
2013-01-20 01:38:17 -06:00
|
|
|
fn key(_: GlobalIoTask) { }
|
|
|
|
|
|
|
|
match global_data_clone(key) {
|
|
|
|
Some(GlobalIoTask(iotask)) => iotask,
|
|
|
|
None => {
|
|
|
|
let iotask: IoTask = spawn_loop();
|
|
|
|
let mut installed = false;
|
|
|
|
let final_iotask = do global_data_clone_create(key) {
|
|
|
|
installed = true;
|
|
|
|
~GlobalIoTask(iotask.clone())
|
|
|
|
};
|
|
|
|
if installed {
|
|
|
|
do task().unlinked().spawn() unsafe {
|
|
|
|
debug!("global monitor task starting");
|
|
|
|
// As a weak task the runtime will notify us when to exit
|
|
|
|
do weaken_task |weak_exit_po| {
|
2013-01-21 21:16:01 -06:00
|
|
|
debug!("global monitor task is weak");
|
2013-01-20 01:38:17 -06:00
|
|
|
weak_exit_po.recv();
|
|
|
|
iotask::exit(&iotask);
|
2013-01-21 21:16:01 -06:00
|
|
|
debug!("global monitor task is unweak");
|
2013-01-20 01:38:17 -06:00
|
|
|
};
|
|
|
|
debug!("global monitor task exiting");
|
2012-04-27 23:42:04 -05:00
|
|
|
}
|
2013-01-20 01:38:17 -06:00
|
|
|
} else {
|
|
|
|
iotask::exit(&iotask);
|
2012-05-24 23:38:48 -05:00
|
|
|
}
|
|
|
|
|
2013-01-20 01:38:17 -06:00
|
|
|
match final_iotask {
|
|
|
|
GlobalIoTask(iotask) => iotask
|
|
|
|
}
|
|
|
|
}
|
2012-04-17 14:05:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-29 19:41:38 -05:00
|
|
|
fn spawn_loop() -> IoTask {
|
2013-01-20 01:38:17 -06:00
|
|
|
let builder = do task().add_wrapper |task_body| {
|
2012-05-25 00:26:30 -05:00
|
|
|
fn~(move task_body) {
|
|
|
|
// The I/O loop task also needs to be weak so it doesn't keep
|
|
|
|
// the runtime alive
|
2012-08-24 14:17:08 -05:00
|
|
|
unsafe {
|
2013-01-20 01:38:17 -06:00
|
|
|
do weaken_task |_| {
|
|
|
|
debug!("global libuv task is now weak");
|
2012-08-24 14:17:08 -05:00
|
|
|
task_body();
|
2012-05-25 00:26:30 -05:00
|
|
|
|
2012-08-24 14:17:08 -05:00
|
|
|
// We don't wait for the exit message on weak_exit_po
|
|
|
|
// because the monitor task will tell the uv loop when to
|
|
|
|
// exit
|
2012-05-25 00:26:30 -05:00
|
|
|
|
2012-08-24 14:17:08 -05:00
|
|
|
debug!("global libuv task is leaving weakened state");
|
|
|
|
}
|
2012-05-25 00:26:30 -05:00
|
|
|
}
|
|
|
|
}
|
2012-07-23 18:53:22 -05:00
|
|
|
};
|
2013-01-20 01:38:17 -06:00
|
|
|
let builder = builder.unlinked();
|
2012-09-11 19:17:54 -05:00
|
|
|
spawn_iotask(move builder)
|
2012-04-17 14:05:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
2013-01-08 21:37:25 -06:00
|
|
|
use core::prelude::*;
|
|
|
|
|
2012-12-27 20:24:18 -06:00
|
|
|
use uv::iotask;
|
|
|
|
use uv::ll;
|
2013-01-08 21:37:25 -06:00
|
|
|
use uv_global_loop::*;
|
2012-12-27 20:24:18 -06:00
|
|
|
|
|
|
|
use core::iter;
|
|
|
|
use core::libc;
|
|
|
|
use core::oldcomm;
|
|
|
|
use core::ptr;
|
2012-12-28 14:46:08 -06:00
|
|
|
use core::task;
|
2012-12-27 20:24:18 -06:00
|
|
|
|
2012-07-03 18:32:02 -05:00
|
|
|
extern fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) unsafe {
|
2012-04-17 14:05:04 -05:00
|
|
|
let exit_ch_ptr = ll::get_data_for_uv_handle(
|
2012-12-13 16:18:47 -06:00
|
|
|
timer_ptr as *libc::c_void) as *oldcomm::Chan<bool>;
|
2012-04-17 14:05:04 -05:00
|
|
|
let exit_ch = *exit_ch_ptr;
|
2012-12-13 16:18:47 -06:00
|
|
|
oldcomm::send(exit_ch, true);
|
2012-08-22 19:24:52 -05:00
|
|
|
log(debug, fmt!("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
|
|
|
|
exit_ch_ptr));
|
2012-04-17 14:05:04 -05:00
|
|
|
}
|
2012-07-03 18:32:02 -05:00
|
|
|
extern fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
|
2012-05-24 22:31:20 -05:00
|
|
|
_status: libc::c_int) unsafe {
|
2012-07-14 00:57:48 -05:00
|
|
|
log(debug, ~"in simple timer cb");
|
2012-04-17 14:05:04 -05:00
|
|
|
ll::timer_stop(timer_ptr);
|
2013-01-20 01:38:17 -06:00
|
|
|
let hl_loop = &get_gl();
|
2012-08-24 14:17:08 -05:00
|
|
|
do iotask::interact(hl_loop) |_loop_ptr| unsafe {
|
2012-07-14 00:57:48 -05:00
|
|
|
log(debug, ~"closing timer");
|
2012-04-27 23:42:04 -05:00
|
|
|
ll::close(timer_ptr, simple_timer_close_cb);
|
2012-07-14 00:57:48 -05:00
|
|
|
log(debug, ~"about to deref exit_ch_ptr");
|
|
|
|
log(debug, ~"after msg sent on deref'd exit_ch");
|
2012-04-17 14:05:04 -05:00
|
|
|
};
|
2012-07-14 00:57:48 -05:00
|
|
|
log(debug, ~"exiting simple timer cb");
|
2012-04-17 14:05:04 -05:00
|
|
|
}
|
|
|
|
|
2013-01-20 01:38:17 -06:00
|
|
|
fn impl_uv_hl_simple_timer(iotask: &IoTask) unsafe {
|
2012-12-13 16:18:47 -06:00
|
|
|
let exit_po = oldcomm::Port::<bool>();
|
|
|
|
let exit_ch = oldcomm::Chan(&exit_po);
|
2012-10-03 16:38:01 -05:00
|
|
|
let exit_ch_ptr = ptr::addr_of(&exit_ch);
|
2012-08-22 19:24:52 -05:00
|
|
|
log(debug, fmt!("EXIT_CH_PTR newly created exit_ch_ptr: %?",
|
|
|
|
exit_ch_ptr));
|
2012-04-17 14:05:04 -05:00
|
|
|
let timer_handle = ll::timer_t();
|
2012-10-03 16:38:01 -05:00
|
|
|
let timer_ptr = ptr::addr_of(&timer_handle);
|
2012-08-24 14:17:08 -05:00
|
|
|
do iotask::interact(iotask) |loop_ptr| unsafe {
|
2012-07-14 00:57:48 -05:00
|
|
|
log(debug, ~"user code inside interact loop!!!");
|
2012-04-17 14:05:04 -05:00
|
|
|
let init_status = ll::timer_init(loop_ptr, timer_ptr);
|
|
|
|
if(init_status == 0i32) {
|
|
|
|
ll::set_data_for_uv_handle(
|
|
|
|
timer_ptr as *libc::c_void,
|
|
|
|
exit_ch_ptr as *libc::c_void);
|
|
|
|
let start_status = ll::timer_start(timer_ptr, simple_timer_cb,
|
|
|
|
1u, 0u);
|
|
|
|
if(start_status == 0i32) {
|
|
|
|
}
|
|
|
|
else {
|
2012-07-14 00:57:48 -05:00
|
|
|
fail ~"failure on ll::timer_start()";
|
2012-04-17 14:05:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2012-07-14 00:57:48 -05:00
|
|
|
fail ~"failure on ll::timer_init()";
|
2012-04-17 14:05:04 -05:00
|
|
|
}
|
|
|
|
};
|
2012-12-13 16:18:47 -06:00
|
|
|
oldcomm::recv(exit_po);
|
2012-07-14 00:57:48 -05:00
|
|
|
log(debug, ~"global_loop timer test: msg recv on exit_po, done..");
|
2012-04-17 14:05:04 -05:00
|
|
|
}
|
2012-04-27 23:42:04 -05:00
|
|
|
|
2012-04-17 14:05:04 -05:00
|
|
|
#[test]
|
2012-04-27 23:42:04 -05:00
|
|
|
fn test_gl_uv_global_loop_high_level_global_timer() unsafe {
|
2013-01-20 01:38:17 -06:00
|
|
|
let hl_loop = &get_gl();
|
2012-12-13 16:18:47 -06:00
|
|
|
let exit_po = oldcomm::Port::<()>();
|
|
|
|
let exit_ch = oldcomm::Chan(&exit_po);
|
2012-08-15 16:10:46 -05:00
|
|
|
task::spawn_sched(task::ManualThreads(1u), || {
|
2013-01-20 01:38:17 -06:00
|
|
|
let hl_loop = &get_gl();
|
2012-04-17 14:05:04 -05:00
|
|
|
impl_uv_hl_simple_timer(hl_loop);
|
2012-12-13 16:18:47 -06:00
|
|
|
oldcomm::send(exit_ch, ());
|
2012-04-17 14:05:04 -05:00
|
|
|
});
|
|
|
|
impl_uv_hl_simple_timer(hl_loop);
|
2012-12-13 16:18:47 -06:00
|
|
|
oldcomm::recv(exit_po);
|
2012-04-27 23:42:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// keeping this test ignored until some kind of stress-test-harness
|
|
|
|
// is set up for the build bots
|
|
|
|
#[test]
|
|
|
|
#[ignore]
|
|
|
|
fn test_stress_gl_uv_global_loop_high_level_global_timer() unsafe {
|
2012-12-13 16:18:47 -06:00
|
|
|
let exit_po = oldcomm::Port::<()>();
|
|
|
|
let exit_ch = oldcomm::Chan(&exit_po);
|
2012-04-27 23:42:04 -05:00
|
|
|
let cycles = 5000u;
|
2012-07-04 14:04:28 -05:00
|
|
|
for iter::repeat(cycles) {
|
2012-08-15 16:10:46 -05:00
|
|
|
task::spawn_sched(task::ManualThreads(1u), || {
|
2013-01-20 01:38:17 -06:00
|
|
|
let hl_loop = &get_gl();
|
2012-04-27 23:42:04 -05:00
|
|
|
impl_uv_hl_simple_timer(hl_loop);
|
2012-12-13 16:18:47 -06:00
|
|
|
oldcomm::send(exit_ch, ());
|
2012-04-27 23:42:04 -05:00
|
|
|
});
|
|
|
|
};
|
2012-07-04 14:04:28 -05:00
|
|
|
for iter::repeat(cycles) {
|
2012-12-13 16:18:47 -06:00
|
|
|
oldcomm::recv(exit_po);
|
2012-04-27 23:42:04 -05:00
|
|
|
};
|
2012-07-14 00:57:48 -05:00
|
|
|
log(debug, ~"test_stress_gl_uv_global_loop_high_level_global_timer"+
|
|
|
|
~" exiting sucessfully!");
|
2012-04-17 14:05:04 -05:00
|
|
|
}
|
2012-07-04 14:04:28 -05:00
|
|
|
}
|