Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-11-19 09:50:49

0001 // ParkingLot is an internal API for building efficient synchronization
0002 // primitives like mutexes and events.
0003 //
0004 // The API and name is inspired by WebKit's WTF::ParkingLot, which in turn
0005 // is inspired Linux's futex API.
0006 // See https://webkit.org/blog/6161/locking-in-webkit/.
0007 //
0008 // The core functionality is an atomic "compare-and-sleep" operation along with
0009 // an atomic "wake-up" operation.
0010 
0011 #ifndef Py_INTERNAL_PARKING_LOT_H
0012 #define Py_INTERNAL_PARKING_LOT_H
0013 #ifdef __cplusplus
0014 extern "C" {
0015 #endif
0016 
0017 #ifndef Py_BUILD_CORE
0018 #  error "this header requires Py_BUILD_CORE define"
0019 #endif
0020 
0021 
0022 enum {
0023     // The thread was unparked by another thread.
0024     Py_PARK_OK = 0,
0025 
0026     // The value of `address` did not match `expected`.
0027     Py_PARK_AGAIN = -1,
0028 
0029     // The thread was unparked due to a timeout.
0030     Py_PARK_TIMEOUT = -2,
0031 
0032     // The thread was interrupted by a signal.
0033     Py_PARK_INTR = -3,
0034 };
0035 
0036 // Checks that `*address == *expected` and puts the thread to sleep until an
0037 // unpark operation is called on the same `address`. Otherwise, the function
0038 // returns `Py_PARK_AGAIN`. The comparison behaves like memcmp, but is
0039 // performed atomically with respect to unpark operations.
0040 //
0041 // The `address_size` argument is the size of the data pointed to by the
0042 // `address` and `expected` pointers (i.e., sizeof(*address)). It must be
0043 // 1, 2, 4, or 8.
0044 //
0045 // The `timeout_ns` argument specifies the maximum amount of time to wait, with
0046 // -1 indicating an infinite wait.
0047 //
0048 // `park_arg`, which can be NULL, is passed to the unpark operation.
0049 //
0050 // If `detach` is true, then the thread will detach/release the GIL while
0051 // waiting.
0052 //
0053 // Example usage:
0054 //
0055 //  if (_Py_atomic_compare_exchange_uint8(address, &expected, new_value)) {
0056 //    int res = _PyParkingLot_Park(address, &new_value, sizeof(*address),
0057 //                                 timeout_ns, NULL, 1);
0058 //    ...
0059 //  }
0060 PyAPI_FUNC(int)
0061 _PyParkingLot_Park(const void *address, const void *expected,
0062                    size_t address_size, PyTime_t timeout_ns,
0063                    void *park_arg, int detach);
0064 
0065 // Callback for _PyParkingLot_Unpark:
0066 //
0067 // `arg` is the data of the same name provided to the _PyParkingLot_Unpark()
0068 //      call.
0069 // `park_arg` is the data provided to _PyParkingLot_Park() call or NULL if
0070 //      no waiting thread was found.
0071 // `has_more_waiters` is true if there are more threads waiting on the same
0072 //      address. May be true in cases where threads are waiting on a different
0073 //      address that map to the same internal bucket.
0074 typedef void _Py_unpark_fn_t(void *arg, void *park_arg, int has_more_waiters);
0075 
0076 // Unparks a single thread waiting on `address`.
0077 //
0078 // Note that fn() is called regardless of whether a thread was unparked. If
0079 // no threads are waiting on `address` then the `park_arg` argument to fn()
0080 // will be NULL.
0081 //
0082 // Example usage:
0083 //  void callback(void *arg, void *park_arg, int has_more_waiters);
0084 //  _PyParkingLot_Unpark(address, &callback, arg);
0085 PyAPI_FUNC(void)
0086 _PyParkingLot_Unpark(const void *address, _Py_unpark_fn_t *fn, void *arg);
0087 
0088 // Unparks all threads waiting on `address`.
0089 PyAPI_FUNC(void) _PyParkingLot_UnparkAll(const void *address);
0090 
0091 // Resets the parking lot state after a fork. Forgets all parked threads.
0092 PyAPI_FUNC(void) _PyParkingLot_AfterFork(void);
0093 
0094 #ifdef __cplusplus
0095 }
0096 #endif
0097 #endif /* !Py_INTERNAL_PARKING_LOT_H */