<commit_before>use latch::{Latch, SpinLatch, LockLatch};
use job::{JobMode, HeapJob, StackJob};
use std::any::Any;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::sync::atomic::{AtomicUsize, AtomicPtr, Ordering};
use thread_pool::{self, WorkerThread};
use unwind;

#[cfg(test)]
mod test;

pub struct Scope<'scope> {
    /// thread where `scope()` was executed (note that individual jobs
    /// may be executing on different worker threads, though they
    /// should always be within the same pool of threads)
    owner_thread: *mut WorkerThread,

    /// number of jobs created that have not yet completed or errored
    counter: AtomicUsize,

    /// if some job panicked, the error is stored here; it will be
    /// propagated to the one who created the scope
    panic: AtomicPtr<Box<Any + Send + 'static>>,

    /// latch to set when the counter drops to zero (and hence this scope is complete)
    job_completed_latch: SpinLatch,

    marker: PhantomData<fn(&'scope ())>,
}

/// Create a "fork-join" scope `s` and invokes the closure with a
/// reference to `s`. This closure can then spawn asynchronous tasks
/// into `s`. Those tasks may run asynchronously with respect to the
/// closure; they may themselves spawn additional tasks into `s`. When
/// the closure returns, it will block until all tasks that have been
/// spawned into `s` complete.
///
/// `scope()` is a more flexible building block compared to `join()`,
/// since a loop can be used to spawn any number of tasks without
/// recursing. However, that flexibility comes at a performance price:
/// tasks spawned using `scope()` must be allocated onto the heap,
/// whereas `join()` can make exclusive use of the stack. **Prefer
/// `join()` (or, even better, parallel iterators) where possible.**
///
/// ### Example
///
/// The Rayon `join()` function launches two closures and waits for them
/// to stop. One could implement `join()` using a scope like so, although
/// it would be less efficient than the real implementation:
///
/// ```rust
/// pub fn join<A,B,RA,RB>(oper_a: A, oper_b: B) -> (RA, RB)
///     where A: FnOnce() -> RA + Send,
///           B: FnOnce() -> RB + Send,
///           RA: Send,
///           RB: Send,
/// {
///     let mut result_a: Option<RA> = None;
///     let mut result_b: Option<RB> = None;
///     rayon::scope(|s| {
///         s.spawn(|_| result_a = Some(oper_a()));
///         s.spawn(|_| result_b = Some(oper_b()));
///     });
///     (result_a.unwrap(), result_b.unwrap())
/// }
/// ```
///
/// ### Task execution
///
/// Task execution potentially starts as soon as `spawn()` is called.
/// The task will end sometime before `scope()` returns. Note that the
/// *closure* given to scope may return much earlier. In general
/// the lifetime of a scope created like `scope(body) goes something like this:
///
/// - Scope begins when `scope(body)` is called
/// - Scope body `body()` is invoked
///     - Scope tasks may be spawned
/// - Scope body returns
/// - Scope tasks execute, possibly spawning more tasks
/// - Once all tasks are done, scope ends and `scope()` returns
///
/// To see how and when tasks are joined, consider this example:
///
/// ```rust
/// // point start
/// rayon::scope(|s| {
///     s.spawn(|s| { // task s.1
///         s.spawn(|s| { // task s.1.1
///             rayon::scope(|t| {
///                 t.spawn(|_| ()); // task t.1
///                 t.spawn(|_| ()); // task t.2
///             });
///         });
///     });
///     s.spawn(|s| { // task 2
///     });
///     // point mid
/// });
/// // point end
/// ```
///
/// The various tasks that are run will execute roughly like so:
///
/// ```notrust
/// | (start)
/// |
/// | (scope `s` created)
/// +--------------------+ (task s.1)
/// +-------+ (task s.2) |
/// |       |            +---+ (task s.1.1)
/// |       |            |   |
/// |       |            |   | (scope `t` created)
/// |       |            |   +----------------+ (task t.1)
/// |       |            |   +---+ (task t.2) |
/// | (mid) |            |   |   |            |
/// :       |            |   + <-+------------+ (scope `t` ends)
/// :       |            |   |
/// |<------+------------+---+ (scope `s` ends)
/// |
/// | (end)
/// ```
///
/// The point here is that everything spawned into scope `s` will
/// terminate (at latest) at the same point -- right before the
/// original call to `rayon::scope` returns. This includes new
/// subtasks created by other subtasks (e.g., task `s.1.1`). If a new
/// scope is created (such as `t`), the things spawned into that scope
/// will be joined before that scope returns, which in turn occurs
/// before the creating task (task `s.1.1` in this case) finishes.
///
/// ### Accessing stack data
///
/// In general, spawned tasks may access stack data in place that
/// outlives the scope itself. Other data must be fully owned by the
/// spawned task.
///
/// ```rust
/// let ok: Vec<i32> = vec![1, 2, 3];
/// rayon::scope(|s| {
///     let bad: Vec<i32> = vec![4, 5, 6];
///     s.spawn(|_| {
///         // We can access `ok` because outlives the scope `s`.
///         println!("ok: {:?}", ok);
///
///         // If we just try to use `bad` here, the closure will borrow `bad`
///         // (because we are just printing it out, and that only requires a
///         // borrow), which will result in a compilation error. Read on
///         // for options.
///         // println!("bad: {:?}", bad);
///    });
/// });
/// ```
///
/// As the comments example above suggest, to reference `bad` we must
/// take ownership of it. One way to do this is to detach the closure
/// from the surrounding stack frame, using the `move` keyword. This
/// will cause it to take ownership of *all* the variables it touches,
/// in this case including both `ok` *and* `bad`:
///
/// ```rust
/// let ok: Vec<i32> = vec![1, 2, 3];
/// rayon::scope(|s| {
///     let bad: Vec<i32> = vec![4, 5, 6];
///     s.spawn(move |_| {
///         println!("ok: {:?}", ok);
///         println!("bad: {:?}", bad);
///     });
///
///     // That closure is fine, but now we can't use `ok` anywhere else,
///     // since it is owend by the previous task:
///     // s.spawn(|_| println!("ok: {:?}", ok));
/// });
/// ```
///
/// While this works, it could be a problem if we want to use `ok` elsewhere.
/// There are two choices. We can keep the closure as a `move` closure, but
/// instead of referencing the variable `ok`, we create a shadowed variable that
/// is a borrow of `ok` and capture *that*:
///
/// ```rust
/// let ok: Vec<i32> = vec![1, 2, 3];
/// rayon::scope(|s| {
///     let bad: Vec<i32> = vec![4, 5, 6];
///     let ok: &Vec<i32> = &ok; // shadow the original `ok`
///     s.spawn(move |_| {
///         println!("ok: {:?}", ok); // captures the shadowed version
///         println!("bad: {:?}", bad);
///     });
///
///     // Now we too can use the shadowed `ok`, since `&Vec<i32>` references
///     // can be shared freely. Note that we need a `move` closure here though,
///     // because otherwise we'd be trying to borrow the shadowed `ok`,
///     // and that doesn't outlive `scope`.
///     s.spawn(move |_| println!("ok: {:?}", ok));
/// });
/// ```
///
/// Another option is not to use the `move` keyword but instead to take ownership
/// of individual variables:
///
/// ```rust
/// let ok: Vec<i32> = vec![1, 2, 3];
/// rayon::scope(|s| {
///     let bad: Vec<i32> = vec![4, 5, 6];
///     s.spawn(|_| {
///         // Transfer ownership of `bad` into a local variable (also named `bad`).
///         // This will force the closure to take ownership of `bad` from the environment.
///         let bad = bad;
///         println!("ok: {:?}", ok); // `ok` is only borrowed.
///         println!("bad: {:?}", bad); // refers to our local variable, above.
///     });
///
///     s.spawn(|_| println!("ok: {:?}", ok)); // we too can borrow `ok`
/// });
/// ```
pub fn scope<'scope, OP>(op: OP)
    where OP: for<'s> FnOnce(&'s Scope<'scope>) + 'scope + Send
{
    unsafe {
        let owner_thread = WorkerThread::current();
        if !owner_thread.is_null() {
            let scope: Scope<'scope> = Scope {
                owner_thread: owner_thread,
                counter: AtomicUsize::new(1),
                panic: AtomicPtr::new(ptr::null_mut()),
                job_completed_latch: SpinLatch::new(),
                marker: PhantomData,
            };
            scope.execute_job_closure(op);
            scope.steal_till_jobs_complete();
        } else {
            scope_not_in_worker(op)
        }
    }
}

#[cold]
unsafe fn scope_not_in_worker<'scope, OP>(op: OP)
    where OP: for<'s> FnOnce(&'s Scope<'scope>) + 'scope + Send
{
    // never run from a worker thread; just shifts over into worker threads
    debug_assert!(WorkerThread::current().is_null());

    let mut result = None;
    {
        let job = StackJob::new(|| result = Some(scope(op)), LockLatch::new());
        thread_pool::get_registry().inject(&[job.as_job_ref()]);
        job.latch.wait();
    }
    result.unwrap()
}

