Repository navigation
vehicle_time: Deliver VehicleClock callbacks from a worker thread - #215
Conversation
License Check Results🚀 The license check job ran with the Bazel command: bazel run //:license-checkStatus: Click to expand output |
d4f4e67 to
143d1fb
Compare
143d1fb to
d447876
Compare
d447876 to
a816147
Compare
c811e27 to
041c9b8
Compare
041c9b8 to
4448f49
Compare
4448f49 to
756eaad
Compare
756eaad to
28b62ff
Compare
e5731ec to
150c89a
Compare
| const auto status_flags = ConvertPtpStatus(snapshot.value().status); | ||
| score::cpp::ignore = | ||
| status_slot_.InvokeIfChanged(status_flags, VehicleTimeStatus{status_flags, snapshot.value().rate_deviation}); | ||
| score::cpp::ignore = sync_data_slot_.TryDeliverChangedData(ConvertSyncData(snapshot.value().sync_fup_data)); |
There was a problem hiding this comment.
why do we need still to ignore the result?
regarding the returning result.
I think, the point, the callback was executed or nto is indeed not interesting.
but if the callback will return some result and we can react on it - that might be interesting.
but do we need this thing?
one of the use case - the callback could return if the registration shall still be hold.
so, if it will return true - continue calling it, false - drop the subscription.
if not, I would propose to drop the return at all.
There was a problem hiding this comment.
Return dropped.
|
|
||
| void SvtCallbackDispatcher::PollAndDispatch() noexcept | ||
| { | ||
| const auto snapshot = svt_receiver_->Receive(); |
There was a problem hiding this comment.
then we need to investigate before we will merge it
| template <typename Timebase> | ||
| bool IsSameForDelivery(const TimeSlaveSyncData<Timebase>& first, const TimeSlaveSyncData<Timebase>& second) noexcept | ||
| { | ||
| const bool same_precise_origin_timestamp = (first.precise_origin_timestamp == second.precise_origin_timestamp); |
There was a problem hiding this comment.
why the default instantiation doesn't fit here?
There was a problem hiding this comment.
Implemented operator==
| bool IsSameForDelivery(const PDelayMeasurementData<Timebase>& first, | ||
| const PDelayMeasurementData<Timebase>& second) noexcept | ||
| { | ||
| const bool same_request_origin_timestamp = (first.request_origin_timestamp == second.request_origin_timestamp); |
There was a problem hiding this comment.
why the default instantiation doesn't fit here?
There was a problem hiding this comment.
Implemented operator==
| /// @brief Thread-safe holder for a single move-only callback that is invoked from a dedicated worker thread | ||
| /// @brief Delivery comparison for types that already provide @c operator==. | ||
| template <typename Value> | ||
| bool IsSameForDelivery(const Value& first, const Value& second) noexcept |
There was a problem hiding this comment.
Not sure, I can understand the function name
There was a problem hiding this comment.
Changed to IsSame
| /// @return @c true if the callback was invoked, @c false if none is installed or @p data is unchanged. | ||
| template <typename Argument> | ||
| bool InvokeIfChanged(const Data& data, const Argument& argument) noexcept | ||
| bool TryDeliverChangedData(const Data& data) noexcept |
There was a problem hiding this comment.
is it a delivery?
Maybe TryToEnvoke() or somehting?
also the user of this function doesn't know, what the "new" data is.
he jsut has the "data"
There was a problem hiding this comment.
Renamed to TryToEnvoke
| std::recursive_mutex mutex_; | ||
| std::shared_ptr<Callback> callback_{}; | ||
| std::optional<Data> last_data_{}; | ||
| // Mirrors callback_ != nullptr. Written only under mutex_, read lock-free by IsSet(). |
There was a problem hiding this comment.
I don't think, we need this comment
22c6f71 to
0eee42c
Compare
|
Documentation preview for this pull request is available at: |
| // No write was in progress when the copy started and none started since | ||
| if (exit_cnt_before_read == entry_cnt_after_read) | ||
| // Even: no write in progress | ||
| if ((seq_before_read & 1U) == 0U) |
There was a problem hiding this comment.
Create a very small, tiny but self-explaining function.
you will not need the comment then.
| { | ||
| return read_data; | ||
| // Copy the payload | ||
| read_data = shared_memory_data_->data_; |
There was a problem hiding this comment.
Shall we set something another atomic variable to block the writer for moment here?
or it wil l be anyway compensated by +1 and +2 done by writer?
There was a problem hiding this comment.
The counter does the job: An in-progress write makes it odd and a complete write makes it even again. So the reader's final check fails and it retries. A lock would make the writer wait on slow readers.
What still remeins is a data race. The reader and the writer could still access the same memory location at the same time. This is undefined behavior. But we should solve this issue in a dedicated ticket.
| shared_memory_data_->seq_.store(seq + 1U, std::memory_order_relaxed); | ||
|
|
||
| // Copy the non-atomic payload | ||
| // Copy the payload |
There was a problem hiding this comment.
do we need this comment?
There was a problem hiding this comment.
I can remove it
| wakeup_requested_ = true; | ||
| StartWorkerIfReadyLocked(); | ||
| // Also delivers the first snapshot promptly to a fresh registration instead of after a full poll interval. | ||
| worker_wakeup_.notify_all(); |
There was a problem hiding this comment.
if the thread doesn't wait for itright now, the even will be missed
There was a problem hiding this comment.
Yes notify_all() is lost when nothing is waiting, but the callback registration already happened in SetCallback and with the next poll the value will be delivered. The notify_all() here is for waking up the thread if it is currently waiting.
The Set/Unset callback methods of VehicleClockBackendImpl were no-ops. Callbacks are now delivered by a worker thread that polls the TimeDaemon shared memory every 50 ms: - The thread starts with the first registered callback after Init() and runs until the backend is destroyed. While no callback is registered it sleeps. - A callback receives the first snapshot polled after its registration and afterwards only changes of its part of the snapshot: TimeSlaveSyncData and PDelayMeasurementData on any change, VehicleTimeStatus only when the flags change (rate deviation excluded). - Set/Unset are safe against in-flight invocations, also from inside a callback; Unset returns only after a running invocation finished. Add unit tests, update the docs and remove the "not yet delivered" warnings. Refs eclipse-score#59 Signed-off-by: Florian Füller <5454068+florianfueller@users.noreply.github.com>
The Set/Unset callback methods of VehicleClockBackendImpl were no-ops.
Callbacks are now delivered by a worker thread that polls the
TimeDaemon shared memory every 50 ms:
and runs until the backend is destroyed. While no callback is
registered it sleeps.
and afterwards only changes of its part of the snapshot:
TimeSlaveSyncData and PDelayMeasurementData on any change,
VehicleTimeStatus only when the flags change (rate deviation
excluded).
callback; Unset returns only after a running invocation finished.
Add unit tests, update the docs and remove the "not yet delivered"
warnings.
closes #59 (improvement ticket)