64 lines
3.4 KiB
C
64 lines
3.4 KiB
C
#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
|