impl<'scope> Scope<'scope> {
    /// Spawns a job into the fork-join scope `self`. This job will
    /// execute sometime before the fork-join scope completes.  The
    /// job is specified as a closure, and this closure receives its
    /// own reference to `self` as argument. This can be used to
    /// inject new jobs into `self`.
    pub fn spawn<BODY>(&self, body: BODY)
        where BODY: FnOnce(&Scope<'scope>) + 'scope
    {
        unsafe {
            let old_value = self.counter.fetch_add(1, Ordering::SeqCst);
            assert!(old_value > 0); // scope can't have completed yet
            let job_ref = Box::new(HeapJob::new(move |mode| self.execute_job(body, mode)))
                .as_job_ref();
            let worker_thread = WorkerThread::current();

            // the `Scope` is not send or sync, and we only give out
            // pointers to it from within a worker thread
            debug_assert!(!WorkerThread::current().is_null());

            let worker_thread = &*worker_thread;
            let spawn_count = worker_thread.spawn_count();
            spawn_count.set(spawn_count.get() + 1);
            worker_thread.push(job_ref);
        }
    }

    /// Executes `func` as a job, either aborting or executing as
    /// appropriate.
    ///
    /// Unsafe because it must be executed on a worker thread.
    unsafe fn execute_job<FUNC>(&self, func: FUNC, mode: JobMode)
        where FUNC: FnOnce(&Scope<'scope>) + 'scope
    {
        match mode {
            JobMode::Execute => self.execute_job_closure(func),
            JobMode::Abort => self.job_completed_ok(),
        }
    }

    /// Executes `func` as a job in scope. Adjusts the "job completed"
    /// counters and also catches any panic and stores it into
    /// `scope`.
    ///
    /// Unsafe because this must be executed on a worker thread.
    unsafe fn execute_job_closure<FUNC>(&self, func: FUNC)
        where FUNC: FnOnce(&Scope<'scope>) + 'scope
    {
        let worker_thread = &*WorkerThread::current();
        let start_count = worker_thread.spawn_count().get();

        match unwind::halt_unwinding(move || func(self)) {
            Ok(()) => self.job_completed_ok(),
            Err(err) => self.job_panicked(err),
        }

        Self::pop_jobs(worker_thread, start_count);
    }

    /// We have to maintain an invariant that we pop off any work
    /// that we pushed onto the local thread deque. In other words,
    /// if no thieves are at play, then the height of the local
    /// deque must be the same when we enter and exit. Otherwise,
    /// we get into trouble composing with the main `join` API,
    /// which assumes that -- after it executes the first closure
    /// -- the top-most thing on the stack is the second closure.
    ///
    /// Unsafe because `worker_thread` must be the current worker
    /// thread, and it must be correct to pop jobs until the
    /// spawn-count on `worker_thread` is `start_count`.
    unsafe fn pop_jobs(worker_thread: &WorkerThread, start_count: usize) {
        let spawn_count = worker_thread.spawn_count();
        let current_count = spawn_count.get();
        for _ in start_count..current_count {
            if let Some(job_ref) = worker_thread.pop() {
                job_ref.execute(JobMode::Execute);
            }
        }
        spawn_count.set(start_count);
    }

    unsafe fn job_panicked(&self, err: Box<Any + Send + 'static>) {
        // capture the first error we see, free the rest
        let nil = ptr::null_mut();
        let mut err = Box::new(err); // box up the fat ptr
        if self.panic.compare_and_swap(nil, &mut *err, Ordering::SeqCst).is_null() {
            mem::forget(err); // ownership now transferred into self.panic
        }

        self.job_completed_ok()
    }

    unsafe fn job_completed_ok(&self) {
        let old_value = self.counter.fetch_sub(1, Ordering::Release);
        if old_value == 1 {
            // Important: grab the lock here to avoid a data race with
            // the `block_till_jobs_complete` code. Consider what could
            // otherwise happen:
            //
            // ```
            //    Us          Them
            //              Acquire lock
            //              Read counter: 1
            // Dec counter
            // Notify all
            //              Wait on job_completed_cvar
            // ```
            //
            // By holding the lock, we ensure that the "read counter"
            // and "wait on job_completed_cvar" occur atomically with respect to the
            // notify.
            self.job_completed_latch.set();
        }
    }

    unsafe fn steal_till_jobs_complete(&self) {
        // wait for job counter to reach 0:
        (*self.owner_thread).steal_until(&self.job_completed_latch);

        // propagate panic, if any occurred; at this point, all
        // outstanding jobs have completed, so we can use a relaxed
        // ordering:
        let panic = self.panic.swap(ptr::null_mut(), Ordering::Relaxed);
        if !panic.is_null() {
            let value: Box<Box<Any + Send + 'static>> = mem::transmute(panic);
            unwind::resume_unwinding(*value);
        }
    }
}
<commit_msg>add a note about thread-locals<commit_after>use latch::{Latch, SpinLatch, LockLatch};
use job::{JobMode, HeapJob, StackJob};
use std::any::Any;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::sync::atomic::{AtomicUsize, AtomicPtr, Ordering};
use thread_pool::{self, WorkerThread};
use unwind;

#[cfg(test)]
mod test;

pub struct Scope<'scope> {
    /// thread where `scope()` was executed (note that individual jobs
    /// may be executing on different worker threads, though they
    /// should always be within the same pool of threads)
    owner_thread: *mut WorkerThread,

    /// number of jobs created that have not yet completed or errored
    counter: AtomicUsize,

    /// if some job panicked, the error is stored here; it will be
    /// propagated to the one who created the scope
    panic: AtomicPtr<Box<Any + Send + 'static>>,

    /// latch to set when the counter drops to zero (and hence this scope is complete)
    job_completed_latch: SpinLatch,

    marker: PhantomData<fn(&'scope ())>,
}

/// Create a "fork-join" scope `s` and invokes the closure with a
/// reference to `s`. This closure can then spawn asynchronous tasks
/// into `s`. Those tasks may run asynchronously with respect to the
/// closure; they may themselves spawn additional tasks into `s`. When
/// the closure returns, it will block until all tasks that have been
/// spawned into `s` complete.
///
/// `scope()` is a more flexible building block compared to `join()`,
/// since a loop can be used to spawn any number of tasks without
/// recursing. However, that flexibility comes at a performance price:
/// tasks spawned using `scope()` must be allocated onto the heap,
/// whereas `join()` can make exclusive use of the stack. **Prefer
/// `join()` (or, even better, parallel iterators) where possible.**
///
/// ### Example
///
/// The Rayon `join()` function launches two closures and waits for them
/// to stop. One could implement `join()` using a scope like so, although
/// it would be less efficient than the real implementation:
///
/// ```rust
/// pub fn join<A,B,RA,RB>(oper_a: A, oper_b: B) -> (RA, RB)
///     where A: FnOnce() -> RA + Send,
///           B: FnOnce() -> RB + Send,
///           RA: Send,
///           RB: Send,
/// {
///     let mut result_a: Option<RA> = None;
///     let mut result_b: Option<RB> = None;
///     rayon::scope(|s| {
///         s.spawn(|_| result_a = Some(oper_a()));
///         s.spawn(|_| result_b = Some(oper_b()));
///     });
///     (result_a.unwrap(), result_b.unwrap())
/// }
/// ```
///
/// ### A note on threading
///
/// The closure given to `scope()` executes in the Rayon thread-pool,
/// as do those given to `spawn()`. This means that you can't access
/// thread-local variables (well, you can, but they may have
/// unexpected values).
///
/// ### Task execution
///
/// Task execution potentially starts as soon as `spawn()` is called.
/// The task will end sometime before `scope()` returns. Note that the
/// *closure* given to scope may return much earlier. In general
/// the lifetime of a scope created like `scope(body) goes something like this:
///
/// - Scope begins when `scope(body)` is called
/// - Scope body `body()` is invoked
///     - Scope tasks may be spawned
/// - Scope body returns
/// - Scope tasks execute, possibly spawning more tasks
/// - Once all tasks are done, scope ends and `scope()` returns
///
/// To see how and when tasks are joined, consider this example:
///
/// ```rust
/// // point start
/// rayon::scope(|s| {
///     s.spawn(|s| { // task s.1
///         s.spawn(|s| { // task s.1.1
///             rayon::scope(|t| {
///                 t.spawn(|_| ()); // task t.1
///                 t.spawn(|_| ()); // task t.2
///             });
///         });
///     });
///     s.spawn(|s| { // task 2
///     });
///     // point mid
/// });
/// // point end
/// ```
///
/// The various tasks that are run will execute roughly like so:
///
/// ```notrust
/// | (start)
/// |
/// | (scope `s` created)
/// +--------------------+ (task s.1)
/// +-------+ (task s.2) |
/// |       |            +---+ (task s.1.1)
/// |       |            |   |
/// |       |            |   | (scope `t` created)
/// |       |            |   +----------------+ (task t.1)
/// |       |            |   +---+ (task t.2) |
/// | (mid) |            |   |   |            |
/// :       |            |   + <-+------------+ (scope `t` ends)
/// :       |            |   |
/// |<------+------------+---+ (scope `s` ends)
/// |
/// | (end)
/// ```
///
/// The point here is that everything spawned into scope `s` will
/// terminate (at latest) at the same point -- right before the
/// original call to `rayon::scope` returns. This includes new
/// subtasks created by other subtasks (e.g., task `s.1.1`). If a new
/// scope is created (such as `t`), the things spawned into that scope
/// will be joined before that scope returns, which in turn occurs
/// before the creating task (task `s.1.1` in this case) finishes.
///
/// ### Accessing stack data
///
/// In general, spawned tasks may access stack data in place that
/// outlives the scope itself. Other data must be fully owned by the
/// spawned task.
///
/// ```rust
/// let ok: Vec<i32> = vec![1, 2, 3];
/// rayon::scope(|s| {
///     let bad: Vec<i32> = vec![4, 5, 6];
///     s.spawn(|_| {
///         // We can access `ok` because outlives the scope `s`.
///         println!("ok: {:?}", ok);
///
///         // If we just try to use `bad` here, the closure will borrow `bad`
///         // (because we are just printing it out, and that only requires a
///         // borrow), which will result in a compilation error. Read on
///         // for options.
///         // println!("bad: {:?}", bad);
///    });
/// });
/// ```
///
/// As the comments example above suggest, to reference `bad` we must
/// take ownership of it. One way to do this is to detach the closure
/// from the surrounding stack frame, using the `move` keyword. This
/// will cause it to take ownership of *all* the variables it touches,
/// in this case including both `ok` *and* `bad`:
///
/// ```rust
/// let ok: Vec<i32> = vec![1, 2, 3];
/// rayon::scope(|s| {
///     let bad: Vec<i32> = vec![4, 5, 6];
///     s.spawn(move |_| {
///         println!("ok: {:?}", ok);
///         println!("bad: {:?}", bad);
///     });
///
///     // That closure is fine, but now we can't use `ok` anywhere else,
///     // since it is owend by the previous task:
///     // s.spawn(|_| println!("ok: {:?}", ok));
/// });
/// ```
///
/// While this works, it could be a problem if we want to use `ok` elsewhere.
/// There are two choices. We can keep the closure as a `move` closure, but
/// instead of referencing the variable `ok`, we create a shadowed variable that
/// is a borrow of `ok` and capture *that*:
///
/// ```rust
/// let ok: Vec<i32> = vec![1, 2, 3];
/// rayon::scope(|s| {
///     let bad: Vec<i32> = vec![4, 5, 6];
///     let ok: &Vec<i32> = &ok; // shadow the original `ok`
///     s.spawn(move |_| {
///         println!("ok: {:?}", ok); // captures the shadowed version
///         println!("bad: {:?}", bad);
///     });
///
///     // Now we too can use the shadowed `ok`, since `&Vec<i32>` references
///     // can be shared freely. Note that we need a `move` closure here though,
///     // because otherwise we'd be trying to borrow the shadowed `ok`,
///     // and that doesn't outlive `scope`.
///     s.spawn(move |_| println!("ok: {:?}", ok));
/// });
/// ```
///
/// Another option is not to use the `move` keyword but instead to take ownership
/// of individual variables:
///
/// ```rust
/// let ok: Vec<i32> = vec![1, 2, 3];
/// rayon::scope(|s| {
///     let bad: Vec<i32> = vec![4, 5, 6];
///     s.spawn(|_| {
///         // Transfer ownership of `bad` into a local variable (also named `bad`).
///         // This will force the closure to take ownership of `bad` from the environment.
///         let bad = bad;
///         println!("ok: {:?}", ok); // `ok` is only borrowed.
///         println!("bad: {:?}", bad); // refers to our local variable, above.
///     });
///
///     s.spawn(|_| println!("ok: {:?}", ok)); // we too can borrow `ok`
/// });
/// ```
pub fn scope<'scope, OP>(op: OP)
    where OP: for<'s> FnOnce(&'s Scope<'scope>) + 'scope + Send
{
    unsafe {
        let owner_thread = WorkerThread::current();
        if !owner_thread.is_null() {
            let scope: Scope<'scope> = Scope {
                owner_thread: owner_thread,
                counter: AtomicUsize::new(1),
                panic: AtomicPtr::new(ptr::null_mut()),
                job_completed_latch: SpinLatch::new(),
                marker: PhantomData,
            };
            scope.execute_job_closure(op);
            scope.steal_till_jobs_complete();
        } else {
            scope_not_in_worker(op)
        }
    }
}

#[cold]
unsafe fn scope_not_in_worker<'scope, OP>(op: OP)
    where OP: for<'s> FnOnce(&'s Scope<'scope>) + 'scope + Send
{
    // never run from a worker thread; just shifts over into worker threads
    debug_assert!(WorkerThread::current().is_null());

    let mut result = None;
    {
        let job = StackJob::new(|| result = Some(scope(op)), LockLatch::new());
        thread_pool::get_registry().inject(&[job.as_job_ref()]);
        job.latch.wait();
    }
    result.unwrap()
}

impl<'scope> Scope<'scope> {
    /// Spawns a job into the fork-join scope `self`. This job will
    /// execute sometime before the fork-join scope completes.  The
    /// job is specified as a closure, and this closure receives its
    /// own reference to `self` as argument. This can be used to
    /// inject new jobs into `self`.
    pub fn spawn<BODY>(&self, body: BODY)
        where BODY: FnOnce(&Scope<'scope>) + 'scope
    {
        unsafe {
            let old_value = self.counter.fetch_add(1, Ordering::SeqCst);
            assert!(old_value > 0); // scope can't have completed yet
            let job_ref = Box::new(HeapJob::new(move |mode| self.execute_job(body, mode)))
                .as_job_ref();
            let worker_thread = WorkerThread::current();

            // the `Scope` is not send or sync, and we only give out
            // pointers to it from within a worker thread
            debug_assert!(!WorkerThread::current().is_null());

            let worker_thread = &*worker_thread;
            let spawn_count = worker_thread.spawn_count();
            spawn_count.set(spawn_count.get() + 1);
            worker_thread.push(job_ref);
        }
    }

    /// Executes `func` as a job, either aborting or executing as
    /// appropriate.
    ///
    /// Unsafe because it must be executed on a worker thread.
    unsafe fn execute_job<FUNC>(&self, func: FUNC, mode: JobMode)
        where FUNC: FnOnce(&Scope<'scope>) + 'scope
    {
        match mode {
            JobMode::Execute => self.execute_job_closure(func),
            JobMode::Abort => self.job_completed_ok(),
        }
    }

    /// Executes `func` as a job in scope. Adjusts the "job completed"
    /// counters and also catches any panic and stores it into
    /// `scope`.
    ///
    /// Unsafe because this must be executed on a worker thread.
    unsafe fn execute_job_closure<FUNC>(&self, func: FUNC)
        where FUNC: FnOnce(&Scope<'scope>) + 'scope
    {
        let worker_thread = &*WorkerThread::current();
        let start_count = worker_thread.spawn_count().get();

        match unwind::halt_unwinding(move || func(self)) {
            Ok(()) => self.job_completed_ok(),
            Err(err) => self.job_panicked(err),
        }

        Self::pop_jobs(worker_thread, start_count);
    }

    /// We have to maintain an invariant that we pop off any work
    /// that we pushed onto the local thread deque. In other words,
    /// if no thieves are at play, then the height of the local
    /// deque must be the same when we enter and exit. Otherwise,
    /// we get into trouble composing with the main `join` API,
    /// which assumes that -- after it executes the first closure
    /// -- the top-most thing on the stack is the second closure.
    ///
    /// Unsafe because `worker_thread` must be the current worker
    /// thread, and it must be correct to pop jobs until the
    /// spawn-count on `worker_thread` is `start_count`.
    unsafe fn pop_jobs(worker_thread: &WorkerThread, start_count: usize) {
        let spawn_count = worker_thread.spawn_count();
        let current_count = spawn_count.get();
        for _ in start_count..current_count {
            if let Some(job_ref) = worker_thread.pop() {
                job_ref.execute(JobMode::Execute);
            }
        }
        spawn_count.set(start_count);
    }

    unsafe fn job_panicked(&self, err: Box<Any + Send + 'static>) {
        // capture the first error we see, free the rest
        let nil = ptr::null_mut();
        let mut err = Box::new(err); // box up the fat ptr
        if self.panic.compare_and_swap(nil, &mut *err, Ordering::SeqCst).is_null() {
            mem::forget(err); // ownership now transferred into self.panic
        }

        self.job_completed_ok()
    }

    unsafe fn job_completed_ok(&self) {
        let old_value = self.counter.fetch_sub(1, Ordering::Release);
        if old_value == 1 {
            // Important: grab the lock here to avoid a data race with
            // the `block_till_jobs_complete` code. Consider what could
            // otherwise happen:
            //
            // ```
            //    Us          Them
            //              Acquire lock
            //              Read counter: 1
            // Dec counter
            // Notify all
            //              Wait on job_completed_cvar
            // ```
            //
            // By holding the lock, we ensure that the "read counter"
            // and "wait on job_completed_cvar" occur atomically with respect to the
            // notify.
            self.job_completed_latch.set();
        }
    }

    unsafe fn steal_till_jobs_complete(&self) {
        // wait for job counter to reach 0:
        (*self.owner_thread).steal_until(&self.job_completed_latch);

        // propagate panic, if any occurred; at this point, all
        // outstanding jobs have completed, so we can use a relaxed
        // ordering:
        let panic = self.panic.swap(ptr::null_mut(), Ordering::Relaxed);
        if !panic.is_null() {
            let value: Box<Box<Any + Send + 'static>> = mem::transmute(panic);
            unwind::resume_unwinding(*value);
        }
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use std::borrow::BorrowMut;
use gl;
use gl::types::*;
use context::ContextOf;
use framebuffer::FramebufferBinding;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl<AB, EAB, P, FB, RB, TU> ContextOf<AB, EAB, P, FB, RB, TU> {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }

    pub fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ArrayBufferBinding<'a>,
            ContextOf<(), EAB, P, FB, RB, TU>
        )
        where AB: BorrowMut<ArrayBufferBinder>
    {
        let (mut array_buffer, gl) = self.split_array_buffer();
        (array_buffer.borrow_mut().bind(buffer), gl)
    }

    pub fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ElementArrayBufferBinding<'a>,
            ContextOf<AB, (), P, FB, RB, TU>
        )
        where EAB: BorrowMut<ElementArrayBufferBinder>
    {
        let (mut element_array_buffer, gl) = self.split_element_array_buffer();
        (element_array_buffer.borrow_mut().bind(buffer), gl)
    }
}

gl_enum! {
    pub gl_enum BufferDataUsage {
        StreamDraw as STREAM_DRAW = gl::STREAM_DRAW,
        StaticDraw as STATIC_DRAW = gl::STATIC_DRAW,
        DynamicDraw as DYNAMIC_DRAW = gl::DYNAMIC_DRAW
    }
}

gl_enum! {
    pub gl_enum BufferBindingTarget {
        ArrayBuffer as ARRAY_BUFFER = gl::ARRAY_BUFFER,
        ElementArrayBuffer as ELEMENT_ARRAY_BUFFER = gl::ELEMENT_ARRAY_BUFFER
    }
}

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target().gl_enum(),
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage.gl_enum());
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indices: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode.gl_enum(),
                     count as GLsizei,
                     gl_index_type,
                     indices);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type.gl_enum(),
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }
}

