libamxp  1.4.0
Patterns C Implementation
Timer

Timers can be used to do a job at regular intervals or once some time later. More...

Data Structures

struct  _amxp_timer
 The timer type. More...
 

Typedefs

typedef void(* amxp_timer_cb_t) (amxp_timer_t *timer, void *priv)
 Timer timeout callback function. More...
 
typedef enum _amxp_timer_state amxp_timer_state_t
 The timer states. More...
 

Enumerations

enum  _amxp_timer_state {
  amxp_timer_off , amxp_timer_started , amxp_timer_running , amxp_timer_expired ,
  amxp_timer_deleted
}
 The timer states. More...
 

Functions

void amxp_timers_calculate (void)
 Caclulates the remaining time of all timers. More...
 
void amxp_timers_check (void)
 Check all timers and call the callback function when the timer is in Timer expired state. More...
 
void amxp_timers_enable (bool enable)
 Enable or disable all timers. More...
 
int amxp_timer_new (amxp_timer_t **timer, amxp_timer_cb_t cb, void *priv)
 Allocate and initializes a new timer. More...
 
void amxp_timer_delete (amxp_timer_t **timer)
 Deletes a timer. More...
 
int amxp_timer_set_interval (amxp_timer_t *timer, unsigned int msec)
 Sets the interval of a timer in milli seconds. More...
 
unsigned int amxp_timer_remaining_time (amxp_timer_t *timer)
 Get the remaining time of the timer. More...
 
int amxp_timer_start (amxp_timer_t *timer, unsigned int timeout_msec)
 Starts or resets a timer. More...
 
int amxp_timer_stop (amxp_timer_t *timer)
 Stops the timer. More...
 
amxp_timer_state_t amxp_timer_get_state (amxp_timer_t *timer)
 Get the timer's state. More...
 

Detailed Description

Timers can be used to do a job at regular intervals or once some time later.

To have timers fully functional an event loop must be started. The timers are using the SIGALRM signal. Multiple timers can be started, but only one timer will be the next to trigger the SIGALRM.

Using timers

To create a timer, use the amxp_timer_new function. Some arbitrary private data can be attached to the timer. This private data is a pointer to memory allocated by the caller and must be managed by the caller. This private data can be changed at any time by modifying the priv member of the amxp_timer_t structure. The pointer to the private data will be passed to the callback function. The callback function will be called each time the timer expires.

To start a timer, use the amxp_timer_start function.

By default a timer will only expire once. To have the timer repeat, an interval must be set before starting the timer, an interval can be set using amxp_timer_set_interval. The interval and the initial expire time can be different. While the timer is running the interval can be changed and will take effect on the next time the timer expires.

A timer can be stopped at any time by calling amxp_timer_stop, to restart the time call amxp_timer_start again.

A running timer can be reset to it's initial value by calling amxp_timer_start again.

All timers can be disabled or enabled again by callling amxp_timers_enable.

A timer that is not needed any more can be removed by calling amxp_timer_delete.

The current state of a timer can be fetched using amxp_timer_get_state.

Timers and eventloops

To make the timer implementation work, an eventloop must be available that monitors SIG_ALRM system signal. When the SIG_ALRM is triggered the eventloop must call the functions

The first one will calculate the remaining time for each timer, if the remaining time is 0 or lower the time is expired, the state of the timer will be set to expired state. Timers in started state will become active when this function is called.

The amxp_timers_check will call the callback function for each expired timer and reset the state of the timer if needed. This function will remove the timers in deleted state from memory.

Typedef Documentation

◆ amxp_timer_cb_t

typedef void(* amxp_timer_cb_t) (amxp_timer_t *timer, void *priv)

Timer timeout callback function.

Definition of the timer timeout callback function. This function is called whenever a timer expires. The private data attached to the timer when creating the timer using amxp_timer_new is passed as is to this callback function.

It is allowed to delete the timer in the callback function, it is not allowed to delete other timers in the callback function.

Definition at line 139 of file amxp_timer.h.

◆ amxp_timer_state_t

The timer states.

This enum holds all possible timer states

Enumeration Type Documentation

◆ _amxp_timer_state

