| // Copyright 2019 The Fuchsia Authors |
| // |
| // Use of this source code is governed by a MIT-style |
| // license that can be found in the LICENSE file or at |
| // https://opensource.org/licenses/MIT |
| |
| #include <lib/affine/ratio.h> |
| #include <lib/affine/transform.h> |
| #include <lib/arch/intrin.h> |
| #include <lib/counters.h> |
| #include <zircon/errors.h> |
| #include <zircon/rights.h> |
| #include <zircon/syscalls/clock.h> |
| |
| #include <fbl/alloc_checker.h> |
| #include <object/clock_dispatcher.h> |
| |
| KCOUNTER(dispatcher_clock_create_count, "dispatcher.clock.create") |
| KCOUNTER(dispatcher_clock_destroy_count, "dispatcher.clock.destroy") |
| |
| namespace { |
| |
| inline zx_clock_transformation_t CopyTransform(const affine::Transform& src) { |
| return {src.a_offset(), src.b_offset(), {src.numerator(), src.denominator()}}; |
| } |
| |
| } // namespace |
| |
| zx_status_t ClockDispatcher::Create(uint64_t options, const zx_clock_create_args_v1_t& create_args, |
| KernelHandle<ClockDispatcher>* handle, zx_rights_t* rights) { |
| // The syscall_ layer has already parsed our args version and extracted them |
| // into our |create_args| argument as appropriate. Go ahead and discard the |
| // version information before sanity checking the rest of the options. |
| options &= ~ZX_CLOCK_ARGS_VERSION_MASK; |
| |
| // Reject any request which includes an options flag we do not recognize. |
| if (~ZX_CLOCK_OPTS_ALL & options) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| // If the user asks for a continuous clock, it must also be monotonic |
| if ((options & ZX_CLOCK_OPT_CONTINUOUS) && !(options & ZX_CLOCK_OPT_MONOTONIC)) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| // Make sure that the backstop time is valid. If this clock is being created |
| // with the "auto start" flag, then it begins life as a clone of clock |
| // monotonic, and the backstop time has to be <= the current clock monotonic |
| // value. Otherwise, the clock starts in the stopped state, and any specified |
| // backstop time must simply be non-negative. |
| // |
| if (((options & ZX_CLOCK_OPT_AUTO_START) && (create_args.backstop_time > current_time())) || |
| (create_args.backstop_time < 0)) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| fbl::AllocChecker ac; |
| KernelHandle clock(fbl::AdoptRef(new (&ac) ClockDispatcher(options, create_args.backstop_time))); |
| if (!ac.check()) { |
| return ZX_ERR_NO_MEMORY; |
| } |
| |
| *rights = default_rights(); |
| *handle = ktl::move(clock); |
| return ZX_OK; |
| } |
| |
| ClockDispatcher::ClockDispatcher(uint64_t options, zx_time_t backstop_time) |
| : options_(options), |
| backstop_time_(backstop_time), |
| mono_to_synthetic_{0, backstop_time, {0, 1}}, |
| ticks_to_synthetic_{0, backstop_time, {0, 1}} { |
| // If this clock is created with the "auto start" flag, set the clock up to |
| // initially be a clone of clock monotonic instead of being in an undefined |
| // (non-started) state. |
| if (options & ZX_CLOCK_OPT_AUTO_START) { |
| ZX_DEBUG_ASSERT(backstop_time <= current_time()); // This should have been checked by Create |
| affine::Ratio ticks_to_mono_ratio = platform_get_ticks_to_time_ratio(); |
| mono_to_synthetic_ = {0, 0, {1, 1}}, |
| ticks_to_synthetic_ = { |
| 0, 0, {ticks_to_mono_ratio.numerator(), ticks_to_mono_ratio.denominator()}}; |
| UpdateState(0, ZX_CLOCK_STARTED); |
| } |
| |
| kcounter_add(dispatcher_clock_create_count, 1); |
| } |
| |
| ClockDispatcher::~ClockDispatcher() { kcounter_add(dispatcher_clock_destroy_count, 1); } |
| |
| zx_status_t ClockDispatcher::Read(zx_time_t* out_now) { |
| int64_t now_ticks; |
| affine::Transform ticks_to_synthetic; |
| |
| while (true) { |
| // load the generation counter. If it is odd, we are in the middle of |
| // an update and need to wait. Just spin; the update operation (once |
| // started) is non-preemptable and will be done very shortly. |
| auto gen = gen_counter_.load(ktl::memory_order_acquire); |
| if ((gen & 0x1) == 0) { |
| // Latch the transformation and observe the tick counter. |
| ticks_to_synthetic = ticks_to_synthetic_; |
| now_ticks = current_ticks(); |
| |
| // If the generation counter has not changed, then we are done. |
| // Otherwise, we need to start over. |
| if (gen == gen_counter_.load(ktl::memory_order_acquire)) { |
| break; |
| } |
| } |
| |
| // Pause just a bit before trying again. |
| arch::Yield(); |
| } |
| |
| *out_now = ticks_to_synthetic.Apply(now_ticks); |
| |
| return ZX_OK; |
| } |
| |
| zx_status_t ClockDispatcher::GetDetails(zx_clock_details_v1_t* out_details) { |
| while (true) { |
| // load the generation counter. If it is odd, we are in the middle of |
| // an update and need to wait. Just spin; the update operation (once |
| // started) is non-preemptable and will be done very shortly. |
| auto gen = gen_counter_.load(ktl::memory_order_acquire); |
| if ((gen & 0x1) == 0) { |
| // Latch the detailed information. |
| out_details->generation_counter = gen; |
| out_details->ticks_to_synthetic = CopyTransform(ticks_to_synthetic_); |
| out_details->mono_to_synthetic = CopyTransform(mono_to_synthetic_); |
| out_details->error_bound = error_bound_; |
| out_details->query_ticks = current_ticks(); |
| out_details->last_value_update_ticks = last_value_update_ticks_; |
| out_details->last_rate_adjust_update_ticks = last_rate_adjust_update_ticks_; |
| out_details->last_error_bounds_update_ticks = last_error_bounds_update_ticks_; |
| |
| // If the generation counter has not changed, then we are done. |
| // Otherwise, we need to start over. |
| if (gen == gen_counter_.load(ktl::memory_order_acquire)) { |
| break; |
| } |
| |
| // Pause just a bit before trying again. |
| arch::Yield(); |
| } |
| } |
| |
| // Options and backstop_time are constant over the life of the clock. We |
| // don't need to latch them during the generation counter spin. |
| out_details->options = options_; |
| out_details->backstop_time = backstop_time_; |
| |
| return ZX_OK; |
| } |
| |
| zx_status_t ClockDispatcher::Update(uint64_t options, const zx_clock_update_args_v1_t& args) { |
| const bool do_set = options & ZX_CLOCK_UPDATE_OPTION_VALUE_VALID; |
| const bool do_rate = options & ZX_CLOCK_UPDATE_OPTION_RATE_ADJUST_VALID; |
| |
| // if this is a set operation, and we are trying to set the time to something |
| // before the backstop, just deny the operation. The backstop time is a fixed |
| // property of the clock determined at creation time; we don't need to even |
| // enter into the writer lock to know that this is an illegal operation. |
| if (do_set && (args.value < backstop_time_)) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| bool clock_was_started = false; |
| { |
| // Enter the writer lock. Only one update can take place at a time. We use |
| // an IrqSave spinlock for this because this operation should be very quick, |
| // and we may have observers who are spinning attempting to read the clock. |
| // We cannot afford to become preempted while we are performing an update |
| // operation. |
| Guard<SpinLock, IrqSave> writer_lock{&writer_lock_}; |
| |
| // If the clock has not yet been started, then we require the first update |
| // to include a set operation. |
| if (!do_set && !is_started()) { |
| return ZX_ERR_BAD_STATE; |
| } |
| |
| // Continue with the argument sanity checking. Set operations are not |
| // allowed on continuous clocks after the very first one (which is what |
| // starts the clock). |
| if (do_set && is_continuous() && is_started()) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| // Bump the generation counter. This will disable all read operations until |
| // we bump the counter again. |
| // |
| // We should only need release semantics here. Only things which hold the |
| // writer spin-lock can make changes to the generation counter, and acquiring |
| // that spin-lock should serve as our acquire barrier. |
| auto prev_counter = gen_counter_.fetch_add(1, ktl::memory_order_release); |
| ZX_DEBUG_ASSERT((prev_counter & 0x1) == 0); |
| int64_t now_ticks = static_cast<int64_t>(current_ticks()); |
| |
| // Are we updating the transformations at all? |
| if (do_set || do_rate) { |
| int64_t now_synthetic; |
| |
| // Figure out the new synthetic offset |
| if (do_set) { |
| // We are performing a set operation. If this clock is started and |
| // monotonic, and the set operation would result in non-monotonic |
| // behavior for the clock, disallow it. |
| if (is_started() && is_monotonic()) { |
| int64_t now_clock = ticks_to_synthetic_.Apply(now_ticks); |
| if (args.value < now_clock) { |
| // turns out we are not going to make any changes to the clock. |
| // Put the generation counter back to where it was. |
| gen_counter_.store(prev_counter, ktl::memory_order_release); |
| return ZX_ERR_INVALID_ARGS; |
| } |
| } |
| |
| // Because this is a set operation, now on the synthetic timeline is |
| // what the user has specified. |
| now_synthetic = args.value; |
| last_value_update_ticks_ = now_ticks; |
| |
| // We are past the point where this update can fail. All of our |
| // parameters have been sanity checked, including the monotonic check |
| // which can only be performed while we are holding off readers using |
| // the generation counter. At this point, because we are performing a |
| // set operation, we are starting the clock if it was not already |
| // started. |
| clock_was_started = !is_started(); |
| } else { |
| // Looks like we are updating the rate, but not explicitly setting the |
| // clock. Make sure that the offsets we choose for the new affine |
| // transformation result in it being 1st order continuous with the |
| // previous transformation. The simple way to do this is to choose the |
| // reference time at which the change is taking place (now_ticks) as the |
| // first offset, and the same value transformed by the previous |
| // transformation as the second (synthetic) offset. By definition, this |
| // point marks the point at which the previous transformation's domain |
| // ended and the new one started, and must exist on the line defined by |
| // both transformations. |
| now_synthetic = ticks_to_synthetic_.Apply(now_ticks); |
| } |
| |
| // Figure out the new rates. |
| affine::Ratio ticks_to_mono_ratio = platform_get_ticks_to_time_ratio(); |
| affine::Ratio mono_to_synthetic_rate; |
| affine::Ratio ticks_to_synthetic_rate; |
| bool skip_update = false; |
| |
| if (do_rate) { |
| // We want to explicitly update the rate. Encode the PPM adjustment |
| // as a ratio, then compute the ticks_to_synthetic_rate. |
| // |
| // If the PPM adjustment being applied is identical to the last |
| // adjustment being applied, then don't bother to recompute these. Just |
| // use the rates we already have. |
| if (do_set || args.rate_adjust != cur_ppm_adj_) { |
| mono_to_synthetic_rate = {static_cast<uint32_t>(1000000 + args.rate_adjust), 1000000}; |
| ticks_to_synthetic_rate = ticks_to_mono_ratio * mono_to_synthetic_rate; |
| cur_ppm_adj_ = args.rate_adjust; |
| } else { |
| mono_to_synthetic_rate = mono_to_synthetic_.ratio(); |
| ticks_to_synthetic_rate = ticks_to_synthetic_.ratio(); |
| |
| // If our rate is being "adjusted" to the same thing that it already |
| // was, and we are not updating the position at all, then we can just |
| // go ahead and skip the update of the transformation equations (even |
| // though we will record the time of this update as the last rate |
| // adjustment time). See fxbug.dev/57593 |
| skip_update = true; |
| } |
| last_rate_adjust_update_ticks_ = now_ticks; |
| } else if (!is_started()) { |
| // The clock has never been started, then the default rate is 1:1 |
| // with the mono reference. |
| mono_to_synthetic_rate = {1, 1}; |
| ticks_to_synthetic_rate = ticks_to_mono_ratio; |
| last_rate_adjust_update_ticks_ = now_ticks; |
| } else { |
| // Otherwise, preserve the existing rate. |
| mono_to_synthetic_rate = mono_to_synthetic_.ratio(); |
| ticks_to_synthetic_rate = ticks_to_synthetic_.ratio(); |
| } |
| |
| // Now, simply update the transformations with the proper offsets and |
| // the calculated rates. |
| if (!skip_update) { |
| zx_time_t now_mono = ticks_to_mono_ratio.Scale(now_ticks); |
| mono_to_synthetic_ = {now_mono, now_synthetic, mono_to_synthetic_rate}; |
| ticks_to_synthetic_ = {now_ticks, now_synthetic, ticks_to_synthetic_rate}; |
| } |
| } |
| |
| // If we are supposed to update the error bound, do so. |
| if (options & ZX_CLOCK_UPDATE_OPTION_ERROR_BOUND_VALID) { |
| error_bound_ = args.error_bound; |
| last_error_bounds_update_ticks_ = now_ticks; |
| } |
| |
| // We are finished. Update the generation counter to allow clock reading again. |
| gen_counter_.store(prev_counter + 2, ktl::memory_order_release); |
| } |
| |
| // Now that we are out of the time critical section, if the clock was just |
| // started, make sure to assert the ZX_CLOCK_STARTED signal to observers. |
| if (clock_was_started) { |
| UpdateState(0, ZX_CLOCK_STARTED); |
| } |
| |
| return ZX_OK; |
| } |