Topics

[RFC] Nanokernel timers rework proposal


Dmitriy Korovkin
 

Problem: there are two similar mechanisms in nanokernel: nano_timers and
nano_timeouts. In order to optimize codeand space it's better to have one
mechanism for both.

Proposal: Implement nano_timer through timeout mechanism. This aproach
allows to get rid of heavier nanokernel lifo component in favor of more
lightweight nanokernel timeout implementation.

The _nano_timeout structure gets two additional arguments: void
*user_data_ptr and bool expired, the flag that is set to true when the
timeout is expired.
_nano_timeout structure now can be safely renamed to nano_timer, as it
has everything required by nano_timer API.
In this case, if a function like fiber_sleep() is invoked, the
user_data_ptr is set to NULL.
For the nano_timer API user_data_ptr is used to store the user data
pointer. When the nano_timer_init() function is called, it gets the
_nano_timer structure and initializes it as before. On the
nano_timer_start() call the nano_timer structure is being added to the
sorted list via _nano_timeout_add() function.
nano_timer_test() checks the expired flag of the nano_timer structure.
if it is true, the function just returns the user_data_ptr, otherwise,
if the timeout_in_ticks is not TICKS_NONE, it puts the fiber or task to
sleep by calling _Swap().

Question: is it needed to wait for a specified timeout, if
timeout_in_ticks argument is neither TICKS_NONE nor TICKS_UNLIMITED?

_nano_timeout_handle_one_timeout(), in turn, sets the expired flag to
true and if fiber or task is waiting, marks it runnable.
fiberRtnValueSet is used to set the return value to user_data_ptr.


Problem: in microkernel system clock ticks are processed in the k_server
fiber, which does not allow using timeouts during the initialization
before k_server fiber starts.

In order to allow using timeouts during the system initialization
_do_sys_clock_tick_announce pointer has to be modified to point at the
_nano_sys_clock_tick_announce() until the microkernel _k_server() fiber
starts. This way the _do_sys_clock_tick_announce may be initialized as a
pointer to
_nano_sys_clock_tick_announce() routine by default.

This modification needs to be done with changing priority of the driver
initialization routines that use timeout. Such routines need to be
invoked not on PRIMARY, but on NANOKERNEL initialization level.

--
Dmitriy Korovkin


Benjamin Walsh <benjamin.walsh@...>
 

On Thu, Feb 25, 2016 at 03:54:03PM -0500, Dmitriy Korovkin wrote:
Problem: there are two similar mechanisms in nanokernel: nano_timers and
nano_timeouts. In order to optimize codeand space it's better to have one
mechanism for both.

Proposal: Implement nano_timer through timeout mechanism. This
aproach allows to get rid of heavier nanokernel lifo component in
favor of more lightweight nanokernel timeout implementation.

The _nano_timeout structure gets two additional arguments: void
*user_data_ptr and bool expired, the flag that is set to true when
the timeout is expired.
I don't think you need this expired flag: delta_ticks_from_prev is
either 0 or -1 when the timeout expires (-1 I think).

_nano_timeout structure now can be safely renamed to nano_timer, as
it has everything required by nano_timer API.
I would prefer if we had a nano_timer object that is a wrapper around a
_nano_timeout, so that not all timeouts in the system are impacted in
size by this.

struct nano_timer {
struct _nano_timeout timeout;
void *user_data;
};

In this case, if a function like fiber_sleep() is invoked, the
user_data_ptr is set to NULL.
For the nano_timer API user_data_ptr is used to store the user data
pointer. When the nano_timer_init() function is called, it gets the
_nano_timer structure and initializes it as before. On the
nano_timer_start() call the nano_timer structure is being added to
the sorted list via _nano_timeout_add() function.
nano_timer_test() checks the expired flag of the nano_timer
structure. if it is true, the function just returns the
user_data_ptr, otherwise, if the timeout_in_ticks is not TICKS_NONE,
it puts the fiber or task to sleep by calling _Swap().

Question: is it needed to wait for a specified timeout, if
timeout_in_ticks argument is neither TICKS_NONE nor TICKS_UNLIMITED?
No. We consider that you only want to verify if the timeout has expired
by polling, or you want to wait for it to expire, which has a itself a
timeout.

_nano_timeout_handle_one_timeout(), in turn, sets the expired flag
to true and if fiber or task is waiting, marks it runnable.
As stated above, I don't think you need the expired flag.