The timer states.

This enum holds all possible timer states

Enumerator
amxp_timer_off 

Timer is not running

amxp_timer_started 

Timer is started

amxp_timer_running 

Timer is running

amxp_timer_expired 

Timer has expired

amxp_timer_deleted 

Timer is deleted and can not be used anymore

Definition at line 148 of file amxp_timer.h.

148  {
enum _amxp_timer_state amxp_timer_state_t
The timer states.
@ amxp_timer_off
Definition: amxp_timer.h:149
@ amxp_timer_running
Definition: amxp_timer.h:151
@ amxp_timer_expired
Definition: amxp_timer.h:152
@ amxp_timer_deleted
Definition: amxp_timer.h:153
@ amxp_timer_started
Definition: amxp_timer.h:150

Function Documentation

◆ amxp_timer_delete()

void amxp_timer_delete ( amxp_timer_t **  timer)

Deletes a timer.

Removes the timer timers list and cleanup allocated memory.

Note
When private data was attached to the timer and memory was allocated for it, it is up to the caller to free that allocated memory.
Parameters
timerpointer to the timer.

Definition at line 247 of file amxp_timer.c.

247  {
248  when_null(timer, exit);
249  when_null(*timer, exit);
250 
251  amxp_timer_stop(*timer);
252  (*timer)->state = amxp_timer_deleted;
253  *timer = NULL;
254 
255 exit:
256  return;
257 }
int amxp_timer_stop(amxp_timer_t *timer)
Stops the timer.
Definition: amxp_timer.c:319

◆ amxp_timer_get_state()

amxp_timer_state_t amxp_timer_get_state ( amxp_timer_t timer)

Get the timer's state.

Returns the current state of the timer.

Parameters
timerpointer to the timer.
Returns
The current state of the timer, any of amxp_timer_state_t

Definition at line 334 of file amxp_timer.c.

334  {
335  return timer == NULL ? amxp_timer_off : timer->state;
336 }
amxp_timer_state_t state
Definition: amxp_timer.h:166

◆ amxp_timer_new()

int amxp_timer_new ( amxp_timer_t **  timer,
amxp_timer_cb_t  cb,
void *  priv 
)

Allocate and initializes a new timer.

Allocates and initializes a new timer structure. The new timer will be added to the list of timers.

The *timer must be initialized to NULL before calling this function.

Parameters
timerwill receive the pointer to the new timer.
cbthe time callback function, see amxp_timer_cb_t
privpointer to private data, this pointer is passed to the callback function when the timer expires.
Returns
0 when the imer is allocated and initialized. any other value indicates an error

Definition at line 229 of file amxp_timer.c.

229  {
230  int retval = -1;
231 
232  when_null(timer, exit);
233  when_not_null(*timer, exit);
234 
235  *timer = (amxp_timer_t*) calloc(1, sizeof(amxp_timer_t));
236  when_null(*timer, exit);
237  (*timer)->cb = cb;
238  (*timer)->priv = priv;
239  amxc_llist_append(&timers, &(*timer)->it);
240 
241  retval = 0;
242 
243 exit:
244  return retval;
245 }
static amxc_llist_t timers
Definition: amxp_timer.c:65
The timer type.
Definition: amxp_timer.h:163

◆ amxp_timer_remaining_time()

unsigned int amxp_timer_remaining_time ( amxp_timer_t timer)

Get the remaining time of the timer.

Returns the remaining time of the timer in milliseconds. If a timer is not running, this function will always return 0.

Parameters
timerpointer to the timer.
Returns
The remaining time in milliseconds

Definition at line 281 of file amxp_timer.c.

281  {
282  unsigned int retval = 0;
283 
284  when_null(timer, exit);
285  when_true(timer->state != amxp_timer_running &&
286  timer->state != amxp_timer_started,
287  exit);
288 
289  retval = timer->timer.it_value.tv_sec * 1000 +
290  timer->timer.it_value.tv_usec / 1000;
291 
292 exit:
293  return retval;
294 }
struct itimerval timer
Definition: amxp_timer.h:165

◆ amxp_timer_set_interval()

int amxp_timer_set_interval ( amxp_timer_t timer,
unsigned int  msec 
)

Sets the interval of a timer in milli seconds.

Assigns an interval to the timer. When the initial timeout of the timer occurs, this interval time will be used to restart the timer.

A timer with an interval set will keep on running until amxp_timer_stop is called.

Parameters
timerpointer to the timer.
msecthe interval specified in milliseconds
Returns
0 on success, any other value indicates an error.

Definition at line 259 of file amxp_timer.c.

259  {
260  int retval = -1;
261 
262  when_null(timer, exit);
263 
264  if(msec == 0) {
265  // this is the absolute minimum value for a timer.
266  // if the value is 0 setitimer has no effect as when set to zero
267  // the timer is stopped (and will never trigger SIGALRM)
268  // see man page of setitimer
269  msec = 1;
270  }
271 
272  timer->timer.it_interval.tv_sec = msec / 1000;
273  timer->timer.it_interval.tv_usec = (msec % 1000) * 1000;
274 
275  retval = 0;
276 
277 exit:
278  return retval;
279 }

◆ amxp_timer_start()

int amxp_timer_start ( amxp_timer_t timer,
unsigned int  timeout_msec 
)

Starts or resets a timer.

The timer will be started, the initial time out value is must be provided in milliseconds.

If an interval time was set, the interval will start after the initial timeout.

If the timer was already started, the timer will be reset and restarted using the new timeout value.

Parameters
timerpointer to the timer.
timeout_msecinitial timeout value.
Returns
0 when the timer is started, any other value indicates an error.

Definition at line 296 of file amxp_timer.c.

296  {
297  int retval = -1;
298  when_null(timer, exit);
299  when_true(timer->state == amxp_timer_deleted, exit);
300 
301  if(timeout_msec == 0) {
302  // this is the absolute minimum value for a timer.
303  // if the value is 0 setitimer has no effect as when set to zero
304  // the timer is stopped (and will never trigger SIGALRM)
305  // see man page of setitimer
306  timeout_msec = 1;
307  }
308  timer->timer.it_value.tv_sec = timeout_msec / 1000;
309  timer->timer.it_value.tv_usec = (timeout_msec % 1000) * 1000;
310  timer->state = amxp_timer_started;
311 
313 
314  retval = 0;
315 exit:
316  return retval;
317 }
void amxp_timers_calculate(void)
Caclulates the remaining time of all timers.
Definition: amxp_timer.c:144

◆ amxp_timer_stop()

int amxp_timer_stop ( amxp_timer_t timer)

Stops the timer.

This function will stop the timer. After calling this function the timeout callback function of the timer will not be called again until the timer is restarted using amxp_timer_start

Parameters
timerpointer to the timer.
Returns
0 when the timer is stopped, any other value indicates an error.

Definition at line 319 of file amxp_timer.c.

319  {
320  int retval = -1;
321  when_null(timer, exit);
322  when_true(timer->state == amxp_timer_deleted, exit);
323 
324  timer->state = amxp_timer_off;
325 
327 
328  retval = 0;
329 
330 exit:
331  return retval;
332 }

◆ amxp_timers_calculate()

void amxp_timers_calculate ( void  )

Caclulates the remaining time of all timers.

Updates all timers with the time passed since the last update by subtracting the passed time from each timer. If a timer reaches zero or becomes negative it is expired and the state is changed to amxp_timer_expired.

The timer with the smallest remaining time is used to set the SIGALRM signal.

Note
Typically this function is called from within an eventloop.

Definition at line 144 of file amxp_timer.c.

144  {
145  struct timeval elapsed = { 0, 0 };
146  bool active_timer = false;
147  struct itimerval ti;
148  struct timeval smallest;
149 
150  elapsed = amxp_timer_get_elapsed_time();
151 
152  timerclear(&smallest);
153  amxp_timer_update_current(&elapsed);
154 
155  amxc_llist_for_each(it, (&timers)) {
156  amxp_timer_t* timer = amxc_llist_it_get_data(it, amxp_timer_t, it);
157  if(timer->state == amxp_timer_deleted) {
158  continue;
159  }
160  if(timer->state == amxp_timer_off) {
161  continue;
162  }
163  if(timer->state == amxp_timer_started) {
164  amxp_timer_start_timer(timer, &smallest);
165  active_timer = true;
166  continue;
167  }
168 
169  active_timer |= amxp_timer_update(timer, &smallest, &elapsed);
170  }
171 
172  timerclear(&ti.it_interval);
173  current = smallest;
174  if(active_timer) {
175  ti.it_value = current;
176  } else {
177  ti.it_value.tv_sec = 0;
178  ti.it_value.tv_usec = 0;
179  }
180  setitimer(ITIMER_REAL, &ti, NULL);
181 }
static struct timeval current
Definition: amxp_timer.c:66
static struct timeval amxp_timer_get_elapsed_time(void)
Definition: amxp_timer.c:74
static void amxp_timer_update_current(struct timeval *elapsed)
Definition: amxp_timer.c:93
static bool amxp_timer_update(amxp_timer_t *timer, struct timeval *smallest, struct timeval *elapsed)
Definition: amxp_timer.c:110
static void amxp_timer_start_timer(amxp_timer_t *timer, struct timeval *smallest)
Definition: amxp_timer.c:101

◆ amxp_timers_check()

void amxp_timers_check ( void  )

Check all timers and call the callback function when the timer is in Timer expired state.

Loops over all timers and for each expired timer the timeout callback function is called. If the timer has an interval set, the state is reset to amxp_timer_running, if no interval is availble the timer state is reset to amxp_timer_off.

Note
Typically this function is called from within an eventloop and after amxp_timers_calculate. This function will call the timer expired callback function for all expired timers. In the callback function it is possible to delete the timer for which the callback functions was called, but not any other timer can be deleted in the callback function as it will modify the timer's list.

Definition at line 183 of file amxp_timer.c.

183  {
184  static uint32_t recursive = 0;
185  amxp_timer_t* timer = NULL;
186  amxc_llist_it_t* it = NULL;
187 
188  recursive++;
189  when_true(!timers_enabled, exit);
190 
191  it = amxc_llist_get_first(&timers);
192  // do not use amxc_llist_for_each here.
193  // it is possible that in the callback function a new timer is added.
194  // this new timer must be taken into account as well.
195  // new timers are always added to the end of the list.
196  while(it) {
197  timer = amxc_llist_it_get_data(it, amxp_timer_t, it);
198  if((timer->state == amxp_timer_deleted) && (recursive == 1)) {
199  it = amxc_llist_it_get_next(&timer->it);
200  amxc_llist_it_clean(&timer->it, amxp_timer_free_it);
201  continue;
202  }
203 
204  if(timer->state == amxp_timer_expired) {
205  if(timerisset(&timer->timer.it_interval)) {
206  timer->state = amxp_timer_running;
207  } else {
208  timer->state = amxp_timer_off;
209  }
210  if(timer->cb) {
211  amxp_timers_enable(false);
212  timer->cb(timer, timer->priv);
213  amxp_timers_enable(true);
214  }
215  }
216 
217  it = amxc_llist_it_get_next(&timer->it);
218  }
219 
220 exit:
221  recursive--;
222  return;
223 }
static void amxp_timer_free_it(amxc_llist_it_t *it)
Definition: amxp_timer.c:69
static bool timers_enabled
Definition: amxp_timer.c:67
void amxp_timers_enable(bool enable)
Enable or disable all timers.
Definition: amxp_timer.c:225
void * priv
Definition: amxp_timer.h:168
amxc_llist_it_t it
Definition: amxp_timer.h:164
amxp_timer_cb_t cb
Definition: amxp_timer.h:167

◆ amxp_timers_enable()

void amxp_timers_enable ( bool  enable)

Enable or disable all timers.

With this function all timers can be disable or enabled. When the timers are disabled they can still expire, but the callback functions are not called. The next time the timers are enabled all callback function of the expired timers will be called in the next iteration in the event loop.

Parameters
enableTrue to enable timer handling or false to disable timer handling

Definition at line 225 of file amxp_timer.c.

225  {
226  timers_enabled = enable;
227 }