1- // ===--- Futex utils for Darwin -----------------------------------*- C++
2- // -*-===//
1+ // ===--- Futex utils for Darwin ------------------------*- C++-*-===//
32//
43// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
54// See https://llvm.org/LICENSE.txt for license information.
65// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
76//
8- // ===---------------------------------------------------------------------- ===//
7+ // ===------------------------------------------------------------===//
98
109#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_FUTEX_UTILS_H
1110#define LLVM_LIBC_SRC___SUPPORT_THREADS_DARWIN_FUTEX_UTILS_H
@@ -25,39 +24,52 @@ struct Futex : public cpp::Atomic<FutexWordType> {
2524 using cpp::Atomic<FutexWordType>::Atomic;
2625 using Timeout = internal::AbsTimeout;
2726
28- // The Darwin futex API does not return a value on timeout, so we have to
29- // check for it manually. This means we can't use the return value to
30- // distinguish between a timeout and a successful wake-up.
31- int wait (FutexWordType val, cpp::optional<Timeout> timeout, bool ) {
32- if (timeout) {
33- struct timespec now;
34- clock_gettime (timeout->is_realtime () ? CLOCK_REALTIME : CLOCK_MONOTONIC,
35- &now);
36- const timespec &target_ts = timeout->get_timespec ();
27+ LIBC_INLINE long wait (FutexWordType val, cpp::optional<Timeout> timeout,
28+ bool /* is_shared */ ) {
29+ // TODO(bojle): consider using OS_SYNC_WAIT_ON_ADDRESS_SHARED to sync
30+ // betweeen processes. Catch: it is recommended to only be used by shared
31+ // processes, not threads of a same process.
3732
38- if (now.tv_sec > target_ts.tv_sec ||
39- (now.tv_sec == target_ts.tv_sec && now.tv_nsec >= target_ts.tv_nsec ))
40- return ETIMEDOUT;
33+ for (;;) {
34+ if (this ->load (cpp::MemoryOrder::RELAXED) != val)
35+ return 0 ;
36+ long ret = 0 ;
37+ if (timeout) {
38+ // Assuming, OS_CLOCK_MACH_ABSOLUTE_TIME is equivalent to CLOCK_REALTIME
39+ uint64_t tnsec = timeout->get_timespec ().tv_sec * 1000000000 +
40+ timeout->get_timespec ().tv_nsec ;
41+ ret = os_sync_wait_on_address_with_timeout (
42+ reinterpret_cast <void *>(this ), static_cast <uint64_t >(val),
43+ sizeof (FutexWordType), OS_SYNC_WAIT_ON_ADDRESS_NONE,
44+ OS_CLOCK_MACH_ABSOLUTE_TIME, tnsec);
45+ } else {
46+ ret = os_sync_wait_on_address (
47+ reinterpret_cast <void *>(this ), static_cast <uint64_t >(val),
48+ sizeof (FutexWordType), OS_SYNC_WAIT_ON_ADDRESS_NONE);
49+ }
50+ if ((ret < 0 ) && (errno == ETIMEDOUT)) {
51+ return -ETIMEDOUT;
52+ }
53+ // case when os_sync returns early with an error. retry.
54+ if ((ret < 0 ) && ((errno == EINTR) || (errno == EFAULT))) {
55+ continue ;
56+ }
57+ return ret;
4158 }
42-
43- os_sync_wait_on_address (reinterpret_cast <void *>(this ),
44- static_cast <uint64_t >(val), sizeof (FutexWordType),
45- OS_SYNC_WAIT_ON_ADDRESS_NONE);
46- return 0 ;
4759 }
4860
49- void notify_one (bool ) {
50- os_sync_wake_by_address_any (reinterpret_cast <void *>(this ),
51- sizeof (FutexWordType),
52- OS_SYNC_WAKE_BY_ADDRESS_NONE);
61+ LIBC_INLINE long notify_one (bool /* is_shared */ ) {
62+ // TODO(bojle): deal with is_shared
63+ return os_sync_wake_by_address_any (reinterpret_cast <void *>(this ),
64+ sizeof (FutexWordType),
65+ OS_SYNC_WAKE_BY_ADDRESS_NONE);
5366 }
5467
55- void notify_all (bool ) {
56- // os_sync_wake_by_address_all is not available, so we use notify_one.
57- // This is not ideal, but it's the best we can do with the available API.
58- os_sync_wake_by_address_any (reinterpret_cast <void *>(this ),
59- sizeof (FutexWordType),
60- OS_SYNC_WAKE_BY_ADDRESS_NONE);
68+ LIBC_INLINE long notify_all (bool /* is_shared */ ) {
69+ // TODO(bojle): deal with is_shared
70+ return os_sync_wake_by_address_all (reinterpret_cast <void *>(this ),
71+ sizeof (FutexWordType),
72+ OS_SYNC_WAKE_BY_ADDRESS_NONE);
6173 }
6274};
6375
0 commit comments