/**
@page GRAS_tut_tour_timers Lesson 7: Using internal timers
\section GRAS_tut_tour_timers_toc Table of Contents
- \ref GRAS_tut_tour_timers_intro
- \ref GRAS_tut_tour_timers_use
- \ref GRAS_tut_tour_timers_recap
\section GRAS_tut_tour_timers_intro Introduction
The messaging primitives we saw until now allow the processes to react to
external events. This is good, but sometimes, you want the same action to be
done periodically. Think of a system based on a group of processes. If you
want to give some adaptability to this system, you shouldn't hardcode the
memberships but have the members send a message to a coordinator to register
to the system.
This add some dynamism to your system since new members can join at any
time. To have a process leaving the system, you can imagine an "unregister"
message symetric to the "register" one. But how will you deal with failures?
What if a process leaves without being given the ability to inform the
coordinator?
One solution is to have the members re-register periodically, so that the
coordinator can detect the processes which didn't do so since a while, and
dismiss them.
To implement this in GRAS, we need some more functions: gras_timer_repeat()
allows to specify a periodic action and gras_timer_delay() allows to get an
action done once a given delay expires. gras_timer_cancel_delay() and
gras_timer_cancel_repeat() allow to remove already declared timers. Actions
must be function without argument nor result (void my_action(void){
... }).
It is important to note that timers are not prehemptive. They will not start
as soon as they are ready. Instead, they get served when you go into
gras_msg_handle() (and they are served before incomming messages). This is
because allowing timers to run in parallel to the callbacks would add
parallelism to the user code, which would have to protect data with mutexes.
This is a level of complexity I really don't want for user code. If you
really need several running entities, simply run several processes (see \ref
GRAS_tut_intro_model for more details).
\section GRAS_tut_tour_timers_use Putting timers into action
We will change the client of our example so that it send an hello message
every half second to the server. Then we will add a delayed action scheduled
5 seconds later in charge of stopping every processes. For this to work, we
first need to add a global to the server too, containing the socket binded
onto the server (to send messages) and a boolean indicating whether we are
done or not, just like we did on the server side in \ref
GRAS_tut_tour_globals. Here is the resulting global structure:
\dontinclude 07-timers.c
\skip client_data
\until client_data_t
Then, we define the repetitive action in charge of sending messages to the
server:
\skip client_do_hello
\until end_of_client_do_hello
This timer is installed the following way. You simply tell the action to
schedule and its periodicity.
\skip gras_timer_repeat
\until gras_timer_repeat
Desinstalling this is not harder. You tell the action to unschedule, and the
periodicity at which it was desinstalled (so that the same action can be
scheduled at different intervals, and each of them be desinstallable
separately).
\dontinclude 07-timers.c
\skip gras_timer_cancel_repeat
\until gras_timer_cancel_repeat
Then comes the delayed action in charge of stopping everything, which should
be self-explanatory at this point. It could be cancelled before its
expiration using gras_timer_cancel_delay(), which accepts exactly the same
kind of arguments than gras_timer_cancel_repeat().
\dontinclude 07-timers.c
\skip client_do_stop
\until end_of_client_do_stop
Finally, we should change the client main function to adapt to these
modifications, as you can see in the recapping below.
\section GRAS_tut_tour_timers_recap Recapping everything together
The program now reads:
\include 07-timers.c
Which produces the expected output:
\include 07-timers.output
Go to \ref GRAS_tut_tour_exceptions
*/