Make adjustments to a clock object.
#include <zircon/syscalls.h> zx_status_t zx_clock_update(zx_handle_t handle, uint64_t options, const void* args);
handle must be of type ZX_OBJ_TYPE_CLOCK and have ZX_RIGHT_WRITE.
Three different parameters may be dynamically controlled by a clock maintainer. They are
When a clock maintainer wishes to change one or more of these parameters, they may do so using the zx_clock_update
syscall. Updating a clock's parameters is an atomic operation from the perspective of all other users in the system.
The first update operation performed by a clock maintainer must include a valid value. This update is the update that starts the clock and defines its initial value. Before this update operation has succeeded, the ZX_CLOCK_STARTED signal will be de-asserted, and afterwards it will be asserted and remain so for the lifetime of the clock.
In order to update a clock, a user fills out the fields of a zx_clock_update_args_v2_t
structure that they wish to adjust, then passes the structure to the update call, setting the bits in options
which indicate both the explicit version of the structure (version 2), and which of these fields are valid and should be set. Defined options
bits are
The version of the structure is passed using the ZX_CLOCK_ARGS_VERSION(...)
macro, specifically ZX_CLOCK_ARGS_VERSION(2)
for the version 2 structure.
For example
#include <zircon/syscalls.h> #include <zircon/syscalls/clock.h> void MaintainMyClock(zx_handle_t the_clock) { zx_clock_update_args_v2_t args; zx_status_t status; // Set the clock's value to 1500. Note that this also starts the clock. args.synthetic_value = 1500; status = zx_clock_update(the_clock, ZX_CLOCK_ARGS_VERSION(2) | ZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID, &args); if (status != ZX_OK) { // Panic! return; } // Make the clock run 23 PPM slower than nominal relative to clock monotonic. args.rate_adjust = -23; status = zx_clock_update(the_clock, ZX_CLOCK_ARGS_VERSION(2) | ZX_CLOCK_UPDATE_OPTION_RATE_ADJUST_VALID, &args); if (status != ZX_OK) { // Halt and catch fire return; } // Set the clock to 100,000, make it run 50 PPM faster than nominal, and specify an error bound of // +/- 400mSec, all at the same time. const uint64_t options = ZX_CLOCK_ARGS_VERSION(2) | ZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID | ZX_CLOCK_UPDATE_OPTION_RATE_ADJUST_VALID | ZX_CLOCK_UPDATE_OPTION_ERROR_BOUND_VALID; args.synthetic_value = 100000; args.rate_adjust = 50; args.error_bound = ZX_MSEC(400); status = zx_clock_update(the_clock, options, &args); if (status != ZX_OK) { // Burn down, fall over, and then sink into the swamp. return; } }
With the addition of the V2 update structure, it is now possible (with some limitations) to explicitly control the reference time used for a clock update operation. Note that, upon success, the actual new reference <-> synthetic transformation specified by the user's update arguments will replace the old transformation during the call to zx_clock_update
. Supplying an explicit reference time does not affect when the actual transformation is updated, it will always take effect during the call to zx_clock_update
.
Diagrams provided in RFC-0077 may help to understand the effects of the operations described below.
When users update the synthetic value (S
) of a clock with an explicitly provided reference time (R
), they are specifying a point ([R, S]
) through which the new transformation will pass. In other words, the new transformation explicitly specifies that “when it is time R on the reference timeline, it will be time S on the synthetic timeline”.
#include <zircon/syscalls.h> #include <zircon/syscalls/clock.h> // Set the syntheic value of the clock to be "synth" at the explicitly provided // reference time "ref". In other words, upon success, this update operation will // cause the clock's transformation from reference to synthetic time to // specifically pass through the point (ref, synth) zx_status_t SetSynthAtRef(zx_handle_t the_clock, zx_time_t ref, zx_time_t synth) { zx_clock_update_args_v2_t args; uint64_t options = ZX_CLOCK_ARGS_VERSION(2) | ZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALID | ZX_CLOCK_UPDATE_OPTION_SYNTHETIC_VALUE_VALID; // Note that these options are equivalent, they just use a shorthand to // specify that both values are valid. options = ZX_CLOCK_ARGS_VERSION(2) | ZX_CLOCK_UPDATE_OPTION_BOTH_VALUES_VALID; args.reference_value = ref; args.synthetic_value = synth; return zx_clock_update(the_clock, options, args); }
Let T(R)
be the function which transforms a reference time R
to a synthetic time for a clock before an update operation. When users adjust the rate of a clock with an explicitly provided reference time (R
), they are specifying the slope of the new transformation T'(R)
for the clock, such that T'(R) = T(R)
. In other words, at reference time R
, the new transformation will pass through the same synthetic time that the old transformation did, but with a different slope.
#include <zircon/syscalls.h> #include <zircon/syscalls/clock.h> zx_status_t SetRateAtRef(zx_handle_t the_clock, zx_time_t ref, int32_t ppm_adj) { zx_clock_update_args_v2_t args; const uint64_t options = ZX_CLOCK_ARGS_VERSION(2) | ZX_CLOCK_UPDATE_OPTION_REFERENCE_VALUE_VALID | ZX_CLOCK_UPDATE_OPTION_RATE_ADJUST_VALID; args.reference_value = ref; args.rate_adjust = ppm_adj; return zx_clock_update(the_clock, options, args); }
Details provided in RFC-0077 may help to understand the reasoning behind some of these rules and limitations.
On success, returns ZX_OK.