impl<'a> FramebufferBinding<'a> {
    pub unsafe fn draw_arrays_range(&mut self,
                                    _ab: &ArrayBufferBinding,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode.gl_enum(), first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&mut self,
                                           _ab: &ArrayBufferBinding,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&mut self,
                                     _ab: &ArrayBufferBinding,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indices.len());

        let ptr = indices.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&mut self,
                                   _ab: &ArrayBufferBinding,
                                   mode: DrawingMode,
                                   indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(_ab, mode, indices.len(), indices);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    unsafe {
        gl::BindBuffer(target as GLuint, buffer.gl_id());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`target` is not an allowed value",
            _ => "Unknown error"
        }
    }
}

pub struct BufferBinderOf<A, E> {
    array: A,
    element_array: E
}

pub type BufferBinder = BufferBinderOf<ArrayBufferBinder,
                                       ElementArrayBufferBinder>;

pub type BufferBinderRef<'a> = BufferBinderOf<&'a ArrayBufferBinder,
                                              &'a ElementArrayBufferBinder>;

pub type BufferBinderMut<'a> = BufferBinderOf<&'a mut ArrayBufferBinder,
                                              &'a mut ElementArrayBufferBinder>;

impl<A, E> BufferBinderOf<A, E> {
    pub unsafe fn current() -> BufferBinder {
        BufferBinderOf {
            array: ArrayBufferBinder,
            element_array: ElementArrayBufferBinder
        }
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer) -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}
<commit_msg>Add `BufferBinder.borrowed()` and `borrowed_mut()`<commit_after>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use std::borrow::{Borrow, BorrowMut};
use gl;
use gl::types::*;
use context::ContextOf;
use framebuffer::FramebufferBinding;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl<AB, EAB, P, FB, RB, TU> ContextOf<AB, EAB, P, FB, RB, TU> {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = 0;

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }

    pub fn bind_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ArrayBufferBinding<'a>,
            ContextOf<(), EAB, P, FB, RB, TU>
        )
        where AB: BorrowMut<ArrayBufferBinder>
    {
        let (mut array_buffer, gl) = self.split_array_buffer();
        (array_buffer.borrow_mut().bind(buffer), gl)
    }

    pub fn bind_element_array_buffer<'a>(self, buffer: &'a mut Buffer)
        -> (
            ElementArrayBufferBinding<'a>,
            ContextOf<AB, (), P, FB, RB, TU>
        )
        where EAB: BorrowMut<ElementArrayBufferBinder>
    {
        let (mut element_array_buffer, gl) = self.split_element_array_buffer();
        (element_array_buffer.borrow_mut().bind(buffer), gl)
    }
}

