Serenity Operating System
at master 161 lines 6.0 kB view raw
1/* 2 * Copyright (c) 2019, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, Sergey Bugaev <bugaevc@serenityos.org> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/Assertions.h> 9#include <AK/Atomic.h> 10#include <AK/Types.h> 11#include <bits/pthread_cancel.h> 12#include <errno.h> 13#include <pthread.h> 14#include <serenity.h> 15#include <sys/types.h> 16#include <time.h> 17 18// Condition variable attributes. 19 20// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_init.html 21int pthread_condattr_init(pthread_condattr_t* attr) 22{ 23 attr->clockid = CLOCK_MONOTONIC_COARSE; 24 return 0; 25} 26 27// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_destroy.html 28int pthread_condattr_destroy(pthread_condattr_t*) 29{ 30 return 0; 31} 32 33// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_getclock.html 34int pthread_condattr_getclock(pthread_condattr_t* attr, clockid_t* clock) 35{ 36 *clock = attr->clockid; 37 return 0; 38} 39 40// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_setclock.html 41int pthread_condattr_setclock(pthread_condattr_t* attr, clockid_t clock) 42{ 43 switch (clock) { 44 case CLOCK_REALTIME: 45 case CLOCK_REALTIME_COARSE: 46 case CLOCK_MONOTONIC: 47 case CLOCK_MONOTONIC_COARSE: 48 case CLOCK_MONOTONIC_RAW: 49 attr->clockid = clock; 50 return 0; 51 default: 52 return EINVAL; 53 } 54} 55 56// Condition variables. 57 58// cond->value is the generation number (number of times the variable has been 59// signaled) multiplied by INCREMENT, or'ed with the NEED_TO_WAKE flags. It's 60// done this way instead of putting the flags into the high bits because the 61// sequence number can easily overflow, which is completely fine but should not 62// cause it to corrupt the flags. 63static constexpr u32 NEED_TO_WAKE_ONE = 1; 64static constexpr u32 NEED_TO_WAKE_ALL = 2; 65static constexpr u32 INCREMENT = 4; 66 67// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_init.html 68int pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t const* attr) 69{ 70 cond->mutex = nullptr; 71 cond->value = 0; 72 cond->clockid = attr ? attr->clockid : CLOCK_REALTIME_COARSE; 73 return 0; 74} 75 76// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_destroy.html 77int pthread_cond_destroy(pthread_cond_t*) 78{ 79 return 0; 80} 81 82// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_wait.html 83int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) 84{ 85 return pthread_cond_timedwait(cond, mutex, nullptr); 86} 87 88// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html 89int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime) 90{ 91 __pthread_maybe_cancel(); 92 93 // Save the mutex this condition variable is associated with. We don't (yet) 94 // support changing this mutex once set. 95 pthread_mutex_t* old_mutex = AK::atomic_exchange(&cond->mutex, mutex, AK::memory_order_relaxed); 96 if (old_mutex && old_mutex != mutex) 97 TODO(); 98 99 // Fetch the current value, and record that we're about to wait. Fetching 100 // the current value has to be done while we hold the mutex, because the 101 // value might change as soon as we unlock it. 102 u32 value = AK::atomic_fetch_or(&cond->value, NEED_TO_WAKE_ONE | NEED_TO_WAKE_ALL, AK::memory_order_release) | NEED_TO_WAKE_ONE | NEED_TO_WAKE_ALL; 103 pthread_mutex_unlock(mutex); 104 int rc = futex_wait(&cond->value, value, abstime, cond->clockid, false); 105 if (rc < 0 && errno != EAGAIN) 106 return errno; 107 108 // We might have been re-queued onto the mutex while we were sleeping. Take 109 // the pessimistic locking path. 110 __pthread_mutex_lock_pessimistic_np(mutex); 111 return 0; 112} 113 114// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_signal.html 115int pthread_cond_signal(pthread_cond_t* cond) 116{ 117 // Increment the generation. 118 u32 value = AK::atomic_fetch_add(&cond->value, INCREMENT, AK::memory_order_relaxed); 119 // Fast path: nobody's waiting (or at least, nobody has to be woken). 120 if (!(value & NEED_TO_WAKE_ONE)) [[likely]] 121 return 0; 122 123 // Wake someone, and clear the NEED_TO_WAKE_ONE flag if there was nobody for 124 // us to wake, to take the fast path the next time. Since we only learn 125 // whether there has been somebody waiting or not after we have tried to 126 // wake them, it would make sense for us to clear the flag after trying to 127 // wake someone up and seeing there was nobody waiting; but that would race 128 // with somebody else setting the flag. Therefore, we do it like this: 129 // attempt to clear the flag first... 130 value = AK::atomic_fetch_and(&cond->value, ~NEED_TO_WAKE_ONE, AK::memory_order_relaxed); 131 // ...check if it was already cleared by someone else... 132 if (!(value & NEED_TO_WAKE_ONE)) [[likely]] 133 return 0; 134 // ...try to wake someone... 135 int rc = futex_wake(&cond->value, 1, false); 136 VERIFY(rc >= 0); 137 // ...and if we have woken someone, put the flag back. 138 if (rc > 0) 139 AK::atomic_fetch_or(&cond->value, NEED_TO_WAKE_ONE, AK::memory_order_relaxed); 140 141 return 0; 142} 143 144// https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html 145int pthread_cond_broadcast(pthread_cond_t* cond) 146{ 147 // Increment the generation. 148 u32 value = AK::atomic_fetch_add(&cond->value, INCREMENT, AK::memory_order_relaxed); 149 // Fast path: nobody's waiting (or at least, nobody has to be woken). 150 if (!(value & NEED_TO_WAKE_ALL)) [[likely]] 151 return 0; 152 153 AK::atomic_fetch_and(&cond->value, ~(NEED_TO_WAKE_ONE | NEED_TO_WAKE_ALL), AK::memory_order_acquire); 154 155 pthread_mutex_t* mutex = AK::atomic_load(&cond->mutex, AK::memory_order_relaxed); 156 VERIFY(mutex); 157 158 int rc = futex(&cond->value, FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG, 1, nullptr, &mutex->lock, INT_MAX); 159 VERIFY(rc >= 0); 160 return 0; 161}