1 // Copyright 2016 Amanieu d'Antras
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
10 sync
::atomic
::{AtomicI32, Ordering}
,
13 use std
::{thread, time::Instant}
;
15 // x32 Linux uses a non-standard type for tv_nsec in timespec.
16 // See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
17 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
18 #[allow(non_camel_case_types)]
20 #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
21 #[allow(non_camel_case_types)]
22 type tv_nsec_t
= libc
::c_long
;
24 fn errno() -> libc
::c_int
{
25 #[cfg(target_os = "linux")]
27 *libc
::__errno_location()
29 #[cfg(target_os = "android")]
35 // Helper type for putting a thread to sleep until some other thread wakes it up
36 pub struct ThreadParker
{
40 impl super::ThreadParkerT
for ThreadParker
{
41 type UnparkHandle
= UnparkHandle
;
43 const IS_CHEAP_TO_CONSTRUCT
: bool
= true;
46 fn new() -> ThreadParker
{
48 futex
: AtomicI32
::new(0),
53 unsafe fn prepare_park(&self) {
54 self.futex
.store(1, Ordering
::Relaxed
);
58 unsafe fn timed_out(&self) -> bool
{
59 self.futex
.load(Ordering
::Relaxed
) != 0
63 unsafe fn park(&self) {
64 while self.futex
.load(Ordering
::Acquire
) != 0 {
65 self.futex_wait(None
);
70 unsafe fn park_until(&self, timeout
: Instant
) -> bool
{
71 while self.futex
.load(Ordering
::Acquire
) != 0 {
72 let now
= Instant
::now();
76 let diff
= timeout
- now
;
77 if diff
.as_secs() as libc
::time_t
as u64 != diff
.as_secs() {
78 // Timeout overflowed, just sleep indefinitely
82 let ts
= libc
::timespec
{
83 tv_sec
: diff
.as_secs() as libc
::time_t
,
84 tv_nsec
: diff
.subsec_nanos() as tv_nsec_t
,
86 self.futex_wait(Some(ts
));
91 // Locks the parker to prevent the target thread from exiting. This is
92 // necessary to ensure that thread-local ThreadData objects remain valid.
93 // This should be called while holding the queue lock.
95 unsafe fn unpark_lock(&self) -> UnparkHandle
{
96 // We don't need to lock anything, just clear the state
97 self.futex
.store(0, Ordering
::Release
);
99 UnparkHandle { futex: &self.futex }
105 fn futex_wait(&self, ts
: Option
<libc
::timespec
>) {
108 .map(|ts_ref
| ts_ref
as *const _
)
109 .unwrap_or(ptr
::null());
114 libc
::FUTEX_WAIT
| libc
::FUTEX_PRIVATE_FLAG
,
119 debug_assert
!(r
== 0 || r
== -1);
122 errno() == libc
::EINTR
123 || errno() == libc
::EAGAIN
124 || (ts
.is_some() && errno() == libc
::ETIMEDOUT
)
130 pub struct UnparkHandle
{
131 futex
: *const AtomicI32
,
134 impl super::UnparkHandleT
for UnparkHandle
{
136 unsafe fn unpark(self) {
137 // The thread data may have been freed at this point, but it doesn't
138 // matter since the syscall will just return EFAULT in that case.
139 let r
= libc
::syscall(
142 libc
::FUTEX_WAKE
| libc
::FUTEX_PRIVATE_FLAG
,
145 debug_assert
!(r
== 0 || r
== 1 || r
== -1);
147 debug_assert_eq
!(errno(), libc
::EFAULT
);
153 pub fn thread_yield() {