(index<- )        ./libstd/unstable/sync.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2013 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  use clone::Clone;
  12  use kinds::Send;
  13  use sync::arc::UnsafeArc;
  14  use unstable::mutex::NativeMutex;
  15  
  16  struct ExData<T> {
  17      lock: NativeMutex,
  18      failed: bool,
  19      data: T,
  20  }
  21  
  22  /**
  23   * An arc over mutable data that is protected by a lock. For library use only.
  24   *
  25   * # Safety note
  26   *
  27   * This uses a pthread mutex, not one that's aware of the userspace scheduler.
  28   * The user of an Exclusive must be careful not to invoke any functions that may
  29   * reschedule the task while holding the lock, or deadlock may result. If you
  30   * need to block or deschedule while accessing shared state, use extra::sync::RWArc.
  31   */
  32  pub struct Exclusive<T> {
  33      x: UnsafeArc<ExData<T>>
  34  }
  35  
  36  impl<T:Send> Clone for Exclusive<T> {
  37      // Duplicate an Exclusive Arc, as std::arc::clone.
  38      fn clone(&self) -> Exclusive<T> {
  39          Exclusive { x: self.x.clone() }
  40      }
  41  }
  42  
  43  impl<T:Send> Exclusive<T> {
  44      pub fn new(user_dataT) -> Exclusive<T> {
  45          let data = ExData {
  46              lock: unsafe {NativeMutex::new()},
  47              failed: false,
  48              data: user_data
  49          };
  50          Exclusive {
  51              x: UnsafeArc::new(data)
  52          }
  53      }
  54  
  55      // Exactly like sync::MutexArc.access(). Same reason for being
  56      // unsafe.
  57      //
  58      // Currently, scheduling operations (i.e., descheduling, receiving on a pipe,
  59      // accessing the provided condition variable) are prohibited while inside
  60      // the Exclusive. Supporting that is a work in progress.
  61      #[inline]
  62      pub unsafe fn with<U>(&self, f|x: &mut T-> U) -> U {
  63          let rec = self.x.get();
  64          let _l = (*rec).lock.lock();
  65          if (*rec).failed {
  66              fail!("Poisoned Exclusive::new - another task failed inside!");
  67          }
  68          (*rec).failed = true;
  69          let result = f(&mut (*rec).data);
  70          (*rec).failed = false;
  71          result
  72      }
  73  
  74      #[inline]
  75      pub unsafe fn with_imm<U>(&self, f|x: &T-> U) -> U {
  76          self.with(|x| f(x))
  77      }
  78  
  79      #[inline]
  80      pub unsafe fn hold_and_signal(&self, f|x: &mut T|) {
  81          let rec = self.x.get();
  82          let guard = (*rec).lock.lock();
  83          if (*rec).failed {
  84              fail!("Poisoned Exclusive::new - another task failed inside!");
  85          }
  86          (*rec).failed = true;
  87          f(&mut (*rec).data);
  88          (*rec).failed = false;
  89          guard.signal();
  90      }
  91  
  92      #[inline]
  93      pub unsafe fn hold_and_wait(&self, f|x: &T-> bool) {
  94          let rec = self.x.get();
  95          let l = (*rec).lock.lock();
  96          if (*rec).failed {
  97              fail!("Poisoned Exclusive::new - another task failed inside!");
  98          }
  99          (*rec).failed = true;
 100          let result = f(&(*rec).data);
 101          (*rec).failed = false;
 102          if result {
 103              l.wait();
 104          }
 105      }
 106  }
 107  
 108  #[cfg(test)]
 109  mod tests {
 110      use option::*;
 111      use prelude::*;
 112      use super::Exclusive;
 113      use task;
 114  
 115      #[test]
 116      fn exclusive_new_arc() {
 117          unsafe {
 118              let mut futures = Vec::new();
 119  
 120              let num_tasks = 10;
 121              let count = 10;
 122  
 123              let total = Exclusive::new(box 0);
 124  
 125              for _ in range(0u, num_tasks) {
 126                  let total = total.clone();
 127                  let (tx, rx) = channel();
 128                  futures.push(rx);
 129  
 130                  task::spawn(proc() {
 131                      for _ in range(0u, count) {
 132                          total.with(|count| **count += 1);
 133                      }
 134                      tx.send(());
 135                  });
 136              };
 137  
 138              for f in futures.mut_iter() { f.recv() }
 139  
 140              total.with(|total| assert!(**total == num_tasks * count));
 141          }
 142      }
 143  
 144      #[test] #[should_fail]
 145      fn exclusive_new_poison() {
 146          unsafe {
 147              // Tests that if one task fails inside of an Exclusive::new, subsequent
 148              // accesses will also fail.
 149              let x = Exclusive::new(1);
 150              let x2 = x.clone();
 151              let _ = task::try(proc() {
 152                  x2.with(|one| assert_eq!(*one, 2))
 153              });
 154              x.with(|one| assert_eq!(*one, 1));
 155          }
 156      }
 157  }