(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, token: uint,
51 missile: HomingMissile) -> 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 t: Box<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, token: uint) -> 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 }
librustuv/access.rs:23:1-23:1 -struct- definition:
pub struct Access {
inner: UnsafeArc<Inner>,
}
references:- 893: fn clone(&self) -> Access {
94: Access { inner: self.inner.clone() }
95: }
librustuv/timeout.rs:
28: timer: Option<Box<TimerWatcher>>,
29: pub access: access::Access,
30: }
librustuv/access.rs:32:1-32:1 -struct- definition:
struct Inner {
queue: Vec<(BlockedTask, uint)>,
held: bool,
references:- 624: pub struct Access {
25: inner: UnsafeArc<Inner>,
26: }
--
135: impl Drop for Inner {
136: fn drop(&mut self) {
librustuv/access.rs:27:1-27:1 -struct- definition:
pub struct Guard<'a> {
access: &'a mut Access,
missile: Option<HomingMissile>,
references:- 568: Guard { access: self, missile: Some(missile) }
69: }
--
107: impl<'a> Drop for Guard<'a> {
108: fn drop(&mut self) {
librustuv/timeout.rs:
33: state: &'a mut TimeoutState,
34: pub access: access::Guard<'a>,
35: pub can_timeout: bool,
librustuv/access.rs:
98: impl<'a> Guard<'a> {
99: pub fn is_closed(&self) -> bool {