This page contains a set of principles and rules that Fuchsia follows when defining C APIs in the driver runtime. Fuchsia is more opinionated for these APIs, compared to others, because they are a significant part of the driver ABI.
Naming
- APIs should follow the Zircon syscall naming convention of
<subject>_<verb>[_<object>]
.- In the API example of
fdf_dispatcher_get_options
, the subject isdispatcher
, the verb isget
, and the object isoptions
. - However, not all APIs have an object. In certain cases, the object may be an adverb
(for instance,
fdf_channel_wait_async
). - Test-only and APIs for the embedding environment APIs refer to global singleton objects.
- In the API example of
- APIs must start with the
fdf_
prefix.- Test-only APIs must start with the
fdf_testing_
prefix. - APIs meant for the embedding environment must start with the
fdf_env_
prefix.
- Test-only APIs must start with the
- Output parameters must start with the
out_
prefix.
Threading
- APIs should indicate whether they are blocking or not blocking in comment blocks.
- Blocking APIs must validate that they are invoked in the context of a driver runtime
dispatcher, which has the
FDF_DISPATCHER_OPTION_ALLOW_SYNC_CALLS
option specified.- However,
zx_futex_wait
andzx_futex_requeue
are exceptions to this rule because they cannot block on state external to the driver, which avoids risk of a deadlock outside of the control of the driver author.
- However,
- APIs must be thread-safe.
- While they may return error when called in the incorrect dispatcher context, they should never act in an undefined manner.
- APIs that take in a callback should provide synchronous cancellation semantics1
in the context of a synchronized2 driver runtime dispatcher.
- Asynchronous cancellation should result in the callback being called, possibly with an error status signaling forward progress was forced and the normal condition for triggering the callback was not met.
- An API should never supply conditionally synchronous or asynchronous cancellation based on anything other than the type of dispatcher that the callback was registered against.
Objects
- APIs that create objects must have a corresponding API to destroy those objects.
- APIs that return created objects should return an opaque pointer to the object and not describe the internal structure of the object.
- APIs that create objects should take in a
uint32_t options
parameter with an extensible set of bit flags for extensibility.
Parameters
- APIs should take in all non-primitive parameters by pointer.
- APIs that take in a client-allocated parameter that outlives the function call itself must do
the following:
- Take full ownership of the object, and any other objects it refers to if they are not self-referential (that is, also contained in the same allocation).
- Supply a mechanism (such as a callback parameter) to return the object to the caller.
- Provide a cancellation mechanism to proactively return the object to the caller before it would normally be returned.
- Provide a mechanism to allow the client to use a single allocation to inline additional client-specific context after the object.
- Strings should not be assumed to be null terminated nor have “static” lifetimes.
- Callback parameters should be aliased to a new type by using
typedef
. - Callback parameters should be embedded in a
struct
to ensure they can be stored in a single allocation.
Miscellaneous
- APIs should have a comment block describing their purpose, parameters, outputs, and
possible errors.
- Examples are optional but recommended.
- Comment blocks must use Markdown syntax, which is conducive to generating web-based documentation.
- APIs must be “memory tight” – in other words, memory allocated by the runtime must be
freed by the runtime and memory allocated by the client must be freed by the client.
- An exception to this rule is allowed for arenas.
- APIs should prefer to return errors rather than assert if invoked incorrectly (for instance, on the wrong dispatcher with invalid parameters).
- Test-only APIs must be available only in the context of tests.
- Environment-only APIs must be available only to the environment in which the driver runs, not the driver itself.
-
Synchronous cancellation semantics mean that when the cancellation function call returns, it is guaranteed that the callback will no longer be called. Either it was already called and cannot be canceled, or was canceled successfully. ↩
-
A synchronized dispatcher is constructed via
fdf_dispatcher_create
when theFDF_DISPATCHER_OPTION_UNSYNCHRONIZED
option is not specified. ↩