| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| library zx; |
| |
| // TODO(scottmg): This is approximately right, but will need to match the |
| // current definition of zx_futex_t (atomic_int in some #if branches). |
| alias Futex = int32; |
| |
| // TODO(scottmg): The futex is unusual in that by virtue of being an int, |
| // sometimes it's passed by pointer, and sometimes by value. |
| @transport("Syscall") |
| @no_protocol_prefix |
| closed protocol Futexfuncs { |
| /// ## Summary |
| /// |
| /// Wait on a futex. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_futex_wait(const zx_futex_t* value_ptr, |
| /// zx_futex_t current_value, |
| /// zx_handle_t new_futex_owner, |
| /// zx_instant_mono_t deadline); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// `zx_futex_wait()` atomically verifies that *value_ptr* still contains the value |
| /// *current_value* and sleeps until the futex is made available by a call to |
| /// `zx_futex_wake`. Optionally, the thread can also be woken up after the |
| /// *deadline* (with respect to `ZX_CLOCK_MONOTONIC`) passes. *deadline* may be |
| /// automatically adjusted according to the job's [timer slack] policy. |
| /// |
| /// ## SPURIOUS WAKEUPS |
| /// |
| /// A component that uses futexes should be prepared to handle spurious |
| /// wakeups. A spurious wakeup is a situation where `zx_futex_wait()` |
| /// returns successfully even though the component did not wake the waiter |
| /// by calling [`zx_futex_wake()`]. |
| /// |
| /// Zircon's implementation of futexes currently does not generate |
| /// spurious wakeups itself. However, commonly-used algorithms that use |
| /// futexes can sometimes generate spurious wakeups. For example, the |
| /// usual implementation of `mutex_unlock` can potentially produce a |
| /// [`zx_futex_wake()`] call on a memory location after the location has been |
| /// freed and reused for unrelated purposes. |
| /// |
| /// ## OWNERSHIP |
| /// |
| /// A successful call to `zx_futex_wait()` results in the owner of the futex being |
| /// set to the thread referenced by the *new_futex_owner* handle, or to nothing if |
| /// *new_futex_owner* is `ZX_HANDLE_INVALID`. |
| /// |
| /// See *Ownership and Priority Inheritance* in [futex](/docs/reference/kernel_objects/futex.md) for |
| /// details. |
| /// |
| /// ## Rights |
| /// |
| /// None. |
| /// |
| /// ## Return value |
| /// |
| /// `zx_futex_wait()` returns `ZX_OK` on success. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_INVALID_ARGS` One of the following is true: |
| /// |
| /// + *value_ptr* is not a valid userspace pointer |
| /// + *value_ptr* is not aligned to a `sizeof(zx_futex_t)` boundary. |
| /// + *new_futex_owner* is currently a member of the waiters for *value_ptr*. |
| /// + *new_futex_owner* has not been started yet. |
| /// |
| /// `ZX_ERR_BAD_HANDLE` *new_futex_owner* is not `ZX_HANDLE_INVALID`, and not a valid handle AND |
| /// *current_value* matches the value at *value_ptr* |
| /// |
| /// `ZX_ERR_WRONG_TYPE` *new_futex_owner* is a valid handle, but is not a handle to a thread. |
| /// |
| /// `ZX_ERR_BAD_STATE` *current_value* does not match the value at *value_ptr*. |
| /// |
| /// `ZX_ERR_TIMED_OUT` The thread was not woken before *deadline* passed. |
| /// |
| /// ## See also |
| /// |
| /// - [futex objects] |
| /// - [timer slack] |
| /// - [`zx_futex_requeue()`] |
| /// - [`zx_futex_wake()`] |
| /// |
| /// [futex objects]: /docs/reference/kernel_objects/futex.md |
| /// [timer slack]: /docs/concepts/kernel/timer_slack.md |
| /// [`zx_futex_requeue()`]: futex_requeue.md |
| /// [`zx_futex_wake()`]: futex_wake.md |
| @blocking |
| strict FutexWait(resource struct { |
| @embedded_alias("zx/Futex") |
| value_ptr experimental_pointer<Futex>; |
| current_value int32; |
| new_futex_owner Handle; |
| deadline InstantMono; |
| }) -> () error Status; |
| |
| /// ## Summary |
| /// |
| /// Wake some number of threads waiting on a futex, and set the ownership of the futex to nothing. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_futex_wake(const zx_futex_t* value_ptr, uint32_t wake_count); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// Waking a futex causes *wake_count* threads waiting on the *value_ptr* |
| /// futex to be woken up. |
| /// |
| /// Waking up zero threads is not an error condition. Passing in an unallocated |
| /// address for *value_ptr* is not an error condition. |
| /// |
| /// ## OWNERSHIP |
| /// |
| /// A successful call to `zx_futex_wake()` results in the owner of the futex being |
| /// set to nothing, regardless of the wake count. In order to transfer ownership of |
| /// a futex, use the [`zx_futex_wake_single_owner()`] variant instead. |
| /// [`zx_futex_wake_single_owner()`] will attempt to wake exactly one thread from the |
| /// futex wait queue. If there is at least one thread to wake, the owner of the |
| /// futex will be set to the thread that was woken. Otherwise, the futex will have |
| /// no owner. |
| /// |
| /// See *Ownership and Priority Inheritance* in [futex](/docs/reference/kernel_objects/futex.md) for |
| /// details. |
| /// |
| /// ## Rights |
| /// |
| /// None. |
| /// |
| /// ## Return value |
| /// |
| /// `zx_futex_wake()` returns `ZX_OK` on success. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_INVALID_ARGS` *value_ptr* is not aligned. |
| /// |
| /// ## See also |
| /// |
| /// - [futex objects] |
| /// - [`zx_futex_requeue()`] |
| /// - [`zx_futex_wait()`] |
| /// - [`zx_futex_wake_single_owner()`] |
| /// |
| /// [futex objects]: /docs/reference/kernel_objects/futex.md |
| /// [`zx_futex_requeue()`]: futex_requeue.md |
| /// [`zx_futex_wait()`]: futex_wait.md |
| /// [`zx_futex_wake_single_owner()`]: futex_wake_single_owner.md |
| strict FutexWake(struct { |
| @embedded_alias("zx/Futex") |
| value_ptr experimental_pointer<Futex>; |
| wake_count uint32; |
| }) -> () error Status; |
| |
| /// ## Summary |
| /// |
| /// Wake some number of threads waiting on a futex, and move more waiters to another wait queue. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_futex_requeue(const zx_futex_t* value_ptr, |
| /// uint32_t wake_count, |
| /// zx_futex_t current_value, |
| /// const zx_futex_t* requeue_ptr, |
| /// uint32_t requeue_count, |
| /// zx_handle_t new_requeue_owner); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// Requeuing is a generalization of waking. First, the kernel verifies |
| /// that the value in *current_value* matches the value of the futex at |
| /// *value_ptr*, and if not reports `ZX_ERR_BAD_STATE`. After waking *wake_count* |
| /// threads, *requeue_count* threads are moved from the original futex's |
| /// wait queue to the wait queue corresponding to *requeue_ptr*, another |
| /// futex. |
| /// |
| /// This requeueing behavior may be used to avoid thundering herds on wake. |
| /// |
| /// ## OWNERSHIP |
| /// |
| /// A requeue operation targets two futexes, the _wake futex_ and the _requeue |
| /// futex_. The ownership implications for each are discussed separately. |
| /// Generally, if the call fails for any reason, no changes to ownership for either |
| /// futex are made. |
| /// |
| /// See *Ownership and Priority Inheritance* in [futex](/docs/reference/kernel_objects/futex.md) for |
| /// details. |
| /// |
| /// ### Effects on the _wake futex_ target |
| /// |
| /// A successful call to `zx_futex_requeue()` results in the owner of the futex being |
| /// set to nothing, regardless of the wake count. In order to transfer ownership of |
| /// a futex, use the [`zx_futex_requeue_single_owner()`] variant instead. |
| /// [`zx_futex_requeue_single_owner()`] will attempt to wake exactly one thread from the |
| /// futex wait queue. If there is at least one thread to wake, the owner of the futex will be |
| /// set to the thread that was woken. Otherwise, the futex |
| /// will have no owner. |
| /// |
| /// ### Effects on the _requeue futex_ target |
| /// |
| /// A successful call to `zx_futex_requeue()` or [`zx_futex_requeue_single_owner()`] |
| /// results in the owner of the futex being set to the thread referenced by the |
| /// *new_requeue_owner* handle, or to nothing if *new_requeue_owner* is |
| /// `ZX_HANDLE_INVALID`. |
| /// |
| /// ## Rights |
| /// |
| /// None. |
| /// |
| /// ## Return value |
| /// |
| /// `zx_futex_requeue()` returns `ZX_OK` on success. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_INVALID_ARGS` One of the following is true: |
| /// |
| /// + Either *value_ptr* or *requeue_ptr* is not a valid userspace pointer |
| /// + Either *value_ptr* or *requeue_ptr* is not aligned to a `sizeof(zx_futex_t)` boundary. |
| /// + *value_ptr* is the same futex as *requeue_ptr* |
| /// + *new_requeue_owner* is currently a member of the waiters for either *value_ptr* or *requeue_ptr* |
| /// + *new_requeue_owner* has not been started yet. |
| /// |
| /// `ZX_ERR_BAD_HANDLE` *new_requeue_owner* is not `ZX_HANDLE_INVALID`, and not a valid handle AND |
| /// *current_value* matches the value at *value_ptr* |
| /// |
| /// `ZX_ERR_WRONG_TYPE` *new_requeue_owner* is a valid handle, but is not a handle to a thread. |
| /// |
| /// `ZX_ERR_BAD_STATE` *current_value* does not match the value at *value_ptr*. |
| /// |
| /// ## See also |
| /// |
| /// - [futex objects] |
| /// - [`zx_futex_requeue_single_owner()`] |
| /// - [`zx_futex_wait()`] |
| /// - [`zx_futex_wake()`] |
| /// |
| /// [futex objects]: /docs/reference/kernel_objects/futex.md |
| /// [`zx_futex_requeue_single_owner()`]: futex_requeue_single_owner.md |
| /// [`zx_futex_wait()`]: futex_wait.md |
| /// [`zx_futex_wake()`]: futex_wake.md |
| strict FutexRequeue(resource struct { |
| @embedded_alias("zx/Futex") |
| value_ptr experimental_pointer<Futex>; |
| wake_count uint32; |
| current_value int32; |
| @embedded_alias("zx/Futex") |
| requeue_ptr experimental_pointer<Futex>; |
| requeue_count uint32; |
| new_requeue_owner Handle; |
| }) -> () error Status; |
| |
| /// ## Summary |
| /// |
| /// Wake one thread waiting on a futex, and set the ownership of the futex to that thread. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_futex_wake_single_owner(const zx_futex_t* value_ptr); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// Wake one thread waiting on a futex. |
| /// If a thread is woken, ownership of the futex is transferred to that thread. If no |
| /// thread is woken (because none are waiting), ownership of the futex is set to none. |
| /// |
| /// See [`zx_futex_wake()`] for a full description. |
| /// |
| /// ## Rights |
| /// |
| /// None. |
| /// |
| /// ## Return value |
| /// |
| /// `zx_futex_wake_single_owner()` returns `ZX_OK` on success. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_INVALID_ARGS` *value_ptr* is not aligned. |
| /// |
| /// ## See also |
| /// |
| /// - [futex objects] |
| /// - [`zx_futex_requeue()`] |
| /// - [`zx_futex_wait()`] |
| /// - [`zx_futex_wake()`] |
| /// |
| /// [futex objects]: /docs/reference/kernel_objects/futex.md |
| /// [`zx_futex_requeue()`]: futex_requeue.md |
| /// [`zx_futex_wait()`]: futex_wait.md |
| /// [`zx_futex_wake()`]: futex_wake.md |
| strict FutexWakeSingleOwner(struct { |
| @embedded_alias("zx/Futex") |
| value_ptr experimental_pointer<Futex>; |
| }) -> () error Status; |
| |
| /// ## Summary |
| /// |
| /// Wake one thread waiting on a futex, and requeue more waiters to another futex wait queue. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_futex_requeue_single_owner(const zx_futex_t* value_ptr, |
| /// zx_futex_t current_value, |
| /// const zx_futex_t* requeue_ptr, |
| /// uint32_t requeue_count, |
| /// zx_handle_t new_requeue_owner); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// Wake one thread waiting on *value_ptr* and assign ownership of *value_ptr* to |
| /// the thread that was woken. If there are no threads waiting on *value_ptr* then |
| /// the ownership of *value_ptr* is set to none. |
| /// |
| /// Then move up to *requeue_count* threads that are still waiting on *value_ptr* from |
| /// the *value_ptr* futex to the *requeue_ptr* futex. |
| /// |
| /// `zx_futex_requeue_single_owner` is similar to `zx_futex_requeue` with a |
| /// *wake_count* of 1, except that `zx_futex_requeue_single_owner` changes the |
| /// ownership of *value_ptr* to the woken thread. |
| /// See [`zx_futex_requeue()`] for a full description. |
| /// |
| /// ## Rights |
| /// |
| /// None. |
| /// |
| /// ## Return value |
| /// |
| /// `zx_futex_requeue_single_owner()` returns `ZX_OK` on success. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_INVALID_ARGS` One of the following is true: |
| /// |
| /// + Either *value_ptr* or *requeue_ptr* is not a valid userspace pointer |
| /// + Either *value_ptr* or *requeue_ptr* is not aligned to a `sizeof(zx_futex_t)` boundary. |
| /// + *value_ptr* is the same futex as *requeue_ptr* |
| /// + *new_requeue_owner* is currently a member of the waiters for either *value_ptr* or *requeue_ptr* |
| /// |
| /// `ZX_ERR_BAD_HANDLE` *new_requeue_owner* is not `ZX_HANDLE_INVALID`, and not a valid handle. |
| /// |
| /// `ZX_ERR_WRONG_TYPE` *new_requeue_owner* is a valid handle, but is not a handle to a thread. |
| /// |
| /// `ZX_ERR_BAD_STATE` *current_value* does not match the value at *value_ptr*. |
| /// |
| /// ## See also |
| /// |
| /// - [futex objects] |
| /// - [`zx_futex_requeue()`] |
| /// - [`zx_futex_wait()`] |
| /// - [`zx_futex_wake()`] |
| /// |
| /// [futex objects]: /docs/reference/kernel_objects/futex.md |
| /// [`zx_futex_requeue()`]: futex_requeue.md |
| /// [`zx_futex_wait()`]: futex_wait.md |
| /// [`zx_futex_wake()`]: futex_wake.md |
| strict FutexRequeueSingleOwner(resource struct { |
| @embedded_alias("zx/Futex") |
| value_ptr experimental_pointer<Futex>; |
| current_value int32; |
| @embedded_alias("zx/Futex") |
| requeue_ptr experimental_pointer<Futex>; |
| requeue_count uint32; |
| new_requeue_owner Handle; |
| }) -> () error Status; |
| |
| /// ## Summary |
| /// |
| /// Fetch the koid current owner of a futex, if any. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_futex_get_owner(const zx_futex_t* value_ptr, zx_koid_t* koid); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// Fetch the koid of the current owner of the futex identified by *value_ptr*, or |
| /// `ZX_KOID_INVALID` if there is no current owner. Knowledge of the ownership of |
| /// a futex typically serves no purpose when building synchronization primitives |
| /// from futexes. This syscall is used primarily for testing. |
| /// |
| /// See *Ownership and Priority Inheritance* in [futex](/docs/reference/kernel_objects/futex.md) for |
| /// details. |
| /// |
| /// ## Rights |
| /// |
| /// None. |
| /// |
| /// ## Return value |
| /// |
| /// `zx_futex_get_owner()` returns `ZX_OK` on success, and koids hold the owner of |
| /// the futex at the time of the syscall, or `ZX_KOID_INVALID` if there was no |
| /// owner. |
| /// |
| /// ## Errors |
| /// |
| /// `ZX_ERR_INVALID_ARGS` One of the following is true: |
| /// |
| /// + *value_ptr* is not a valid userspace pointer. |
| /// + *value_ptr* is not aligned to a `sizeof(zx_futex_t)` boundary. |
| /// + *koid* is not a valid userspace pointer. |
| /// |
| /// ## See also |
| /// |
| /// [futex objects](/docs/reference/kernel_objects/futex.md) |
| strict FutexGetOwner(struct { |
| @embedded_alias("zx/Futex") |
| value_ptr experimental_pointer<Futex>; |
| }) -> (struct { |
| koid Koid; |
| }) error Status; |
| }; |