2013-10-22 17:00:37 -05: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.
|
|
|
|
|
|
|
|
//! This is a basic event loop implementation not meant for any "real purposes"
|
|
|
|
//! other than testing the scheduler and proving that it's possible to have a
|
|
|
|
//! pluggable event loop.
|
|
|
|
|
|
|
|
use prelude::*;
|
|
|
|
|
|
|
|
use cast;
|
2013-11-04 14:45:05 -06:00
|
|
|
use rt::rtio::{EventLoop, IoFactory, RemoteCallback, PausibleIdleCallback,
|
|
|
|
Callback};
|
2013-10-22 17:00:37 -05:00
|
|
|
use unstable::sync::Exclusive;
|
2013-11-12 16:38:28 -06:00
|
|
|
use io::native;
|
2013-10-22 17:00:37 -05:00
|
|
|
use util;
|
|
|
|
|
|
|
|
/// This is the only exported function from this module.
|
|
|
|
pub fn event_loop() -> ~EventLoop {
|
|
|
|
~BasicLoop::new() as ~EventLoop
|
|
|
|
}
|
|
|
|
|
|
|
|
struct BasicLoop {
|
2013-11-04 14:45:05 -06:00
|
|
|
work: ~[proc()], // pending work
|
|
|
|
idle: Option<*mut BasicPausible>, // only one is allowed
|
|
|
|
remotes: ~[(uint, ~Callback)],
|
2013-10-22 17:00:37 -05:00
|
|
|
next_remote: uint,
|
2013-11-12 16:38:28 -06:00
|
|
|
messages: Exclusive<~[Message]>,
|
|
|
|
io: ~IoFactory,
|
2013-10-22 17:00:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
enum Message { RunRemote(uint), RemoveRemote(uint) }
|
|
|
|
|
|
|
|
impl BasicLoop {
|
|
|
|
fn new() -> BasicLoop {
|
|
|
|
BasicLoop {
|
|
|
|
work: ~[],
|
|
|
|
idle: None,
|
|
|
|
next_remote: 0,
|
|
|
|
remotes: ~[],
|
|
|
|
messages: Exclusive::new(~[]),
|
2013-11-12 16:38:28 -06:00
|
|
|
io: ~native::IoFactory as ~IoFactory,
|
2013-10-22 17:00:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Process everything in the work queue (continually)
|
|
|
|
fn work(&mut self) {
|
|
|
|
while self.work.len() > 0 {
|
|
|
|
for work in util::replace(&mut self.work, ~[]).move_iter() {
|
|
|
|
work();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn remote_work(&mut self) {
|
|
|
|
let messages = unsafe {
|
2013-11-20 16:17:12 -06:00
|
|
|
self.messages.with(|messages| {
|
2013-10-22 17:00:37 -05:00
|
|
|
if messages.len() > 0 {
|
|
|
|
Some(util::replace(messages, ~[]))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
2013-11-20 16:17:12 -06:00
|
|
|
})
|
2013-10-22 17:00:37 -05:00
|
|
|
};
|
|
|
|
let messages = match messages {
|
|
|
|
Some(m) => m, None => return
|
|
|
|
};
|
|
|
|
for message in messages.iter() {
|
|
|
|
self.message(*message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn message(&mut self, message: Message) {
|
|
|
|
match message {
|
|
|
|
RunRemote(i) => {
|
2013-11-04 14:45:05 -06:00
|
|
|
match self.remotes.mut_iter().find(|& &(id, _)| id == i) {
|
|
|
|
Some(&(_, ref mut f)) => f.call(),
|
2013-10-22 17:00:37 -05:00
|
|
|
None => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RemoveRemote(i) => {
|
|
|
|
match self.remotes.iter().position(|&(id, _)| id == i) {
|
|
|
|
Some(i) => { self.remotes.remove(i); }
|
|
|
|
None => unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Run the idle callback if one is registered
|
|
|
|
fn idle(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
match self.idle {
|
|
|
|
Some(idle) => {
|
|
|
|
if (*idle).active {
|
2013-11-06 13:38:53 -06:00
|
|
|
(*idle).work.call();
|
2013-10-22 17:00:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn has_idle(&self) -> bool {
|
|
|
|
unsafe { self.idle.is_some() && (**self.idle.get_ref()).active }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EventLoop for BasicLoop {
|
|
|
|
fn run(&mut self) {
|
|
|
|
// Not exactly efficient, but it gets the job done.
|
|
|
|
while self.remotes.len() > 0 || self.work.len() > 0 || self.has_idle() {
|
|
|
|
|
|
|
|
self.work();
|
|
|
|
self.remote_work();
|
|
|
|
|
|
|
|
if self.has_idle() {
|
|
|
|
self.idle();
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
// We block here if we have no messages to process and we may
|
|
|
|
// receive a message at a later date
|
2013-11-20 16:17:12 -06:00
|
|
|
self.messages.hold_and_wait(|messages| {
|
2013-10-22 17:00:37 -05:00
|
|
|
self.remotes.len() > 0 &&
|
|
|
|
messages.len() == 0 &&
|
|
|
|
self.work.len() == 0
|
2013-11-20 16:17:12 -06:00
|
|
|
})
|
2013-10-22 17:00:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-04 14:45:05 -06:00
|
|
|
fn callback(&mut self, f: proc()) {
|
2013-10-22 17:00:37 -05:00
|
|
|
self.work.push(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX: Seems like a really weird requirement to have an event loop provide.
|
2013-11-06 13:38:53 -06:00
|
|
|
fn pausible_idle_callback(&mut self, cb: ~Callback) -> ~PausibleIdleCallback {
|
|
|
|
let callback = ~BasicPausible::new(self, cb);
|
2013-10-22 17:00:37 -05:00
|
|
|
rtassert!(self.idle.is_none());
|
|
|
|
unsafe {
|
2013-11-04 14:45:05 -06:00
|
|
|
let cb_ptr: &*mut BasicPausible = cast::transmute(&callback);
|
2013-10-22 17:00:37 -05:00
|
|
|
self.idle = Some(*cb_ptr);
|
|
|
|
}
|
|
|
|
return callback as ~PausibleIdleCallback;
|
|
|
|
}
|
|
|
|
|
2013-11-04 14:45:05 -06:00
|
|
|
fn remote_callback(&mut self, f: ~Callback) -> ~RemoteCallback {
|
2013-10-22 17:00:37 -05:00
|
|
|
let id = self.next_remote;
|
|
|
|
self.next_remote += 1;
|
|
|
|
self.remotes.push((id, f));
|
|
|
|
~BasicRemote::new(self.messages.clone(), id) as ~RemoteCallback
|
|
|
|
}
|
|
|
|
|
2013-12-05 19:37:02 -06:00
|
|
|
fn io<'a>(&'a mut self) -> Option<&'a mut IoFactory> {
|
|
|
|
let factory: &mut IoFactory = self.io;
|
|
|
|
Some(factory)
|
2013-11-12 16:38:28 -06:00
|
|
|
}
|
2013-10-22 17:00:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
struct BasicRemote {
|
|
|
|
queue: Exclusive<~[Message]>,
|
|
|
|
id: uint,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BasicRemote {
|
|
|
|
fn new(queue: Exclusive<~[Message]>, id: uint) -> BasicRemote {
|
|
|
|
BasicRemote { queue: queue, id: id }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RemoteCallback for BasicRemote {
|
|
|
|
fn fire(&mut self) {
|
|
|
|
unsafe {
|
2013-11-20 16:17:12 -06:00
|
|
|
self.queue.hold_and_signal(|queue| {
|
2013-10-22 17:00:37 -05:00
|
|
|
queue.push(RunRemote(self.id));
|
2013-11-20 16:17:12 -06:00
|
|
|
})
|
2013-10-22 17:00:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for BasicRemote {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
2013-11-20 16:17:12 -06:00
|
|
|
self.queue.hold_and_signal(|queue| {
|
2013-10-22 17:00:37 -05:00
|
|
|
queue.push(RemoveRemote(self.id));
|
2013-11-20 16:17:12 -06:00
|
|
|
})
|
2013-10-22 17:00:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct BasicPausible {
|
|
|
|
eloop: *mut BasicLoop,
|
2013-11-06 13:38:53 -06:00
|
|
|
work: ~Callback,
|
2013-10-22 17:00:37 -05:00
|
|
|
active: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BasicPausible {
|
2013-11-06 13:38:53 -06:00
|
|
|
fn new(eloop: &mut BasicLoop, cb: ~Callback) -> BasicPausible {
|
2013-10-22 17:00:37 -05:00
|
|
|
BasicPausible {
|
|
|
|
active: false,
|
2013-11-06 13:38:53 -06:00
|
|
|
work: cb,
|
2013-10-22 17:00:37 -05:00
|
|
|
eloop: eloop,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PausibleIdleCallback for BasicPausible {
|
|
|
|
fn pause(&mut self) {
|
|
|
|
self.active = false;
|
|
|
|
}
|
|
|
|
fn resume(&mut self) {
|
|
|
|
self.active = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Drop for BasicPausible {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
(*self.eloop).idle = None;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|