fiberRtnValueSet is used to set the return value to user_data_ptr.
I don't think you need to use fiberRtnValueSet: you will get the user
data back when you call nano_timer_test, which can just look in the
nano_timer object to retrieve the data.

Problem: in microkernel system clock ticks are processed in the
k_server fiber, which does not allow using timeouts during the
initialization before k_server fiber starts.

In order to allow using timeouts during the system initialization
_do_sys_clock_tick_announce pointer has to be modified to point at
the _nano_sys_clock_tick_announce() until the microkernel
_k_server() fiber starts. This way the _do_sys_clock_tick_announce
may be initialized as a pointer to
_nano_sys_clock_tick_announce() routine by default.

This modification needs to be done with changing priority of the
driver initialization routines that use timeout. Such routines need
to be invoked not on PRIMARY, but on NANOKERNEL initialization
level.
I don't have a problem with this part of the proposal.

Regards,
Ben

--
Benjamin Walsh, SMTS
Wind River Rocket
www.windriver.com
Zephyr kernel maintainer
www.zephyrproject.org


Dmitriy Korovkin
 

On 16-03-01 05:55 PM, Benjamin Walsh wrote:
On Thu, Feb 25, 2016 at 03:54:03PM -0500, Dmitriy Korovkin wrote:
Problem: there are two similar mechanisms in nanokernel: nano_timers and
nano_timeouts. In order to optimize codeand space it's better to have one
mechanism for both.

Proposal: Implement nano_timer through timeout mechanism. This
aproach allows to get rid of heavier nanokernel lifo component in
favor of more lightweight nanokernel timeout implementation.

The _nano_timeout structure gets two additional arguments: void
*user_data_ptr and bool expired, the flag that is set to true when
the timeout is expired.
I don't think you need this expired flag: delta_ticks_from_prev is
either 0 or -1 when the timeout expires (-1 I think).
Yes, after the timeout expires, delta_ticks_from_prev is -1. I agree, we
can check it and not use any flag.

_nano_timeout structure now can be safely renamed to nano_timer, as
it has everything required by nano_timer API.
I would prefer if we had a nano_timer object that is a wrapper around a
_nano_timeout, so that not all timeouts in the system are impacted in
size by this.

struct nano_timer {
struct _nano_timeout timeout;
void *user_data;
};
This can be implemented. In this case nano_timer_test() places the
nano_timeout part of the nano_timer structure in the list and call
_Swap(), if necessary.

In this case, if a function like fiber_sleep() is invoked, the
user_data_ptr is set to NULL.
For the nano_timer API user_data_ptr is used to store the user data
pointer. When the nano_timer_init() function is called, it gets the
_nano_timer structure and initializes it as before. On the
nano_timer_start() call the nano_timer structure is being added to
the sorted list via _nano_timeout_add() function.
nano_timer_test() checks the expired flag of the nano_timer
structure. if it is true, the function just returns the
user_data_ptr, otherwise, if the timeout_in_ticks is not TICKS_NONE,
it puts the fiber or task to sleep by calling _Swap().

Question: is it needed to wait for a specified timeout, if
timeout_in_ticks argument is neither TICKS_NONE nor TICKS_UNLIMITED?
No. We consider that you only want to verify if the timeout has expired
by polling, or you want to wait for it to expire, which has a itself a
timeout.
Then it makes the algorithm simpler.

_nano_timeout_handle_one_timeout(), in turn, sets the expired flag
to true and if fiber or task is waiting, marks it runnable.
As stated above, I don't think you need the expired flag.

fiberRtnValueSet is used to set the return value to user_data_ptr.
I don't think you need to use fiberRtnValueSet: you will get the user
data back when you call nano_timer_test, which can just look in the
nano_timer object to retrieve the data.
If we do not have user_data_ptr in the nano_timeout structure, there is
no way to use fiberRtnValueSet().

Regards,
Dmitriy.
Problem: in microkernel system clock ticks are processed in the
k_server fiber, which does not allow using timeouts during the
initialization before k_server fiber starts.

In order to allow using timeouts during the system initialization
_do_sys_clock_tick_announce pointer has to be modified to point at
the _nano_sys_clock_tick_announce() until the microkernel
_k_server() fiber starts. This way the _do_sys_clock_tick_announce
may be initialized as a pointer to
_nano_sys_clock_tick_announce() routine by default.

This modification needs to be done with changing priority of the
driver initialization routines that use timeout. Such routines need
to be invoked not on PRIMARY, but on NANOKERNEL initialization
level.
I don't have a problem with this part of the proposal.

Regards,
Ben