Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: callback reentrancy #481

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions doc/articles/Asynchronous Operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,15 @@ The `callback` function pointer is called when the application _observes complet
> @copydoc ::WGPUCallbackMode_AllowSpontaneous

## wgpuInstanceWaitAny {#Wait-Any}

`WGPUWaitStatus wgpuInstanceWaitAny(WGPUInstance, size_t futureCount, WGPUFutureWaitInfo * futures, uint64_t timeoutNS)`

Waits on any WGPUFuture in the list of `futures` to complete for `timeoutNS` nanoseconds. Returns when at least one `WGPUFuture` is completed or `timeoutNS` elapses, whichever is first. If `timeoutNS` is zero, all `futures` are polled once, without blocking.

Returns @ref WGPUWaitStatus_Success if at least one `WGPUFuture` completes. WGPUFutureWaitInfo::completed is set to true for all completed futures. See @ref WGPUWaitStatus for other status codes.

Within this call, for any `WGPUFuture`s that completed, their respective callbacks will fire.
Note that the timeout applies only to the "wait" phase, and does not affect the callback firing phase.

### Timed Wait {#Timed-Wait}

Expand Down Expand Up @@ -69,3 +71,16 @@ Device events are slightly different in that their callback info (`WGPUDeviceLos
The `WGPUUncapturedErrorCallbackInfo` _does not_ have a callback mode member. It is always as-if it were @ref WGPUCallbackMode_AllowSpontaneous. Note also that the uncaptured error callback is a _repeating_ callback that fires multiple times, unlike other callbacks in webgpu.h.

The uncaptured error callback is guaranteed not to fire after the device becomes lost. When the device is lost, it is an appropriate time for the application to free userdata variables for the uncaptured error callback. Note that the device becomes lost _before_ the actual device lost callback fires. First the device state transitions to lost, then the device lost callback fires. The timing of the callback depends on the device lost callback mode.

## Callback Reentrancy {#CallbackReentrancy}

There are three cases of async/callback re-entrancy:

- Calls to the API are nested inside non-spontaneous callbacks (those with @ref WGPUCallbackMode_WaitAnyOnly or @ref WGPUCallbackMode_AllowProcessEvents). Such callbacks always happen in @ref wgpuInstanceWaitAny() or @ref wgpuInstanceProcessEvents().
- This does not introduce any unsafety. Implementations are required to exit critical sections before invoking callbacks.
- This includes making nested calls to @ref wgpuInstanceWaitAny() and @ref wgpuInstanceProcessEvents(). (However, beware of overflowing the call stack!)
- Calls to the API are nested inside @ref WGPUCallbackMode_AllowSpontaneous callbacks, which may happen at any time (during a `webgpu.h` function call or on an arbitrary thread).
- It is therefore always unsafe to make calls to the API in a @ref WGPUCallbackMode_AllowSpontaneous callback. Additionally, applications should take extra care even when accessing their *own* state (and locks) inside the callback.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think "always unsafe" would be too pessimistic? I'm wondering if we could say "potentially unsafe"? (Mainly I'm thinking about getMappedRange calls in MapAsync callback which would be nice to use in spontaneous mode)

- This includes @ref WGPUDeviceDescriptor::uncapturedErrorCallbackInfo, which is always allowed to fire spontaneously.
- Two threads are doing things in parallel and so calls to the API are made while callbacks (or API functions in general) are running on another thread.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit in parallel and so calls -> in parallel so calls

- In general, most API calls are thread-safe (see @ref ThreadSafety).
2 changes: 2 additions & 0 deletions webgpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -3792,6 +3792,8 @@ typedef struct WGPUDeviceDescriptor {
* Called when there is an uncaptured error on this device, from any thread.
* See @ref ErrorScopes.
*
* **Important:** This callback does not have a configurable @ref WGPUCallbackMode; it may be called at any time (like @ref WGPUCallbackMode_AllowSpontaneous). As such, calls into the `webgpu.h` API from this callback are unsafe. See @ref CallbackReentrancy.
*
* The `INIT` macro sets this to @ref WGPU_UNCAPTURED_ERROR_CALLBACK_INFO_INIT.
*/
WGPUUncapturedErrorCallbackInfo uncapturedErrorCallbackInfo;
Expand Down
2 changes: 2 additions & 0 deletions webgpu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1998,6 +1998,8 @@ structs:
doc: |
Called when there is an uncaptured error on this device, from any thread.
See @ref ErrorScopes.

**Important:** This callback does not have a configurable @ref WGPUCallbackMode; it may be called at any time (like @ref WGPUCallbackMode_AllowSpontaneous). As such, calls into the `webgpu.h` API from this callback are unsafe. See @ref CallbackReentrancy.
type: callback.uncaptured_error
- name: extent_3D
doc: |
Expand Down
Loading