gl_enum! {
    pub gl_enum BufferDataUsage {
        StreamDraw as STREAM_DRAW = gl::STREAM_DRAW,
        StaticDraw as STATIC_DRAW = gl::STATIC_DRAW,
        DynamicDraw as DYNAMIC_DRAW = gl::DYNAMIC_DRAW
    }
}

gl_enum! {
    pub gl_enum BufferBindingTarget {
        ArrayBuffer as ARRAY_BUFFER = gl::ARRAY_BUFFER,
        ElementArrayBuffer as ELEMENT_ARRAY_BUFFER = gl::ELEMENT_ARRAY_BUFFER
    }
}

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target().gl_enum(),
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage.gl_enum());
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indices: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode.gl_enum(),
                     count as GLsizei,
                     gl_index_type,
                     indices);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type.gl_enum(),
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }
}

impl<'a> FramebufferBinding<'a> {
    pub unsafe fn draw_arrays_range(&mut self,
                                    _ab: &ArrayBufferBinding,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode.gl_enum(), first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&mut self,
                                           _ab: &ArrayBufferBinding,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&mut self,
                                     _ab: &ArrayBufferBinding,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indices.len());

        let ptr = indices.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&mut self,
                                   _ab: &ArrayBufferBinding,
                                   mode: DrawingMode,
                                   indices: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(_ab, mode, indices.len(), indices);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    unsafe {
        gl::BindBuffer(target as GLuint, buffer.gl_id());
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`target` is not an allowed value",
            _ => "Unknown error"
        }
    }
}

pub struct BufferBinderOf<A, E> {
    array: A,
    element_array: E
}

pub type BufferBinder = BufferBinderOf<ArrayBufferBinder,
                                       ElementArrayBufferBinder>;

pub type BufferBinderRef<'a> = BufferBinderOf<&'a ArrayBufferBinder,
                                              &'a ElementArrayBufferBinder>;

pub type BufferBinderMut<'a> = BufferBinderOf<&'a mut ArrayBufferBinder,
                                              &'a mut ElementArrayBufferBinder>;

impl<A, E> BufferBinderOf<A, E> {
    pub unsafe fn current() -> BufferBinder {
        BufferBinderOf {
            array: ArrayBufferBinder,
            element_array: ElementArrayBufferBinder
        }
    }

    pub fn borrowed<'a, BA = A, BE = E>(&'a self)
        -> BufferBinderOf<&'a BA, &'a BE>
        where A: Borrow<BA>,
              E: Borrow<BE>
    {
        BufferBinderOf {
            array: self.array.borrow(),
            element_array: self.element_array.borrow()
        }
    }

    pub fn borrowed_mut<'a, BA = A, BE = E>(&'a mut self)
        -> BufferBinderOf<&'a mut BA, &'a mut BE>
        where A: BorrowMut<BA>,
              E: BorrowMut<BE>
    {
        BufferBinderOf {
            array: self.array.borrow_mut(),
            element_array: self.element_array.borrow_mut()
        }
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer) -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&mut self, buffer: &'a mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        _bind_buffer(binding.target(), buffer);
        binding
    }
}
<|endoftext|>


<commit_before>use config::ServerConfig;
use util::{FormatBytes, FormatTime, precise_time_ms};

use std::borrow::ToOwned;
use std::fmt;
use std::io::{BufferedReader, File, IoResult};
use std::io::process::{Command, Process};
use std::io::pipe::PipeStream;
use std::sync::mpsc::{sync_channel, Receiver};
use std::thread::Thread;

pub const STOP_TIMEOUT: Option<u64> = Some(10000);

pub struct Server {
   process: Process,
   config: ServerConfig,
   lines: Receiver<String>,
   log: Vec<String>,
}

impl Server {
    pub fn spawn(config: ServerConfig) -> IoResult<Server> {
        let ref dir = Path::new(&*config.dir);
        let mut command = Command::new(&*config.command);

        for arg in config.args.iter() {
            command.arg(arg);
        }

        command.cwd(dir);

        println!("Starting process: {}", command);

        let process = try!(command.spawn());

        let lines = read_lines_threaded(process.stdout.clone().unwrap());

        Ok(Server {
            process: process,
            config: config,
            lines: lines,
            log: Vec::new(),
        })
    }

    pub fn is_alive(&mut self) -> bool {
        self.process.signal(0).is_ok()
    }

    pub fn pid(&self) -> i32 {
        self.process.id()
    }

    pub fn write_status(&mut self, w: &mut Writer) -> IoResult<()> {
        if self.is_alive() {
            writeln!(w, "Status: Running [{}]", try!(ServerInfo::for_process(self.pid())))
        } else {
            w.write_line("Status: Stopped")
        }
    }

    pub fn stop(&mut self) -> IoResult<ExitStatus> {
        if !self.is_alive() {
            return Ok(ExitStatus::AlreadyStopped);
        }

        self.process.set_timeout(self.config.stop_timeout.or(STOP_TIMEOUT));

        if !self.config.on_stop.is_empty() {
            // Asking the server to stop with the given command

            for command in self.config.on_stop.clone().into_iter() {
                try!(self.send_command(&*command));
            }

            if let Ok(_) = self.process.wait() {
                return Ok(ExitStatus::Stopped);
            }
        }

        // Tell the server to please stop now with SIGTERM
        try!(self.process.signal_exit());
        if let Ok(_) = self.process.wait() {
            return Ok(ExitStatus::Terminated);
        }

        // Forcibly kill the server
        try!(self.process.signal_kill());
        self.process.wait().map(|_| ExitStatus::Killed)
    }

    pub fn send_command(&mut self, command: &str) -> IoResult<()> {
        let stdin = self.process.stdin.as_mut().unwrap();
        stdin.write_line(command).and_then(|_| stdin.flush())
    }

    pub fn read_line(&mut self, timeout_ms: u64) -> Option<String> {
        let start = precise_time_ms();

        while (precise_time_ms() - start) < timeout_ms {
            if let Ok(line) = self.lines.try_recv() {
                return Some(line);
            }
        }

        None
    }

    pub fn tail(&mut self, lines: usize) -> &[String] {
        while let Some(line) = self.read_line(100) {
            self.log.push(line);
        }

        truncate_back(&mut self.log, 80);

        let offset = if lines > self.log.len() {
            0
        } else {
            self.log.len() - lines
        };

        &self.log[offset..]
    }

    pub fn auto_restart(&self) -> bool {
        self.config.auto_restart.unwrap_or(false)
    }
}

pub enum ExitStatus {
    Stopped,
    Terminated,
    Killed,
    AlreadyStopped,
}

impl fmt::String for ExitStatus {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt.pad(match *self {
            ExitStatus::Stopped => "Stopped gently (used configured stop command)",
            ExitStatus::Terminated => "Terminated normally (no stop command or timed out)",
            ExitStatus::Killed => "Killed forcibly (server stopped responding)",
            ExitStatus::AlreadyStopped => "Server was already stopped!",
        })
    }
}

pub struct ServerInfo {
    pub pid: i32,
    pub percent_cpu: f32,
    pub memory_usage: u64,
    pub uptime: u64,
}

impl ServerInfo {
    fn for_process(pid: i32) -> IoResult<ServerInfo> {
        fn ticks_per_second() -> u64 {
            use libc::sysconf;
            use libc::consts::os::sysconf::_SC_CLK_TCK;

            unsafe { sysconf(_SC_CLK_TCK) as u64 }
        }

        fn ticks_to_s(ticks: u64) -> u64 {
            ticks / ticks_per_second()
        }

        let ref proc_uptime_path = Path::new("/proc/uptime");
        let proc_uptime = try!(File::open(proc_uptime_path).read_to_string());
        let uptime = proc_uptime.words().next().and_then(|s| s.parse::<f64>()).unwrap() as u64;

        let ref proc_stat_path = Path::new(format!("/proc/{}/stat", pid));
        let proc_stat = try!(File::open(proc_stat_path).read_to_string());

        // Indexes into `columns` taken from the man page for /proc/[pid]/stat
        // Mind that the man page starts the indexes from 1 but these start from 0
        let columns: Vec<_> = proc_stat.words().map(ToOwned::to_owned).collect();

        // Get kernel time and user time
        let cputime_ticks: u64 = columns[13].parse::<u64>().unwrap() + columns[14].parse().unwrap();
        let cputime = ticks_to_s(cputime_ticks);

        let start_time = ticks_to_s(columns[21].parse().unwrap());
        let runtime = uptime - start_time;

        let percent_cpu = (cputime as f32) / (runtime as f32);

        Ok(ServerInfo {
            pid: pid,
            percent_cpu: percent_cpu,
            memory_usage: columns[23].parse().unwrap(),
            uptime: runtime,
        })
    }
}

