Skip to content

clock_settime: don't block when up_rtc_settime is called#18816

Merged
linguini1 merged 1 commit intoapache:masterfrom
michallenc:rtc-lpwork
Apr 28, 2026
Merged

clock_settime: don't block when up_rtc_settime is called#18816
linguini1 merged 1 commit intoapache:masterfrom
michallenc:rtc-lpwork

Conversation

@michallenc
Copy link
Copy Markdown
Contributor

Summary

Setting the current time in RTC may be a blocking operation (driver needs to wait for oscillator stabilization after reset and so on). This may cause the unwanted effect of clock_settime blocking the code execution for a considerable amount of time.

The solution is to plan a low priority work that takes care of setting the time in RTC and let clock_settime continue. We don't have to check if the work is available, just cancel it if there is a new time set request.

This is used only if CONFIG_SCHED_LPWORK is enabled. I was thinking about putting this under a special separate config option, but it seems like something you always want if you have LPWORK - but feel free to suggest otherwise, I am not against creating an option solely for this.

Impact

clock_settime now shouldn't block the code execution.

Testing

We encountered this with mcp794xx RTC - the controller waits until the oscillator is started, which may take tens of milliseconds (we measured up to ~40 ms on oscilloscope delay). This caused issue in a customer's custom protocol implementation - we receive the current time, set it and response with status message - but there were timeouts in the communication if time was set.

The issue no longer occurs if RTC set time is done in a separate work thread as clock_settime doesn't block.

@github-actions github-actions Bot added Area: OS Components OS Components issues Size: S The size of the change in this PR is small labels Apr 28, 2026
@michallenc michallenc changed the title clock_settime: don't block when up_rtc_settime is call clock_settime: don't block when up_rtc_settime is called Apr 28, 2026
jerpelea
jerpelea previously approved these changes Apr 28, 2026
Comment thread sched/clock/clock_settime.c Outdated
Setting the current time in RTC may be a blocking operation (driver
needs to wait for oscillator stabilization after reset and so on).
This may cause the unwanted effect of clock_settime blocking the
code execution for a considerable amount of time.

The solution is to plan a low priority work that takes care
of setting the time in RTC and let clock_settime continue. We don't
have to check if the work is available, just cancel it if there
is a new time set request.

This is used only if CONFIG_SCHED_LPWORK is enabled.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
@linguini1
Copy link
Copy Markdown
Contributor

Seems fine! Would this cause issues with getting the clock time after the set though? Where the caller might expect the time to be set correctly once the caller returns?

Can this issue be fixed by performing the call in a worker thread at the application level, instead of in the kernel?

@michallenc
Copy link
Copy Markdown
Contributor Author

Seems fine! Would this cause issues with getting the clock time after the set though? Where the caller might expect the time to be set correctly once the caller returns?

Can this issue be fixed by performing the call in a worker thread at the application level, instead of in the kernel?

You still get the correct time after the set, because the read with clock_gettime is performed from system clock, not from RTC. The user won't have the confirmation the write to RTC was done, but he can't rely on it now neither as we don't handle possible error from up_rtc_settime - we can't, it would violate POSIX interface of clock_settime. So even now successful clock_settime doesn't mean RTC was written.

The entire RTC clock setting is unfortunately not standardized and platform specific. Linux for example has a specific IOCTL or you can configure periodic writes to RTC if I remember it correctly, but it doesn't change it on clock_settime.

It can be fixed at the application level, but that is fixing the kernel problem from the app instead of fixing it in the kernel. And I think this is kernel issue because clock_settime shouldn't block. I am ok with adding new config option that would not make the proposed behavior default but only if user selects it if you prefer.

@linguini1
Copy link
Copy Markdown
Contributor

You still get the correct time after the set, because the read with clock_gettime is performed from system clock, not from RTC. The user won't have the confirmation the write to RTC was done, but he can't rely on it now neither as we don't handle possible error from up_rtc_settime - we can't, it would violate POSIX interface of clock_settime. So even now successful clock_settime doesn't mean RTC was written.

The entire RTC clock setting is unfortunately not standardized and platform specific. Linux for example has a specific IOCTL or you can configure periodic writes to RTC if I remember it correctly, but it doesn't change it on clock_settime.

It can be fixed at the application level, but that is fixing the kernel problem from the app instead of fixing it in the kernel. And I think this is kernel issue because clock_settime shouldn't block. I am ok with adding new config option that would not make the proposed behavior default but only if user selects it if you prefer.

This explanation makes a lot of sense, I think that fixing in the kernel and having it as default behavior is fine!

Copy link
Copy Markdown
Contributor

@cederom cederom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @michallenc :-)

@linguini1 linguini1 merged commit 7dc6be8 into apache:master Apr 28, 2026
41 checks passed
*/

g_rtc_to_set = *tp;
work_queue(LPWORK, &g_rtc_work, rtc_worker,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but in a busy system, lp work mayn't schedule for while, how to handle the time drift. @michallenc
if caller really care the blocking, it's better let caller call clock_settime in the background thread.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but blocking for 30 ms is also not correct. The user can choose higher priority for lp work if the system is really busy and preempt other not so important tasks. Most RTCs store time in seconds, so the write would have to be significantly delayed to show any time drift.

I don't really see other good solution here, except from removing RTC set from clock_settime and having a separate API like Linux.

Copy link
Copy Markdown
Contributor

@xiaoxiang781216 xiaoxiang781216 Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but blocking for 30 ms is also not correct. The user can choose higher priority for lp work if the system is really busy and preempt other not so important tasks. Most RTCs store time in seconds, so the write would have to be significantly delayed to show any time drift.

it's depends on hardware, nuttx even has the code to support the high res RTC(CONFIG_RTC_HIRES).

I don't really see other good solution here, except from removing RTC set from clock_settime and having a separate API like Linux.

you can update RTC through /dev/rtcx.

BT, timespec has two fields, the second clock_settime may corrupt the setting in the work thread.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can update RTC through /dev/rtcx.

That's what I would prefer in a long term, but that would mean removing up_rtc_settime from clock_settime, which would break many applications that rely on this behavior. And we would have to rewrite some RTC drivers to actually register a device driver.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can update RTC through /dev/rtcx.

That's what I would prefer in a long term, but that would mean removing up_rtc_settime from clock_settime, which would break many applications that rely on this behavior.

And we would have to rewrite some RTC drivers to actually register a device driver.

you can utilize arch_rtc which could simplify the code a lot:
https://github.com/apache/nuttx/blob/master/drivers/timers/arch_rtc.c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: OS Components OS Components issues Size: S The size of the change in this PR is small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants