(index<- )        ./librustuv/access.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  /// An exclusive access primitive
  12  ///
  13  /// This primitive is used to gain exclusive access to read() and write() in uv.
  14  /// It is assumed that all invocations of this struct happen on the same thread
  15  /// (the uv event loop).
  16  
  17  use std::cast;
  18  use std::rt::local::Local;
  19  use std::rt::task::{BlockedTask, Task};
  20  use std::sync::arc::UnsafeArc;
  21  
  22  use homing::HomingMissile;
  23  
  24  pub struct Access {
  25      inner: UnsafeArc<Inner>,
  26  }
  27  
  28  pub struct Guard<'a> {
  29      access: &'a mut Access,
  30      missile: Option<HomingMissile>,
  31  }
  32  
  33  struct Inner {
  34      queue: Vec<(BlockedTask, uint)>,
  35      held: bool,
  36      closed: bool,
  37  }
  38  
  39  impl Access {
  40      pub fn new() -> Access {
  41          Access {
  42              inner: UnsafeArc::new(Inner {
  43                  queue: vec![],
  44                  held: false,
  45                  closed: false,
  46              })
  47          }
  48      }
  49  
  50      pub fn grant<'a>(&'a mut self, tokenuint,
  51                       missileHomingMissile) -> Guard<'a> {
  52          // This unsafety is actually OK because the homing missile argument
  53          // guarantees that we're on the same event loop as all the other objects
  54          // attempting to get access granted.
  55          let inner&mut Inner = unsafe { &mut *self.inner.get() };
  56  
  57          if inner.held {
  58              let tBox<Task> = Local::take();
  59              t.deschedule(1, |task| {
  60                  inner.queue.push((task, token));
  61                  Ok(())
  62              });
  63              assert!(inner.held);
  64          } else {
  65              inner.held = true;
  66          }
  67  
  68          Guard { access: self, missile: Some(missile) }
  69      }
  70  
  71      pub fn close(&self, _missile&HomingMissile) {
  72          // This unsafety is OK because with a homing missile we're guaranteed to
  73          // be the only task looking at the `closed` flag (and are therefore
  74          // allowed to modify it). Additionally, no atomics are necessary because
  75          // everyone's running on the same thread and has already done the
  76          // necessary synchronization to be running on this thread.
  77          unsafe { (*self.inner.get()).closed = true; }
  78      }
  79  
  80      // Dequeue a blocked task with a specified token. This is unsafe because it
  81      // is only safe to invoke while on the home event loop, and there is no
  82      // guarantee that this i being invoked on the home event loop.
  83      pub unsafe fn dequeue(&mut self, tokenuint) -> Option<BlockedTask> {
  84          let inner&mut Inner = &mut *self.inner.get();
  85          match inner.queue.iter().position(|&(_, t)| t == token) {
  86              Some(i) => Some(inner.queue.remove(i).unwrap().val0()),
  87              None => None,
  88          }
  89      }
  90  }
  91  
  92  impl Clone for Access {
  93      fn clone(&self) -> Access {
  94          Access { inner: self.inner.clone() }
  95      }
  96  }
  97  
  98  impl<'a> Guard<'a> {
  99      pub fn is_closed(&self) -> bool {
 100          // See above for why this unsafety is ok, it just applies to the read
 101          // instead of the write.
 102          unsafe { (*self.access.inner.get()).closed }
 103      }
 104  }
 105  
 106  #[unsafe_destructor]
 107  impl<'a> Drop for Guard<'a> {
 108      fn drop(&mut self) {
 109          // This guard's homing missile is still armed, so we're guaranteed to be
 110          // on the same I/O event loop, so this unsafety should be ok.
 111          assert!(self.missile.is_some());
 112          let inner&mut Inner = unsafe {
 113              cast::transmute(self.access.inner.get())
 114          };
 115  
 116          match inner.queue.shift() {
 117              // Here we have found a task that was waiting for access, and we
 118              // current have the "access lock" we need to relinquish access to
 119              // this sleeping task.
 120              //
 121              // To do so, we first drop out homing missile and we then reawaken
 122              // the task. In reawakening the task, it will be immediately
 123              // scheduled on this scheduler. Because we might be woken up on some
 124              // other scheduler, we drop our homing missile before we reawaken
 125              // the task.
 126              Some((task, _)) => {
 127                  drop(self.missile.take());
 128                  task.reawaken();
 129              }
 130              None => { inner.held = false; }
 131          }
 132      }
 133  }
 134  
 135  impl Drop for Inner {
 136      fn drop(&mut self) {
 137          assert!(!self.held);
 138          assert_eq!(self.queue.len(), 0);
 139      }
 140  }