impl fmt::String for ServerInfo {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt.write_fmt(
            format_args!(
                "PID: {} Avg CPU: {:.02}% Memory: {} Uptime: {}",
                self.pid,
                self.percent_cpu,
                FormatBytes(self.memory_usage),
                FormatTime::from_s(self.uptime)
            )
        )
    }
}

const MAX_LINES: usize = 80;

fn read_lines_threaded(stream: PipeStream) -> Receiver<String> {
    let (tx, rx) = sync_channel(MAX_LINES);

    Thread::spawn(move || {
        let mut reader = BufferedReader::new(stream);
        for line in reader.lines() {
            let line = line.unwrap();

            if !line.trim().is_empty() {
                tx.send(line).unwrap();
            }
        }
    });

    rx
}

fn truncate_back<T>(vec: &mut Vec<T>, len: usize) {
    let offset = if vec.len() > len {
        vec.len() - len
    } else {
        return;
    };

    let ptr = vec[offset..].as_ptr();
    unsafe {
        vec.set_len(offset);
        *vec = Vec::from_raw_buf(ptr, len);
    }
}
<commit_msg>Fix server info<commit_after>use config::ServerConfig;
use util::{FormatBytes, FormatTime, precise_time_ms};

use std::borrow::ToOwned;
use std::fmt;
use std::io::{BufferedReader, File, IoResult};
use std::io::process::{Command, Process};
use std::io::pipe::PipeStream;
use std::os;
use std::sync::mpsc::{sync_channel, Receiver};
use std::thread::Thread;

pub const STOP_TIMEOUT: Option<u64> = Some(10000);

pub struct Server {
   process: Process,
   config: ServerConfig,
   lines: Receiver<String>,
   log: Vec<String>,
}

impl Server {
    pub fn spawn(config: ServerConfig) -> IoResult<Server> {
        let ref dir = Path::new(&*config.dir);
        let mut command = Command::new(&*config.command);

        for arg in config.args.iter() {
            command.arg(arg);
        }

        command.cwd(dir);

        println!("Starting process: {}", command);

        let process = try!(command.spawn());

        let lines = read_lines_threaded(process.stdout.clone().unwrap());

        Ok(Server {
            process: process,
            config: config,
            lines: lines,
            log: Vec::new(),
        })
    }

    pub fn is_alive(&mut self) -> bool {
        self.process.signal(0).is_ok()
    }

    pub fn pid(&self) -> i32 {
        self.process.id()
    }

    pub fn write_status(&mut self, w: &mut Writer) -> IoResult<()> {
        if self.is_alive() {
            writeln!(w, "Status: Running [{}]", try!(ServerInfo::for_process(self.pid())))
        } else {
            w.write_line("Status: Stopped")
        }
    }

    pub fn stop(&mut self) -> IoResult<ExitStatus> {
        if !self.is_alive() {
            return Ok(ExitStatus::AlreadyStopped);
        }

        self.process.set_timeout(self.config.stop_timeout.or(STOP_TIMEOUT));

        if !self.config.on_stop.is_empty() {
            // Asking the server to stop with the given command

            for command in self.config.on_stop.clone().into_iter() {
                try!(self.send_command(&*command));
            }

            if let Ok(_) = self.process.wait() {
                return Ok(ExitStatus::Stopped);
            }
        }

        // Tell the server to please stop now with SIGTERM
        try!(self.process.signal_exit());
        if let Ok(_) = self.process.wait() {
            return Ok(ExitStatus::Terminated);
        }

        // Forcibly kill the server
        try!(self.process.signal_kill());
        self.process.wait().map(|_| ExitStatus::Killed)
    }

    pub fn send_command(&mut self, command: &str) -> IoResult<()> {
        let stdin = self.process.stdin.as_mut().unwrap();
        stdin.write_line(command).and_then(|_| stdin.flush())
    }

    pub fn read_line(&mut self, timeout_ms: u64) -> Option<String> {
        let start = precise_time_ms();

        while (precise_time_ms() - start) < timeout_ms {
            if let Ok(line) = self.lines.try_recv() {
                return Some(line);
            }
        }

        None
    }

    pub fn tail(&mut self, lines: usize) -> &[String] {
        while let Some(line) = self.read_line(100) {
            self.log.push(line);
        }

        truncate_back(&mut self.log, 80);

        let offset = if lines > self.log.len() {
            0
        } else {
            self.log.len() - lines
        };

        &self.log[offset..]
    }

    pub fn auto_restart(&self) -> bool {
        self.config.auto_restart.unwrap_or(false)
    }
}

pub enum ExitStatus {
    Stopped,
    Terminated,
    Killed,
    AlreadyStopped,
}

impl fmt::String for ExitStatus {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt.pad(match *self {
            ExitStatus::Stopped => "Stopped gently (used configured stop command)",
            ExitStatus::Terminated => "Terminated normally (no stop command or timed out)",
            ExitStatus::Killed => "Killed forcibly (server stopped responding)",
            ExitStatus::AlreadyStopped => "Server was already stopped!",
        })
    }
}

pub struct ServerInfo {
    pub pid: i32,
    pub percent_cpu: f32,
    pub memory_usage: usize,
    pub uptime: u64,
}

impl ServerInfo {
    fn for_process(pid: i32) -> IoResult<ServerInfo> {
        use libc::sysconf;

        fn ticks_per_second() -> u64 {
            use libc::consts::os::sysconf::_SC_CLK_TCK;

            unsafe { sysconf(_SC_CLK_TCK) as u64 }
        }

        fn ticks_to_s(ticks: u64) -> u64 {
            ticks / ticks_per_second()
        }

        let ref proc_uptime_path = Path::new("/proc/uptime");
        let proc_uptime = try!(File::open(proc_uptime_path).read_to_string());
        let uptime = proc_uptime.words().next().and_then(|s| s.parse::<f64>()).unwrap() as u64;

        let ref proc_stat_path = Path::new(format!("/proc/{}/stat", pid));
        let proc_stat = try!(File::open(proc_stat_path).read_to_string());

        // Indexes into `columns` taken from the man page for /proc/[pid]/stat
        // Mind that the man page starts the indexes from 1 but these start from 0
        let columns: Vec<_> = proc_stat.words().map(ToOwned::to_owned).collect();

        // Get kernel time and user time
        let cputime_ticks: u64 = columns[13].parse::<u64>().unwrap() + columns[14].parse().unwrap();
        let cputime = ticks_to_s(cputime_ticks);

        let start_time = ticks_to_s(columns[21].parse().unwrap());

        let runtime = uptime - start_time;

        Ok(ServerInfo {
            pid: pid,
            percent_cpu: ticks_to_s(cputime_ticks * 100) as f32 / runtime as f32,
            memory_usage: columns[23].parse::<usize>().unwrap() * os::page_size(),
            uptime: runtime,
        })
    }
}

impl fmt::String for ServerInfo {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt.write_fmt(
            format_args!(
                "PID: {} Avg CPU: {:.02}% Memory: {} Uptime: {}",
                self.pid,
                self.percent_cpu,
                FormatBytes(self.memory_usage as u64),
                FormatTime::from_s(self.uptime)
            )
        )
    }
}

const MAX_LINES: usize = 80;

fn read_lines_threaded(stream: PipeStream) -> Receiver<String> {
    let (tx, rx) = sync_channel(MAX_LINES);

    Thread::spawn(move || {
        let mut reader = BufferedReader::new(stream);
        for line in reader.lines() {
            let line = line.unwrap();

            if !line.trim().is_empty() {
                tx.send(line).unwrap();
            }
        }
    });

    rx
}

fn truncate_back<T>(vec: &mut Vec<T>, len: usize) {
    let offset = if vec.len() > len {
        vec.len() - len
    } else {
        return;
    };

    let ptr = vec[offset..].as_ptr();
    unsafe {
        vec.set_len(offset);
        *vec = Vec::from_raw_buf(ptr, len);
    }
}
<|endoftext|>


<commit_before>use std::os::unix::process::CommandExt;
use std::process::Command;

const SYSTEMD_RUN: &'static str = "/usr/bin/systemd-run";
const FIREJAIL: &'static str = "/usr/bin/firejail";

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_PROFILE: &'static str = "/etc/firejail/firefox.profile";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const KEIRA: &'static str = "/home/kalvin/Downloads/.firefox-nightly/firefox";
const KEIRA_PROFILE: &'static str = "/etc/firejail/firefox-nightly.profile";

const TERM: &'static str = "/usr/bin/alacritty";
const TERM_PROFILE: &'static str = "/etc/firejail/x-terminal-emulator.profile";

const THUNDERBIRD: &'static str = "/home/kalvin/Downloads/.thunderbird-beta/thunderbird";
const THUNDERBIRD_PROFILE: &'static str = "/etc/firejail/thunderbird-beta.profile";

#[derive(Debug)]
struct CgroupedFirejailedCommandOptions<'a> {
    bin_path: &'a str,
    memory_high: Option<i32>,
    memory_max: Option<i32>,
    firejail_profile: &'a str,
    implicit_extra_args: Option<&'a [&'a str]>,
    argv_remainder: std::env::Args,
}

fn cgrouped_firejail_command(options: CgroupedFirejailedCommandOptions) -> Command {
    let mut command = Command::new(SYSTEMD_RUN);
    command.args(&["--user", "--scope"]);
    command.args(&["-p", "MemorySwapMax=0"]);

    if let Some(memory_high) = options.memory_high {
        let memory_high_owned_string = format!("MemoryHigh={}M", memory_high);
        command.args(&["-p", memory_high_owned_string.as_str()]);
    }
    if let Some(memory_max) = options.memory_max {
        let memory_max_owned_string = format!("MemoryMax={}M", memory_max);
        command.args(&["-p", memory_max_owned_string.as_str()]);
    }

    command.arg(FIREJAIL);
    command.arg(format!("--profile={}", options.firejail_profile));
    command.arg(options.bin_path);

    if let Some(implicit_extra_args) = options.implicit_extra_args {
        command.args(implicit_extra_args);
    }

    let argv_remainder: Vec<String> = options.argv_remainder.collect();
    command.args(argv_remainder);

    command
}

