]> git.proxmox.com Git - rustc.git/blame - src/libstd/sys/unix/condvar.rs
Imported Upstream version 1.0.0~beta
[rustc.git] / src / libstd / sys / unix / condvar.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
c34b1796
AL
11use prelude::v1::*;
12
1a4d82fc
JJ
13use cell::UnsafeCell;
14use libc;
85aaf69f 15use ptr;
1a4d82fc 16use sys::mutex::{self, Mutex};
85aaf69f 17use sys::time;
1a4d82fc
JJ
18use sys::sync as ffi;
19use time::Duration;
85aaf69f 20use num::{Int, NumCast};
1a4d82fc
JJ
21
22pub struct Condvar { inner: UnsafeCell<ffi::pthread_cond_t> }
23
c34b1796
AL
24unsafe impl Send for Condvar {}
25unsafe impl Sync for Condvar {}
26
1a4d82fc
JJ
27pub const CONDVAR_INIT: Condvar = Condvar {
28 inner: UnsafeCell { value: ffi::PTHREAD_COND_INITIALIZER },
29};
30
31impl Condvar {
32 #[inline]
33 pub unsafe fn new() -> Condvar {
34 // Might be moved and address is changing it is better to avoid
35 // initialization of potentially opaque OS data before it landed
36 Condvar { inner: UnsafeCell::new(ffi::PTHREAD_COND_INITIALIZER) }
37 }
38
39 #[inline]
40 pub unsafe fn notify_one(&self) {
41 let r = ffi::pthread_cond_signal(self.inner.get());
42 debug_assert_eq!(r, 0);
43 }
44
45 #[inline]
46 pub unsafe fn notify_all(&self) {
47 let r = ffi::pthread_cond_broadcast(self.inner.get());
48 debug_assert_eq!(r, 0);
49 }
50
51 #[inline]
52 pub unsafe fn wait(&self, mutex: &Mutex) {
53 let r = ffi::pthread_cond_wait(self.inner.get(), mutex::raw(mutex));
54 debug_assert_eq!(r, 0);
55 }
56
85aaf69f
SL
57 // This implementation is modeled after libcxx's condition_variable
58 // https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
59 // https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
1a4d82fc 60 pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
85aaf69f
SL
61 if dur <= Duration::zero() {
62 return false;
63 }
1a4d82fc 64
85aaf69f
SL
65 // First, figure out what time it currently is, in both system and stable time.
66 // pthread_cond_timedwait uses system time, but we want to report timeout based on stable
67 // time.
68 let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
69 let stable_now = time::SteadyTime::now();
70 let r = ffi::gettimeofday(&mut sys_now, ptr::null_mut());
1a4d82fc
JJ
71 debug_assert_eq!(r, 0);
72
85aaf69f
SL
73 let seconds = NumCast::from(dur.num_seconds());
74 let timeout = match seconds.and_then(|s| sys_now.tv_sec.checked_add(s)) {
75 Some(sec) => {
76 libc::timespec {
77 tv_sec: sec,
78 tv_nsec: (dur - Duration::seconds(dur.num_seconds()))
79 .num_nanoseconds().unwrap() as libc::c_long,
80 }
81 }
82 None => {
83 libc::timespec {
84 tv_sec: Int::max_value(),
85 tv_nsec: 1_000_000_000 - 1,
86 }
87 }
1a4d82fc
JJ
88 };
89
90 // And wait!
85aaf69f
SL
91 let r = ffi::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), &timeout);
92 debug_assert!(r == libc::ETIMEDOUT || r == 0);
93
94 // ETIMEDOUT is not a totally reliable method of determining timeout due to clock shifts,
95 // so do the check ourselves
96 &time::SteadyTime::now() - &stable_now < dur
1a4d82fc
JJ
97 }
98
99 #[inline]
85aaf69f 100 #[cfg(not(target_os = "dragonfly"))]
1a4d82fc
JJ
101 pub unsafe fn destroy(&self) {
102 let r = ffi::pthread_cond_destroy(self.inner.get());
103 debug_assert_eq!(r, 0);
104 }
85aaf69f
SL
105
106 #[inline]
107 #[cfg(target_os = "dragonfly")]
108 pub unsafe fn destroy(&self) {
109 let r = ffi::pthread_cond_destroy(self.inner.get());
110 // On DragonFly pthread_cond_destroy() returns EINVAL if called on
111 // a condvar that was just initialized with
112 // ffi::PTHREAD_COND_INITIALIZER. Once it is used or
113 // pthread_cond_init() is called, this behaviour no longer occurs.
114 debug_assert!(r == 0 || r == libc::EINVAL);
115 }
1a4d82fc 116}