blob: d90879f981178863efcf52979c904f34f5e3be2c [file] [log] [blame]
// 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
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_time_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
FutexWait(resource struct {
@embedded_alias("zx/Futex")
value_ptr experimental_pointer<Futex>;
current_value Futex;
new_futex_owner handle;
deadline time;
}) -> () 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
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
FutexRequeue(resource struct {
@embedded_alias("zx/Futex")
value_ptr experimental_pointer<Futex>;
wake_count uint32;
current_value Futex;
@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
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
FutexRequeueSingleOwner(resource struct {
@embedded_alias("zx/Futex")
value_ptr experimental_pointer<Futex>;
current_value Futex;
@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)
FutexGetOwner(struct {
@embedded_alias("zx/Futex")
value_ptr experimental_pointer<Futex>;
}) -> (struct {
koid koid;
}) error status;
};