fn simple_firejail_command(target: &str, args: std::env::Args) -> Command {
    let mut command = Command::new(FIREJAIL);

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));

    let argv_remainder: Vec<String> = args.collect();
    command.args(argv_remainder);

    command
}

fn init_command() -> Command {
    let mut args = std::env::args();
    args.next();

    let target = args.next().unwrap();
    match target.as_str() {
        "ff" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: FIREFOX,
                memory_high: Some(4420),
                memory_max: Some(5200),
                firejail_profile: FIREFOX_PROFILE,
                implicit_extra_args: Some(&["-P", FIREFOX_MOZILLA_SFW_PROFILE]),
                argv_remainder: args,
            })
        }
        "keira" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: KEIRA,
                memory_high: Some(4420),
                memory_max: Some(5200),
                firejail_profile: KEIRA_PROFILE,
                implicit_extra_args: Some(&["-P", "nightly"]),
                argv_remainder: args,
            })
        }
        "npv" => return simple_firejail_command("mpv", args),
        "t" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: TERM,
                memory_high: None,
                memory_max: None,
                firejail_profile: TERM_PROFILE,
                implicit_extra_args: None,
                argv_remainder: args,
            })
        }
        "tbb" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: THUNDERBIRD,
                memory_high: None,
                memory_max: None,
                firejail_profile: THUNDERBIRD_PROFILE,
                implicit_extra_args: None,
                argv_remainder: args,
            })
        }
        "vlk" => return simple_firejail_command("vlc", args),
        "z" => return simple_firejail_command("zathura", args),
        _ => panic!(format!("no handler for ``{}''", target)),
    }
}

fn main() {
    let mut command = init_command();
    println!("{:#?}", command);
    command.exec();
}
<commit_msg>unner: drop firejail usage<commit_after>use std::os::unix::process::CommandExt;
use std::process::Command;

const SYSTEMD_RUN: &'static str = "/usr/bin/systemd-run";
const FIREJAIL: &'static str = "/usr/bin/firejail";

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_PROFILE: &'static str = "/etc/firejail/firefox.profile";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const KEIRA: &'static str = "/home/kalvin/Downloads/.firefox-nightly/firefox";
const KEIRA_PROFILE: &'static str = "/etc/firejail/firefox-nightly.profile";

const TERM: &'static str = "/usr/bin/alacritty";
const TERM_PROFILE: &'static str = "/etc/firejail/x-terminal-emulator.profile";

const THUNDERBIRD: &'static str = "/home/kalvin/Downloads/.thunderbird-beta/thunderbird";
const THUNDERBIRD_PROFILE: &'static str = "/etc/firejail/thunderbird-beta.profile";

#[derive(Debug)]
struct CgroupedFirejailedCommandOptions<'a> {
    bin_path: &'a str,
    memory_high: Option<i32>,
    memory_max: Option<i32>,
    firejail_profile: Option<&'a str>,
    implicit_extra_args: Option<&'a [&'a str]>,
    argv_remainder: std::env::Args,
}

fn cgrouped_firejail_command(options: CgroupedFirejailedCommandOptions) -> Command {
    let mut command = Command::new(SYSTEMD_RUN);
    command.args(&["--user", "--scope"]);
    command.args(&["-p", "MemorySwapMax=0"]);

    if let Some(memory_high) = options.memory_high {
        let memory_high_owned_string = format!("MemoryHigh={}M", memory_high);
        command.args(&["-p", memory_high_owned_string.as_str()]);
    }
    if let Some(memory_max) = options.memory_max {
        let memory_max_owned_string = format!("MemoryMax={}M", memory_max);
        command.args(&["-p", memory_max_owned_string.as_str()]);
    }

    if let Some(firejail_profile) = options.firejail_profile {
        command.arg(FIREJAIL);
        command.arg(format!("--profile={}", firejail_profile));
    }

    command.arg(options.bin_path);

    if let Some(implicit_extra_args) = options.implicit_extra_args {
        command.args(implicit_extra_args);
    }

    let argv_remainder: Vec<String> = options.argv_remainder.collect();
    command.args(argv_remainder);

    command
}

fn simple_firejail_command(target: &str, args: std::env::Args) -> Command {
    let mut command = Command::new(FIREJAIL);

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));

    let argv_remainder: Vec<String> = args.collect();
    command.args(argv_remainder);

    command
}

fn init_command() -> Command {
    let mut args = std::env::args();
    args.next();

    let target = args.next().unwrap();
    match target.as_str() {
        "ff" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: FIREFOX,
                memory_high: Some(4420),
                memory_max: Some(5200),
                firejail_profile: None, //FIREFOX_PROFILE,
                implicit_extra_args: Some(&["-P", FIREFOX_MOZILLA_SFW_PROFILE]),
                argv_remainder: args,
            });
        }
        "keira" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: KEIRA,
                memory_high: Some(4420),
                memory_max: Some(5200),
                firejail_profile: None, //KEIRA_PROFILE,
                implicit_extra_args: Some(&["-P", "nightly"]),
                argv_remainder: args,
            });
        }
        "npv" => return simple_firejail_command("mpv", args),
        "t" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: TERM,
                memory_high: None,
                memory_max: None,
                firejail_profile: Some(TERM_PROFILE),
                implicit_extra_args: None,
                argv_remainder: args,
            })
        }
        "tbb" => {
            return cgrouped_firejail_command(CgroupedFirejailedCommandOptions {
                bin_path: THUNDERBIRD,
                memory_high: None,
                memory_max: None,
                firejail_profile: None, //THUNDERBIRD_PROFILE,
                implicit_extra_args: None,
                argv_remainder: args,
            });
        }
        "vlk" => return simple_firejail_command("vlc", args),
        "z" => return simple_firejail_command("zathura", args),
        _ => panic!(format!("no handler for ``{}''", target)),
    }
}

fn main() {
    let mut command = init_command();
    println!("{:#?}", command);
    command.exec();
}
<|endoftext|>


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.2

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io};
use extra::arc;
use std::comm::*;

static PORT:    int = 4414;
static IP: &'static str = "0.0.0.0";
static mut visitor_count: uint = 0;

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath
}

fn main() {
    let req_vec: ~[sched_msg] = ~[];
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // add file requests into queue.
    do spawn {
        loop {
            do add_vec.write |vec| {
                // port.recv() will block the code and keep locking the RWArc, so we simply use peek() to check if there's message to recv.
                // But a asynchronous solution will be much better.
                if (port.peek()) {
                    let tf:sched_msg = port.recv();
                    (*vec).push(tf);
                    println(fmt!("add to queue, size: %ud", (*vec).len()));
                }
            }
        }
    }

    // take file requests from queue, and send a response.
    // FIFO
    do spawn {
        loop {
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {
                    // FILO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().
                    let tf_opt: Option<sched_msg> = (*vec).shift_opt();
                    let mut tf = tf_opt.unwrap();
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));

                    match io::read_whole_file(tf.filepath) { // killed if file size is larger than memory size.
                        Ok(file_data) => {
                            println(fmt!("begin serving file [%?]", tf.filepath));
                            // A web server should always reply a HTTP header for any legal HTTP request.
                            tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n".as_bytes());
                            tf.stream.write(file_data);
                            println(fmt!("finish file [%?]", tf.filepath));
                        }
                        Err(err) => {
                            println(err);
                        }
                    }
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on tcp port %d ...", PORT));
    let mut acceptor = socket.listen().unwrap();

    // we can limit the incoming connection count.
    //for stream in acceptor.incoming().take(10 as uint) {
    for stream in acceptor.incoming() {
        let stream = Cell::new(stream);

        // Start a new task to handle the connection
        let child_chan = chan.clone();
        do spawn {
            unsafe {
                visitor_count += 1;
            }

            let mut stream = stream.take();
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));

                let file_path = ~os::getcwd().push(path.replace("/../", ""));
                if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                    println(fmt!("Request received:\n%s", request_str));
                    let response: ~str = fmt!(
                        "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                         <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                         \r\n", unsafe{visitor_count});

                    stream.write(response.as_bytes());
                }
                else {
                    // may do scheduling here
                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone()};
                    child_chan.send(msg);

                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates")
        }
    }
}
<commit_msg>Updated to 0.3.<commit_after>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io};
use extra::arc;
use std::comm::*;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";
static mut visitor_count: uint = 0;

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath
}

fn main() {
    let req_vec: ~[sched_msg] = ~[];
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle
                match io::read_whole_file(tf.filepath) { // killed if file size is larger than memory size.
                    Ok(file_data) => {
                        println(fmt!("begin serving file [%?]", tf.filepath));
                        // A web server should always reply a HTTP header for any legal HTTP request.
                        tf.stream.write("HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n".as_bytes());
                        tf.stream.write(file_data);
                        println(fmt!("finish file [%?]", tf.filepath));
                    }
                    Err(err) => {
                        println(err);
                    }
                }
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {
                    // LIFO didn't make sense in service scheduling, so we modify it as FIFO by using shift_opt() rather than pop().
                    let tf_opt: Option<sched_msg> = (*vec).shift_opt();
                    let tf = tf_opt.unwrap();
                    println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    for stream in acceptor.incoming() {
        let stream = Cell::new(stream);

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let child_add_vec = add_vec.clone();
        do spawn {
            unsafe {
                visitor_count += 1;
            }

            let mut stream = stream.take();
            let mut buf = [0, ..500];
            stream.read(buf);
            let request_str = str::from_utf8(buf);

            let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
            if req_group.len() > 2 {
                let path = req_group[1];
                println(fmt!("Request for path: \n%?", path));

                let file_path = ~os::getcwd().push(path.replace("/../", ""));
                if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                    println(fmt!("Request received:\n%s", request_str));
                    let response: ~str = fmt!(
                        "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                         <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                         \r\n", unsafe{visitor_count});

                    stream.write(response.as_bytes());
                }
                else {
                    // Requests scheduling
                    let msg: sched_msg = sched_msg{stream: stream, filepath: file_path.clone()};
                    let (sm_port, sm_chan) = std::comm::stream();
                    sm_chan.send(msg);

                    do child_add_vec.write |vec| {
                        let msg = sm_port.recv();
                        (*vec).push(msg); // enqueue new request.
                        println("add to queue");
                    }
                    child_chan.send(""); //notify the new arriving request.
                    println(fmt!("get file request: %?", file_path));
                }
            }
            println!("connection terminates")
        }
    }
}
<|endoftext|>


