#pragma once // Baselib_SystemFutex // In computing, a futex (short for "fast userspace mutex") is a kernel system call that programmers can use to implement basic locking, or as a building block // for higher-level locking abstractions such as semaphores and POSIX mutexes or condition variables. // // A futex consists of a kernelspace wait queue that is attached to an atomic integer in userspace. Multiple processes or threads operate on the integer // entirely in userspace (using atomic operations to avoid interfering with one another), and only resort to relatively expensive system calls to request // operations on the wait queue (for example to wake up waiting processes, or to put the current process on the wait queue). A properly programmed futex-based // lock will not use system calls except when the lock is contended; since most operations do not require arbitration between processes, this will not happen // in most cases. // // "Futex", Wikipedia: The Free Encyclopedia // https://en.wikipedia.org/w/index.php?title=Futex&oldid=850172014 #include "Baselib_WakeupFallbackStrategy.h" #ifdef __cplusplus BASELIB_C_INTERFACE { #endif // Determines if the platform has access to a kernel level futex api // // If native support is not present the futex will fallback to an emulated futex setup. // // Notes on the emulation: // * It uses a single synchronization primitive to multiplex all potential addresses. This means there will be // additional contention as well as spurious wakeups compared to a native implementation. // * While the fallback implementation is not something that should be used in production it can still provide value // when bringing up new platforms or to test features built on top of the futex api. BASELIB_INLINE_API bool Baselib_SystemFutex_NativeSupport(void) { return PLATFORM_FUTEX_NATIVE_SUPPORT == 1; } // Wait for notification. // // Address will be checked atomically against expected before entering wait. This can be used to guarantee there are no lost wakeups. // Note: When notified the thread always wake up regardless if the expectation match the value at address or not. // // | Problem this solves // | Thread 1: checks condition and determine we should enter wait // | Thread 2: change condition and notify waiting threads // | Thread 1: enters waiting state // | // | With a futex the two Thread 1 operations become a single op. // // Spurious Wakeup - This function is subject to spurious wakeups. // // \param address Any address that can be read from both user and kernel space. // \param expected What address points to will be checked against this value. If the values don't match thread will not enter a waiting state. // \param timeoutInMilliseconds A timeout indicating to the kernel when to wake the thread. Regardless of being notified or not. BASELIB_API void Baselib_SystemFutex_Wait(int32_t* address, int32_t expected, uint32_t timeoutInMilliseconds); // Notify threads waiting on a specific address. // // \param address Any address that can be read from both user and kernel space // \param count Number of waiting threads to wakeup. // \param wakeupFallbackStrategy Platforms that don't support waking up a specific number of threads will use this strategy. BASELIB_API void Baselib_SystemFutex_Notify(int32_t* address, uint32_t count, Baselib_WakeupFallbackStrategy wakeupFallbackStrategy); #ifdef __cplusplus } // BASELIB_C_INTERFACE #endif