Hosted Physical Clocks
Use an externally advanced clock when a simulator or another driver supplies physical time for a local deployment. Without a clock selection, Boomerang uses the host’s monotonic clock. Every Enclave in the selected Federate observes the same externally supplied time.
Deployment configuration
Add a physical-clock table to the hosted Federate in your Boomerang.toml:
[deployments.production.federates.host.physical-clock]
domain = 7
binding = "sensor"
entry = "drive_clock"
This fragment extends an existing deployment. The host Federate must use the
std runtime, and sensor must already name a payload binding under
deployments.production.bindings.
domainidentifies the physical clock domain shared by the driver and its data.bindingselects the payload package containing the driver.entrynames the driver function relative to that package’s crate root.
Generated launchers enable the runtime’s external-clock feature. A payload
package that directly uses clock APIs must also enable that feature on its
boomerang_runtime dependency.
The clock-only driver receives a boomerang_runtime::clock::ManualClock and
returns Result<Guard, E>. The launcher retains the returned guard throughout
execution. The driver must return after advancing time or starting its own
advancement mechanism; blocking inside the entry function prevents scheduler
startup. Keep a clone of the clock in the driver to advance it during execution.
Clock selection, domain, and driver configuration participate in generated artifact fingerprints. The runtime creates a fresh execution identity for each run; that identity does not change the artifact fingerprint.
Driving time
PhysicalInstant is a point on the selected physical clock’s timeline, much like
std::time::Instant is a point on the host monotonic clock. Its coordinate is
nanoseconds since this execution’s physical epoch; zero is the epoch origin.
Compare values only within the same clock domain and execution epoch. Adapters
carry those identities separately; the numeric timestamp cannot validate them.
Use Duration for elapsed intervals and delays, and PhysicalInstant::checked_add
to compute a later time without advancing the clock.
Reaction and send contexts expose the selected timeline through
try_get_physical_time() -> Result<PhysicalInstant, PhysicalClockError>.
Physical events and asynchronous action scheduling use the same coordinates;
manual time does not need to fit the host’s std::time::Instant representation.
A native send context created before execution returns NotStarted until its
scheduler starts. Start external producers from a startup reaction, or call
Scheduler::startup() before signaling a producer that the scheduler is ready.
Use SendContext::prepare_action to handle this error before sending.
Call PreparedAction::send for blocking delivery or try_send for nonblocking delivery.
Context::get_start_time() returns the epoch coordinate, zero.
try_get_logical_time() projects the current logical offset into a
PhysicalInstant, returning an error if it is outside the physical range.
get_elapsed_logical_time() and get_tag() retain the full signed logical range.
Use std::time::Instant independently for host watchdogs and elapsed run timing.
Call advance_to(PhysicalInstant(n)) with unsigned nanoseconds since the start
of this execution. Equal timestamps are accepted, and forward jumps are allowed.
Timers due within a jump still execute in logical-tag order, so a large jump can
produce a burst of work. Moving time backwards fails the run. close and fail
terminate the clock and release waiting execution.
fast_forward bypasses waiting for physical time. Reactions and physical actions
still read the selected clock, so enable it only when that separation is intended.
Use the host monotonic clock for driver watchdogs and connection timeouts.
Physical events arriving behind completed logical work move to a later microstep. Multiple physical values for an action at the same offset retain separate microsteps. Time or microstep overflow produces an error.
Supported deployments
External clock selection currently supports one local hosted Federate, which can
contain multiple Enclaves. Non-host targets, custom target JSON, non-std
runtimes, and distributed clock configuration are rejected. Simulator stepping,
device decoding, and transport belong to the driver or adapter.
See the clock API documentation for programmatic binding, checked context APIs, and runtime implementation details.