<commit_before>/*
 * Architecture specific stuff.
 * For now arch is assumed to be x86_32
 */

use dbgprint;

const X86_EFLAGS_IF_BIT: usize = 9;
const X86_EFLAGS_IF: u32 = (1u32 << X86_EFLAGS_IF_BIT);

pub fn read_eflags() -> u32 {
    let mut eflags: u32 = 0;
    unsafe {
        asm!("pushf");
        asm!("pop %eax" : "={eax}"(eflags));
    }

    return eflags;
}

/* Interrupts */

pub fn interrupts_enabled() -> bool {
    (read_eflags() & X86_EFLAGS_IF) != 0
}

pub fn interrupts_enable() {
    unsafe { asm!("sti"); }
}

pub fn interrupts_disable() -> bool {
    let iflag = interrupts_enabled();
    unsafe { asm!("cli"); }
    return iflag;
}

pub fn interrupts_enable_if(iflag: bool) {
    if iflag {
        interrupts_enable();
    }
}

struct InterruptGuard {
    iflag: bool,
}

impl Default for InterruptGuard {
    fn default() -> InterruptGuard {
        InterruptGuard {
            iflag: interrupts_disable(),
        }
    }
}

impl Drop for InterruptGuard {
    fn drop(&mut self) {
        interrupts_enable_if(self.iflag);
    }
}

/* IDT */

#[derive(Default, Copy, Clone)]
#[repr(C, packed)]
struct IDTR {
    limit: u16,
    base: u32,
}

#[derive(Default, Copy, Clone)]
#[repr(C, packed)]
struct IDTDescriptor {
    offset_low: u16,
    selector: u16,
    _unused: u8,
    attr: u8,
    offset_high: u16,
}

#[derive(Default, Copy, Clone)]
#[repr(C, packed)]
struct ExceptionFrame {
    eip: u32,
    _pad1: u16,
    cs: u16,
    eflags: u32,
    esp: u32,
    _pad2: u16,
    ss: u16,
}

/* That's our global IDT */
static mut IDT: [IDTDescriptor; 256] = [IDTDescriptor {
    offset_low: 0,
    selector: 0,
    _unused: 0,
    attr: 0,
    offset_high: 0
}; 256];

fn get_code_selector() -> u16 {
    let mut cs_val: u16 = 0;
    unsafe {
        asm!("mov ax, cs" :"={ax}"(cs_val):::"intel", "volatile");
    }

    cs_val & !0x7 // Clear CPL and TI bits if any
}

pub fn set_interrupt_handler(vec: i8, handler: extern "C" fn() -> !) {
    let iflag = InterruptGuard::default();
    let addr: u32 = handler as u32;

    unsafe {
        let desc: &mut IDTDescriptor = &mut IDT[vec as usize];
        desc.offset_low = addr as u16;
        desc.offset_high = (addr >> 16) as u16;
        desc.selector = get_code_selector();
        desc.attr = 0x8E; // 32-bit interrupt gate present
    }
}

pub fn clear_interrupt_handler(vec: i8) {
    let iflag = InterruptGuard::default();

    unsafe {
        let desc: &mut IDTDescriptor = &mut IDT[vec as usize];
        desc.offset_low = 0;
        desc.offset_high = 0;
        desc.selector = 0;
        desc.attr = 0;
    }
}

/**
 * Register function as an exception handler:
 * exception_handler!(0x3, my_handler)
 */
macro_rules! exception_handler {
    ($vec:expr, $name:ident) => {{
        #[naked]
        extern "C" fn exception_handler() -> ! {
            unsafe {
                asm!("
                  push eax
                  push ecx
                  push edx

                  cmp  $1, 8
                  jb   .no_code
                  je   .has_code
                  cmp  $1, 10
                  jb   .no_code
                  cmp  $1, 15
                  jb   .has_code
                  cmp  $1, 17
                  je   .has_code
                  cmp  $1, 30
                  je   .has_code
                .no_code:
                  push  0
                .has_code:
                  push  [esp + 12]

                  push  esp + 16
                  push  $1
                  call  $0
                  add   esp, 122
                  pop  edx
                  pop  ecx
                  pop  eax
                  iret"
                  ::"i"($name as extern "C" fn(u8, *const ExceptionFrame, u32)), "i"($vec as u8) :: "intel");
                ::core::intrinsics::unreachable();
            }
        }
        set_interrupt_handler($vec, exception_handler)
    }}
}

/**
 * Register function as an interrupt vector handler:
 * interrupt_handler!(0x20, my_handler)
 */
macro_rules! interrupt_handler {
    ($vec:expr, $name:ident) => {{
        #[naked]
        extern "C" fn interrupt_handler() -> ! {
            unsafe {
                asm!("
                  push eax
                  push ecx
                  push edx
                  push $1
                  call $0
                  add  esp, 4
                  pop  edx
                  pop  ecx
                  pop  eax
                  iret"
                  :: "i"($name as extern "C" fn(u8)), "i"($vec as u8) :: "intel");
                ::core::intrinsics::unreachable();
            }
        }
        set_interrupt_handler($vec, interrupt_handler)
    }}
}

/*
 * Arch initialization.
 * GDT is already set to flat 32-bit, which is perfectly fine,
 * so we need to initialize IDT only.
 */
#[no_mangle]
pub fn arch_init() {
    unsafe {
        let idtr: IDTR = IDTR {
            limit: 256,
            base: IDT.as_ptr() as u32,
        };

        asm!("lidt [$0]" ::"X"(&idtr as *const IDTR)::"intel", "volatile");
    }
}
<commit_msg>test: fixed a typo in exception handler<commit_after>/*
 * Architecture specific stuff.
 * For now arch is assumed to be x86_32
 */

use dbgprint;

const X86_EFLAGS_IF_BIT: usize = 9;
const X86_EFLAGS_IF: u32 = (1u32 << X86_EFLAGS_IF_BIT);

pub fn read_eflags() -> u32 {
    let mut eflags: u32 = 0;
    unsafe {
        asm!("pushf");
        asm!("pop %eax" : "={eax}"(eflags));
    }

    return eflags;
}

/* Interrupts */

pub fn interrupts_enabled() -> bool {
    (read_eflags() & X86_EFLAGS_IF) != 0
}

pub fn interrupts_enable() {
    unsafe { asm!("sti"); }
}

pub fn interrupts_disable() -> bool {
    let iflag = interrupts_enabled();
    unsafe { asm!("cli"); }
    return iflag;
}

pub fn interrupts_enable_if(iflag: bool) {
    if iflag {
        interrupts_enable();
    }
}

struct InterruptGuard {
    iflag: bool,
}

impl Default for InterruptGuard {
    fn default() -> InterruptGuard {
        InterruptGuard {
            iflag: interrupts_disable(),
        }
    }
}

impl Drop for InterruptGuard {
    fn drop(&mut self) {
        interrupts_enable_if(self.iflag);
    }
}

/* IDT */

#[derive(Default, Copy, Clone)]
#[repr(C, packed)]
struct IDTR {
    limit: u16,
    base: u32,
}

#[derive(Default, Copy, Clone)]
#[repr(C, packed)]
struct IDTDescriptor {
    offset_low: u16,
    selector: u16,
    _unused: u8,
    attr: u8,
    offset_high: u16,
}

#[derive(Default, Copy, Clone)]
#[repr(C, packed)]
struct ExceptionFrame {
    eip: u32,
    _pad1: u16,
    cs: u16,
    eflags: u32,
    esp: u32,
    _pad2: u16,
    ss: u16,
}

/* That's our global IDT */
static mut IDT: [IDTDescriptor; 256] = [IDTDescriptor {
    offset_low: 0,
    selector: 0,
    _unused: 0,
    attr: 0,
    offset_high: 0
}; 256];

fn get_code_selector() -> u16 {
    let mut cs_val: u16 = 0;
    unsafe {
        asm!("mov ax, cs" :"={ax}"(cs_val):::"intel", "volatile");
    }

    cs_val & !0x7 // Clear CPL and TI bits if any
}

pub fn set_interrupt_handler(vec: i8, handler: extern "C" fn() -> !) {
    let iflag = InterruptGuard::default();
    let addr: u32 = handler as u32;

    unsafe {
        let desc: &mut IDTDescriptor = &mut IDT[vec as usize];
        desc.offset_low = addr as u16;
        desc.offset_high = (addr >> 16) as u16;
        desc.selector = get_code_selector();
        desc.attr = 0x8E; // 32-bit interrupt gate present
    }
}

pub fn clear_interrupt_handler(vec: i8) {
    let iflag = InterruptGuard::default();

    unsafe {
        let desc: &mut IDTDescriptor = &mut IDT[vec as usize];
        desc.offset_low = 0;
        desc.offset_high = 0;
        desc.selector = 0;
        desc.attr = 0;
    }
}

/**
 * Register function as an exception handler:
 * exception_handler!(0x3, my_handler)
 */
macro_rules! exception_handler {
    ($vec:expr, $name:ident) => {{
        #[naked]
        extern "C" fn exception_handler() -> ! {
            unsafe {
                asm!("
                  push eax
                  push ecx
                  push edx

                  cmp  $1, 8
                  jb   .no_code
                  je   .has_code
                  cmp  $1, 10
                  jb   .no_code
                  cmp  $1, 15
                  jb   .has_code
                  cmp  $1, 17
                  je   .has_code
                  cmp  $1, 30
                  je   .has_code
                .no_code:
                  push  0
                .has_code:
                  push  [esp + 12]

                  push  esp + 16
                  push  $1
                  call  $0
                  add   esp, 12
                  pop  edx
                  pop  ecx
                  pop  eax
                  iret"
                  ::"i"($name as extern "C" fn(u8, *const ExceptionFrame, u32)), "i"($vec as u8) :: "intel");
                ::core::intrinsics::unreachable();
            }
        }
        set_interrupt_handler($vec, exception_handler)
    }}
}

