]> git.proxmox.com Git - rustc.git/blame - src/libstd/sync/semaphore.rs
Imported Upstream version 1.8.0+dfsg1
[rustc.git] / src / libstd / sync / semaphore.rs
CommitLineData
1a4d82fc
JJ
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
62682a34 11#![unstable(feature = "semaphore",
85aaf69f 12 reason = "the interaction between semaphores and the acquisition/release \
e9174d1e
SL
13 of resources is currently unclear",
14 issue = "27798")]
9cc50fc6 15#![allow(deprecated)]
1a4d82fc
JJ
16
17use ops::Drop;
18use sync::{Mutex, Condvar};
19
20/// A counting, blocking, semaphore.
21///
22/// Semaphores are a form of atomic counter where access is only granted if the
23/// counter is a positive value. Each acquisition will block the calling thread
24/// until the counter is positive, and each release will increment the counter
25/// and unblock any threads if necessary.
26///
c34b1796 27/// # Examples
1a4d82fc
JJ
28///
29/// ```
c1a9b12d
SL
30/// #![feature(semaphore)]
31///
1a4d82fc
JJ
32/// use std::sync::Semaphore;
33///
34/// // Create a semaphore that represents 5 resources
35/// let sem = Semaphore::new(5);
36///
37/// // Acquire one of the resources
38/// sem.acquire();
39///
40/// // Acquire one of the resources for a limited period of time
41/// {
42/// let _guard = sem.access();
43/// // ...
44/// } // resources is released here
45///
46/// // Release our initially acquired resource
47/// sem.release();
48/// ```
7453a54e
SL
49#[rustc_deprecated(since = "1.7.0",
50 reason = "easily confused with system semaphores and not \
51 used enough to pull its weight")]
52#[unstable(feature = "semaphore",
53 reason = "the interaction between semaphores and the acquisition/release \
54 of resources is currently unclear",
55 issue = "27798")]
1a4d82fc 56pub struct Semaphore {
c34b1796 57 lock: Mutex<isize>,
1a4d82fc
JJ
58 cvar: Condvar,
59}
60
61/// An RAII guard which will release a resource acquired from a semaphore when
62/// dropped.
7453a54e
SL
63#[rustc_deprecated(since = "1.7.0",
64 reason = "easily confused with system semaphores and not \
65 used enough to pull its weight")]
66#[unstable(feature = "semaphore",
67 reason = "the interaction between semaphores and the acquisition/release \
68 of resources is currently unclear",
69 issue = "27798")]
1a4d82fc
JJ
70pub struct SemaphoreGuard<'a> {
71 sem: &'a Semaphore,
72}
73
7453a54e
SL
74#[rustc_deprecated(since = "1.7.0",
75 reason = "easily confused with system semaphores and not \
76 used enough to pull its weight")]
77#[unstable(feature = "semaphore",
78 reason = "the interaction between semaphores and the acquisition/release \
79 of resources is currently unclear",
80 issue = "27798")]
1a4d82fc
JJ
81impl Semaphore {
82 /// Creates a new semaphore with the initial count specified.
83 ///
84 /// The count specified can be thought of as a number of resources, and a
85 /// call to `acquire` or `access` will block until at least one resource is
86 /// available. It is valid to initialize a semaphore with a negative count.
c34b1796 87 pub fn new(count: isize) -> Semaphore {
1a4d82fc
JJ
88 Semaphore {
89 lock: Mutex::new(count),
90 cvar: Condvar::new(),
91 }
92 }
93
94 /// Acquires a resource of this semaphore, blocking the current thread until
95 /// it can do so.
96 ///
97 /// This method will block until the internal count of the semaphore is at
98 /// least 1.
99 pub fn acquire(&self) {
100 let mut count = self.lock.lock().unwrap();
101 while *count <= 0 {
102 count = self.cvar.wait(count).unwrap();
103 }
104 *count -= 1;
105 }
106
107 /// Release a resource from this semaphore.
108 ///
109 /// This will increment the number of resources in this semaphore by 1 and
110 /// will notify any pending waiters in `acquire` or `access` if necessary.
111 pub fn release(&self) {
112 *self.lock.lock().unwrap() += 1;
113 self.cvar.notify_one();
114 }
115
116 /// Acquires a resource of this semaphore, returning an RAII guard to
117 /// release the semaphore when dropped.
118 ///
119 /// This function is semantically equivalent to an `acquire` followed by a
120 /// `release` when the guard returned is dropped.
121 pub fn access(&self) -> SemaphoreGuard {
122 self.acquire();
123 SemaphoreGuard { sem: self }
124 }
125}
126
85aaf69f 127#[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc
JJ
128impl<'a> Drop for SemaphoreGuard<'a> {
129 fn drop(&mut self) {
130 self.sem.release();
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use prelude::v1::*;
137
138 use sync::Arc;
139 use super::Semaphore;
140 use sync::mpsc::channel;
85aaf69f 141 use thread;
1a4d82fc
JJ
142
143 #[test]
144 fn test_sem_acquire_release() {
145 let s = Semaphore::new(1);
146 s.acquire();
147 s.release();
148 s.acquire();
149 }
150
151 #[test]
152 fn test_sem_basic() {
153 let s = Semaphore::new(1);
154 let _g = s.access();
155 }
156
157 #[test]
158 fn test_sem_as_mutex() {
159 let s = Arc::new(Semaphore::new(1));
160 let s2 = s.clone();
85aaf69f 161 let _t = thread::spawn(move|| {
1a4d82fc
JJ
162 let _g = s2.access();
163 });
164 let _g = s.access();
165 }
166
167 #[test]
168 fn test_sem_as_cvar() {
169 /* Child waits and parent signals */
170 let (tx, rx) = channel();
171 let s = Arc::new(Semaphore::new(0));
172 let s2 = s.clone();
85aaf69f 173 let _t = thread::spawn(move|| {
1a4d82fc
JJ
174 s2.acquire();
175 tx.send(()).unwrap();
176 });
177 s.release();
178 let _ = rx.recv();
179
180 /* Parent waits and child signals */
181 let (tx, rx) = channel();
182 let s = Arc::new(Semaphore::new(0));
183 let s2 = s.clone();
85aaf69f 184 let _t = thread::spawn(move|| {
1a4d82fc
JJ
185 s2.release();
186 let _ = rx.recv();
187 });
188 s.acquire();
189 tx.send(()).unwrap();
190 }
191
192 #[test]
193 fn test_sem_multi_resource() {
194 // Parent and child both get in the critical section at the same
195 // time, and shake hands.
196 let s = Arc::new(Semaphore::new(2));
197 let s2 = s.clone();
198 let (tx1, rx1) = channel();
199 let (tx2, rx2) = channel();
85aaf69f 200 let _t = thread::spawn(move|| {
1a4d82fc
JJ
201 let _g = s2.access();
202 let _ = rx2.recv();
203 tx1.send(()).unwrap();
204 });
205 let _g = s.access();
206 tx2.send(()).unwrap();
207 rx1.recv().unwrap();
208 }
209
210 #[test]
211 fn test_sem_runtime_friendly_blocking() {
212 let s = Arc::new(Semaphore::new(1));
213 let s2 = s.clone();
214 let (tx, rx) = channel();
215 {
216 let _g = s.access();
85aaf69f 217 thread::spawn(move|| {
1a4d82fc
JJ
218 tx.send(()).unwrap();
219 drop(s2.access());
220 tx.send(()).unwrap();
221 });
222 rx.recv().unwrap(); // wait for child to come alive
223 }
224 rx.recv().unwrap(); // wait for child to be done
225 }
226}