rockbox/firmware/kernel/timeout.c
Thomas Martitz 382d1861af kernel: Break out kernel primitives into separate files and move to separate dir.
No code changed, just shuffling stuff around. This should make it easier to
build only select parts kernel and use different implementations.

Change-Id: Ie1f00f93008833ce38419d760afd70062c5e22b5
2014-03-03 18:11:57 +01:00

97 lines
2.5 KiB
C

/****************************************************************************
* Tick-based interval timers/one-shots - be mindful this is not really
* intended for continuous timers but for events that need to run for a short
* time and be cancelled without further software intervention.
****************************************************************************/
#include "config.h"
#include "system.h" /* TIME_AFTER */
#include "kernel.h"
#include "timeout.h"
#include "general.h"
/* list of active timeout events */
static struct timeout *tmo_list[MAX_NUM_TIMEOUTS+1];
/* timeout tick task - calls event handlers when they expire
* Event handlers may alter expiration, callback and data during operation.
*/
static void timeout_tick(void)
{
unsigned long tick = current_tick;
struct timeout **p = tmo_list;
struct timeout *curr;
for(curr = *p; curr != NULL; curr = *(++p))
{
int ticks;
if(TIME_BEFORE(tick, curr->expires))
continue;
/* this event has expired - call callback */
ticks = curr->callback(curr);
if(ticks > 0)
{
curr->expires = tick + ticks; /* reload */
}
else
{
timeout_cancel(curr); /* cancel */
}
}
}
/* Cancels a timeout callback - can be called from the ISR */
void timeout_cancel(struct timeout *tmo)
{
int oldlevel = disable_irq_save();
int rc = remove_array_ptr((void **)tmo_list, tmo);
if(rc >= 0 && *tmo_list == NULL)
{
tick_remove_task(timeout_tick); /* Last one - remove task */
}
restore_irq(oldlevel);
}
/* Adds a timeout callback - calling with an active timeout resets the
interval - can be called from the ISR */
void timeout_register(struct timeout *tmo, timeout_cb_type callback,
int ticks, intptr_t data)
{
int oldlevel;
void **arr, **p;
if(tmo == NULL)
return;
oldlevel = disable_irq_save();
/* See if this one is already registered */
arr = (void **)tmo_list;
p = find_array_ptr(arr, tmo);
if(p - arr < MAX_NUM_TIMEOUTS)
{
/* Vacancy */
if(*p == NULL)
{
/* Not present */
if(*tmo_list == NULL)
{
tick_add_task(timeout_tick); /* First one - add task */
}
*p = tmo;
}
tmo->callback = callback;
tmo->data = data;
tmo->expires = current_tick + ticks;
}
restore_irq(oldlevel);
}