/**
 * Register function as an interrupt vector handler:
 * interrupt_handler!(0x20, my_handler)
 */
macro_rules! interrupt_handler {
    ($vec:expr, $name:ident) => {{
        #[naked]
        extern "C" fn interrupt_handler() -> ! {
            unsafe {
                asm!("
                  push eax
                  push ecx
                  push edx
                  push $1
                  call $0
                  add  esp, 4
                  pop  edx
                  pop  ecx
                  pop  eax
                  iret"
                  :: "i"($name as extern "C" fn(u8)), "i"($vec as u8) :: "intel");
                ::core::intrinsics::unreachable();
            }
        }
        set_interrupt_handler($vec, interrupt_handler)
    }}
}

/*
 * Arch initialization.
 * GDT is already set to flat 32-bit, which is perfectly fine,
 * so we need to initialize IDT only.
 */
#[no_mangle]
pub fn arch_init() {
    unsafe {
        let idtr: IDTR = IDTR {
            limit: 256,
            base: IDT.as_ptr() as u32,
        };

        asm!("lidt [$0]" ::"X"(&idtr as *const IDTR)::"intel", "volatile");
    }
}
<|endoftext|>


<commit_before>// Implements AEAD_CHACHA20_POLY1305
// unfortunately, there is no concrete standard yet. some drafts exist:
// http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-01
// http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
// they differ in detail, so here we follow google/boringssl implementation.
// openssl 1.0.2-aead branch seems to implement draft 01.

use crypto::chacha20::ChaCha20;
use crypto::poly1305;
use util::u64_le_vec;
use tls_result::{TlsResult, BadRecordMac};
use super::{Encryptor, Decryptor, Aead};

static KEY_LEN: uint = 256 / 8;
static EXPLICIT_IV_LEN: uint = 0;
static MAC_LEN: uint = 16;

fn compute_mac(poly_key: &[u8], encrypted: &[u8], ad: &[u8]) -> [u8, ..MAC_LEN] {
    let mut msg = Vec::new();

    // follow draft-agl-tls-chacha20poly1305-04: data first, length later
    // note that in draft-agl-tls-chacha20poly1305-01 length is first
    fn push_all_with_len(vec: &mut Vec<u8>, data: &[u8]) {
        vec.push_all(data);
        vec.push_all_move(u64_le_vec(data.len() as u64));
    }

    push_all_with_len(&mut msg, ad);
    push_all_with_len(&mut msg, encrypted);

    let mut r = [0u8, ..MAC_LEN];
    for i in range(0u, MAC_LEN) {
        r[i] = poly_key[i];
    }
    let mut k = [0u8, ..MAC_LEN];
    for i in range(0u, MAC_LEN) {
        k[i] = poly_key[MAC_LEN + i];
    }

    poly1305::authenticate(msg.as_slice(), &r, &k)
}

struct ChaCha20Poly1305Encryptor {
    key: Vec<u8>,
}

impl Encryptor for ChaCha20Poly1305Encryptor {
    fn encrypt(&mut self, nonce: &[u8], data: &[u8], ad: &[u8]) -> Vec<u8> {
        let mut chacha20 = ChaCha20::new(self.key.as_slice(), nonce.as_slice());
        let poly1305_key = chacha20.next();

        let mut encrypted = chacha20.encrypt(data);
        let mac = compute_mac(poly1305_key.as_slice(), encrypted.as_slice(), ad);
        encrypted.push_all(mac.as_slice());

        encrypted
    }
}

struct ChaCha20Poly1305Decryptor {
    key: Vec<u8>,
}

impl Decryptor for ChaCha20Poly1305Decryptor {
    fn decrypt(&mut self, nonce: &[u8], data: &[u8], ad: &[u8]) -> TlsResult<Vec<u8>> {
        let enc_len = data.len();
        if enc_len < MAC_LEN {
            return tls_err!(BadRecordMac, "message too short");
        }

        let encrypted = data.slice_to(enc_len - MAC_LEN);
        let mac_expected = data.slice_from(enc_len - MAC_LEN);

        let mut chacha20 = ChaCha20::new(self.key.as_slice(), nonce.as_slice());
        let poly1305_key = chacha20.next();

        let mac_computed = compute_mac(poly1305_key.as_slice(), encrypted.as_slice(), ad);

        {
            let mut diff = 0u8;
            for i in range(0u, MAC_LEN) {
                diff |= mac_computed[i] ^ mac_expected[i];
            }

            if diff != 0 {
                return tls_err!(BadRecordMac, "wrong mac");
            }
        }

        // SECRET
        let plain = chacha20.encrypt(encrypted);
        Ok(plain)
    }

    #[inline(always)]
    fn mac_len(&self) -> uint {
        MAC_LEN
    }
}

pub struct ChaCha20Poly1305;

impl Aead for ChaCha20Poly1305 {
    #[inline(always)]
    fn key_size(&self) -> uint {
        KEY_LEN
    }

    #[inline(always)]
    fn fixed_iv_len(&self) -> uint {
        EXPLICIT_IV_LEN
    }

    #[inline(always)]
    fn mac_len(&self) -> uint {
        MAC_LEN
    }

    #[inline(always)]
    fn new_encryptor(&self, key: Vec<u8>) -> Box<Encryptor> {
        let encryptor = ChaCha20Poly1305Encryptor {
            key: key,
        };
        box encryptor as Box<Encryptor>
    }

    #[inline(always)]
    fn new_decryptor(&self, key: Vec<u8>) -> Box<Decryptor> {
        let decryptor = ChaCha20Poly1305Decryptor {
            key: key,
        };
        box decryptor as Box<Decryptor>
    }
}
<commit_msg>cipher: Decrypt data even if mac is wrong<commit_after>// Implements AEAD_CHACHA20_POLY1305
// unfortunately, there is no concrete standard yet. some drafts exist:
// http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-01
// http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
// they differ in detail, so here we follow google/boringssl implementation.
// openssl 1.0.2-aead branch seems to implement draft 01.

use crypto::chacha20::ChaCha20;
use crypto::poly1305;
use util::u64_le_vec;
use tls_result::{TlsResult, BadRecordMac};
use super::{Encryptor, Decryptor, Aead};

static KEY_LEN: uint = 256 / 8;
static EXPLICIT_IV_LEN: uint = 0;
static MAC_LEN: uint = 16;

fn compute_mac(poly_key: &[u8], encrypted: &[u8], ad: &[u8]) -> [u8, ..MAC_LEN] {
    let mut msg = Vec::new();

    // follow draft-agl-tls-chacha20poly1305-04: data first, length later
    // note that in draft-agl-tls-chacha20poly1305-01 length is first
    fn push_all_with_len(vec: &mut Vec<u8>, data: &[u8]) {
        vec.push_all(data);
        vec.push_all_move(u64_le_vec(data.len() as u64));
    }

    push_all_with_len(&mut msg, ad);
    push_all_with_len(&mut msg, encrypted);

    let mut r = [0u8, ..MAC_LEN];
    for i in range(0u, MAC_LEN) {
        r[i] = poly_key[i];
    }
    let mut k = [0u8, ..MAC_LEN];
    for i in range(0u, MAC_LEN) {
        k[i] = poly_key[MAC_LEN + i];
    }

    poly1305::authenticate(msg.as_slice(), &r, &k)
}

struct ChaCha20Poly1305Encryptor {
    key: Vec<u8>,
}

impl Encryptor for ChaCha20Poly1305Encryptor {
    fn encrypt(&mut self, nonce: &[u8], data: &[u8], ad: &[u8]) -> Vec<u8> {
        let mut chacha20 = ChaCha20::new(self.key.as_slice(), nonce.as_slice());
        let poly1305_key = chacha20.next();

        let mut encrypted = chacha20.encrypt(data);
        let mac = compute_mac(poly1305_key.as_slice(), encrypted.as_slice(), ad);
        encrypted.push_all(mac.as_slice());

        encrypted
    }
}

struct ChaCha20Poly1305Decryptor {
    key: Vec<u8>,
}

impl Decryptor for ChaCha20Poly1305Decryptor {
    fn decrypt(&mut self, nonce: &[u8], data: &[u8], ad: &[u8]) -> TlsResult<Vec<u8>> {
        let enc_len = data.len();
        if enc_len < MAC_LEN {
            return tls_err!(BadRecordMac, "message too short");
        }

        let encrypted = data.slice_to(enc_len - MAC_LEN);
        let mac_expected = data.slice_from(enc_len - MAC_LEN);

        let mut chacha20 = ChaCha20::new(self.key.as_slice(), nonce.as_slice());
        let poly1305_key = chacha20.next();

        let mac_computed = compute_mac(poly1305_key.as_slice(), encrypted.as_slice(), ad);

        // SECRET
        // even if `mac_computed != mac_expected`, decrypt the data to prevent timing attack.
        let plain = chacha20.encrypt(encrypted);

        let mut diff = 0u8;
        for i in range(0u, MAC_LEN) {
            diff |= mac_computed[i] ^ mac_expected[i];
        }

        if diff != 0 {
            tls_err!(BadRecordMac, "wrong mac")
        } else {
            Ok(plain)
        }
    }

    #[inline(always)]
    fn mac_len(&self) -> uint {
        MAC_LEN
    }
}

pub struct ChaCha20Poly1305;

impl Aead for ChaCha20Poly1305 {
    #[inline(always)]
    fn key_size(&self) -> uint {
        KEY_LEN
    }

    #[inline(always)]
    fn fixed_iv_len(&self) -> uint {
        EXPLICIT_IV_LEN
    }

    #[inline(always)]
    fn mac_len(&self) -> uint {
        MAC_LEN
    }

    #[inline(always)]
    fn new_encryptor(&self, key: Vec<u8>) -> Box<Encryptor> {
        let encryptor = ChaCha20Poly1305Encryptor {
            key: key,
        };
        box encryptor as Box<Encryptor>
    }

    #[inline(always)]
    fn new_decryptor(&self, key: Vec<u8>) -> Box<Decryptor> {
        let decryptor = ChaCha20Poly1305Decryptor {
            key: key,
        };
        box decryptor as Box<Decryptor>
    }
}
<|endoftext|>