2013-12-12 19:47:48 -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.
|
|
|
|
|
|
|
|
//! A concurrent queue used to signal remote event loops
|
|
|
|
//!
|
|
|
|
//! This queue implementation is used to send tasks among event loops. This is
|
|
|
|
//! backed by a multi-producer/single-consumer queue from libstd and uv_async_t
|
|
|
|
//! handles (to wake up a remote event loop).
|
|
|
|
//!
|
|
|
|
//! The uv_async_t is stored next to the event loop, so in order to not keep the
|
|
|
|
//! event loop alive we use uv_ref and uv_unref in order to control when the
|
|
|
|
//! async handle is active or not.
|
|
|
|
|
2014-03-21 20:05:05 -05:00
|
|
|
#![allow(dead_code)]
|
2013-12-13 23:14:08 -06:00
|
|
|
|
2014-05-19 20:08:33 -05:00
|
|
|
use alloc::arc::Arc;
|
2014-04-18 21:09:31 -05:00
|
|
|
use libc::c_void;
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
use std::mem;
|
2014-06-04 02:00:59 -05:00
|
|
|
use std::rt::mutex::NativeMutex;
|
2013-12-12 19:47:48 -06:00
|
|
|
use std::rt::task::BlockedTask;
|
|
|
|
use mpsc = std::sync::mpsc_queue;
|
|
|
|
|
|
|
|
use async::AsyncWatcher;
|
|
|
|
use super::{Loop, UvHandle};
|
|
|
|
use uvll;
|
|
|
|
|
|
|
|
enum Message {
|
|
|
|
Task(BlockedTask),
|
|
|
|
Increment,
|
|
|
|
Decrement,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct State {
|
|
|
|
handle: *uvll::uv_async_t,
|
2014-02-14 19:01:52 -06:00
|
|
|
lock: NativeMutex, // see comments in async_cb for why this is needed
|
2014-01-06 17:23:37 -06:00
|
|
|
queue: mpsc::Queue<Message>,
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This structure is intended to be stored next to the event loop, and it is
|
|
|
|
/// used to create new `Queue` structures.
|
|
|
|
pub struct QueuePool {
|
2014-05-19 20:08:33 -05:00
|
|
|
queue: Arc<State>,
|
2014-03-28 12:27:14 -05:00
|
|
|
refcnt: uint,
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/// This type is used to send messages back to the original event loop.
|
|
|
|
pub struct Queue {
|
2014-05-19 20:08:33 -05:00
|
|
|
queue: Arc<State>,
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
|
2014-04-18 21:09:31 -05:00
|
|
|
extern fn async_cb(handle: *uvll::uv_async_t) {
|
2014-01-06 17:23:37 -06:00
|
|
|
let pool: &mut QueuePool = unsafe {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
mem::transmute(uvll::get_data_for_uv_handle(handle))
|
2013-12-12 19:47:48 -06:00
|
|
|
};
|
2014-05-19 20:08:33 -05:00
|
|
|
let state: &State = &*pool.queue;
|
2013-12-12 19:47:48 -06:00
|
|
|
|
|
|
|
// Remember that there is no guarantee about how many times an async
|
|
|
|
// callback is called with relation to the number of sends, so process the
|
|
|
|
// entire queue in a loop.
|
|
|
|
loop {
|
2014-01-06 17:23:37 -06:00
|
|
|
match state.queue.pop() {
|
2013-12-12 19:47:48 -06:00
|
|
|
mpsc::Data(Task(task)) => {
|
2014-01-16 21:58:42 -06:00
|
|
|
let _ = task.wake().map(|t| t.reawaken());
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
mpsc::Data(Increment) => unsafe {
|
2014-01-06 17:23:37 -06:00
|
|
|
if pool.refcnt == 0 {
|
|
|
|
uvll::uv_ref(state.handle);
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
2014-01-06 17:23:37 -06:00
|
|
|
pool.refcnt += 1;
|
2013-12-12 19:47:48 -06:00
|
|
|
},
|
|
|
|
mpsc::Data(Decrement) => unsafe {
|
2014-01-06 17:23:37 -06:00
|
|
|
pool.refcnt -= 1;
|
|
|
|
if pool.refcnt == 0 {
|
|
|
|
uvll::uv_unref(state.handle);
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
},
|
|
|
|
mpsc::Empty | mpsc::Inconsistent => break
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the refcount is now zero after processing the queue, then there is no
|
|
|
|
// longer a reference on the async handle and it is possible that this event
|
|
|
|
// loop can exit. What we're not guaranteed, however, is that a producer in
|
|
|
|
// the middle of dropping itself is yet done with the handle. It could be
|
|
|
|
// possible that we saw their Decrement message but they have yet to signal
|
|
|
|
// on the async handle. If we were to return immediately, the entire uv loop
|
|
|
|
// could be destroyed meaning the call to uv_async_send would abort()
|
|
|
|
//
|
|
|
|
// In order to fix this, an OS mutex is used to wait for the other end to
|
|
|
|
// finish before we continue. The drop block on a handle will acquire a
|
|
|
|
// mutex and then drop it after both the push and send have been completed.
|
|
|
|
// If we acquire the mutex here, then we are guaranteed that there are no
|
|
|
|
// longer any senders which are holding on to their handles, so we can
|
|
|
|
// safely allow the event loop to exit.
|
2014-01-06 17:23:37 -06:00
|
|
|
if pool.refcnt == 0 {
|
2013-12-12 19:47:48 -06:00
|
|
|
unsafe {
|
2014-01-06 17:23:37 -06:00
|
|
|
let _l = state.lock.lock();
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl QueuePool {
|
2014-05-05 20:56:44 -05:00
|
|
|
pub fn new(loop_: &mut Loop) -> Box<QueuePool> {
|
2013-12-12 19:47:48 -06:00
|
|
|
let handle = UvHandle::alloc(None::<AsyncWatcher>, uvll::UV_ASYNC);
|
2014-05-19 20:08:33 -05:00
|
|
|
let state = Arc::new(State {
|
2013-12-12 19:47:48 -06:00
|
|
|
handle: handle,
|
2014-02-14 19:01:52 -06:00
|
|
|
lock: unsafe {NativeMutex::new()},
|
2014-01-06 17:23:37 -06:00
|
|
|
queue: mpsc::Queue::new(),
|
2013-12-12 19:47:48 -06:00
|
|
|
});
|
2014-04-25 03:08:02 -05:00
|
|
|
let q = box QueuePool {
|
2013-12-12 19:47:48 -06:00
|
|
|
refcnt: 0,
|
2014-01-06 17:23:37 -06:00
|
|
|
queue: state,
|
2013-12-12 19:47:48 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
assert_eq!(uvll::uv_async_init(loop_.handle, handle, async_cb), 0);
|
|
|
|
uvll::uv_unref(handle);
|
2014-02-21 05:40:53 -06:00
|
|
|
let data = &*q as *QueuePool as *c_void;
|
2013-12-12 19:47:48 -06:00
|
|
|
uvll::set_data_for_uv_handle(handle, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
return q;
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn queue(&mut self) -> Queue {
|
|
|
|
unsafe {
|
|
|
|
if self.refcnt == 0 {
|
2014-05-19 20:08:33 -05:00
|
|
|
uvll::uv_ref(self.queue.handle);
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
self.refcnt += 1;
|
|
|
|
}
|
2014-01-06 17:23:37 -06:00
|
|
|
Queue { queue: self.queue.clone() }
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
2013-12-16 00:20:53 -06:00
|
|
|
|
2014-05-19 20:08:33 -05:00
|
|
|
pub fn handle(&self) -> *uvll::uv_async_t { self.queue.handle }
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Queue {
|
|
|
|
pub fn push(&mut self, task: BlockedTask) {
|
2014-05-19 20:08:33 -05:00
|
|
|
self.queue.queue.push(Task(task));
|
|
|
|
unsafe { uvll::uv_async_send(self.queue.handle); }
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Clone for Queue {
|
|
|
|
fn clone(&self) -> Queue {
|
|
|
|
// Push a request to increment on the queue, but there's no need to
|
|
|
|
// signal the event loop to process it at this time. We're guaranteed
|
|
|
|
// that the count is at least one (because we have a queue right here),
|
|
|
|
// and if the queue is dropped later on it'll see the increment for the
|
|
|
|
// decrement anyway.
|
2014-05-19 20:08:33 -05:00
|
|
|
self.queue.queue.push(Increment);
|
2013-12-12 19:47:48 -06:00
|
|
|
Queue { queue: self.queue.clone() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for Queue {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
// See the comments in the async_cb function for why there is a lock
|
|
|
|
// that is acquired only on a drop.
|
|
|
|
unsafe {
|
2014-05-19 20:08:33 -05:00
|
|
|
let _l = self.queue.lock.lock();
|
|
|
|
self.queue.queue.push(Decrement);
|
|
|
|
uvll::uv_async_send(self.queue.handle);
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for State {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
uvll::uv_close(self.handle, mem::transmute(0));
|
2013-12-16 00:20:53 -06:00
|
|
|
// Note that this does *not* free the handle, that is the
|
|
|
|
// responsibility of the caller because the uv loop must be closed
|
|
|
|
// before we deallocate this uv handle.
|
2013-12-12 19:47:48 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|