123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263 |
- #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
|