1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

sys: remove vtimer

This commit is contained in:
Kaspar Schleiser 2015-07-29 16:00:58 +02:00
parent 844f8a491c
commit 2cee6b036b
4 changed files with 0 additions and 622 deletions

View File

@ -40,10 +40,6 @@
#include "diskio.h"
#endif
#ifdef MODULE_VTIMER
#include "vtimer.h"
#endif
#ifdef MODULE_XTIMER
#include "xtimer.h"
#endif
@ -94,10 +90,6 @@ void auto_init(void)
config_load();
#endif
#ifdef MODULE_VTIMER
DEBUG("Auto init vtimer module.\n");
vtimer_init();
#endif
#ifdef MODULE_XTIMER
DEBUG("Auto init xtimer module.\n");
xtimer_init();

View File

@ -1,158 +0,0 @@
/*
* Copyright (C) 2009, 2014 Kaspar Schleiser
* Copyright (C) 2013, 2014 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup sys_vtimer Virtual Timer
* @ingroup sys
* @brief Provides a high level abstraction timer module to register
* timers, get current system time, and let a thread sleep for a certain amount
* of time. It does not give any timing guarantees.
* @{
* @file
* @author Kaspar Schleiser <kaspar@schleiser.de>
*/
#ifndef __VTIMER_H
#define __VTIMER_H
#include <time.h>
#include <sys/time.h>
#include "priority_queue.h"
#include "timex.h"
#include "msg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief IPC message type for vtimer msg callback
*/
#define MSG_TIMER 12345
/**
* @brief A vtimer object.
*
* This structure is used for declaring a vtimer. This should not be used by
* programmers, use the vtimer_set_*-functions instead.
*
* \hideinitializer
*/
typedef struct vtimer_t {
/** entry in vtimer's internal priority queue */
priority_queue_node_t priority_queue_entry;
/** the absoule point in time when the timer expires */
timex_t absolute;
/** the action to perform when timer fires */
void (*action)(struct vtimer_t *timer);
/** value for msg_t.type */
uint16_t type;
/** optional argument for vtimer_t::action */
void *arg;
/** optional process id for vtimer_t::action to act on */
kernel_pid_t pid;
} vtimer_t;
/**
* @brief Current system time
* @return Time as timex_t since system boot
*/
void vtimer_now(timex_t *out);
/**
* @brief Get the current time in seconds and microseconds since system start
* @param[in] tp Uptime will be stored in the timeval structure pointed to by tp
*/
void vtimer_gettimeofday(struct timeval *tp);
/**
* @brief Returns the current time in broken down format
* @param[out] localt Pointer to structure to receive time
*/
void vtimer_get_localtime(struct tm *localt);
/**
* @brief Initializes the vtimer subsystem. To be called once at system initialization. Will be initialized by auto_init.
*/
void vtimer_init(void);
/**
* @brief will cause the calling thread to be suspended from excecution until the number of microseconds has elapsed
* @param[in] us number of microseconds
* @return 0 on success, < 0 on error
*/
int vtimer_usleep(uint32_t us);
/**
* @brief will cause the calling thread to be suspended from excecution until the time specified by time has elapsed
* @param[in] time timex_t with time to suspend execution
* @return 0 on success, < 0 on error
*/
int vtimer_sleep(timex_t time);
/**
* @brief set a vtimer with msg event handler of the specified type
* @param[in] t pointer to preinitialised vtimer_t
* @param[in] interval vtimer timex_t interval
* @param[in] pid process id
* @param[in] type value for the msg_t type
* @param[in] ptr message value
*/
void vtimer_set_msg(vtimer_t *t, timex_t interval, kernel_pid_t pid, uint16_t type, void *ptr);
/**
* @brief set a vtimer with wakeup event
* @param[in] t pointer to preinitialised vtimer_t
* @param[in] interval the interval after which the timer shall fire
* @param[in] pid process id
* @return 0 on success, < 0 on error
*/
int vtimer_set_wakeup(vtimer_t *t, timex_t interval, kernel_pid_t pid);
/**
* @brief remove a vtimer
* @param[in] t pointer to preinitialised vtimer_t
*/
void vtimer_remove(vtimer_t *t);
/**
* @brief receive a message but return in case of timeout time is passed by without a new message
* @param[out] m pointer to a msg_t which will be filled in case of no timeout
* @param[in] timeout timex_t containing the relative time to fire the timeout
* @return < 0 on error, other value otherwise
*/
int vtimer_msg_receive_timeout(msg_t *m, timex_t timeout);
#if ENABLE_DEBUG
/**
* @brief Prints a vtimer_t
*/
void vtimer_print(vtimer_t *t);
/**
* @brief Prints the vtimer shortterm queue (use for debug purposes)
*/
void vtimer_print_short_queue(void);
/**
* @brief Prints the vtimer longterm queue (use for debug purposes)
*/
void vtimer_print_long_queue(void);
#endif
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* __VTIMER_H */

View File

@ -1 +0,0 @@
include $(RIOTBASE)/Makefile.base

View File

@ -1,455 +0,0 @@
/**
* virtual timer
*
* Copyright (C) 2013 - 2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
* @ingroup vtimer
* @{
* @file
* @author Kaspar Schleiser <kaspar@schleiser.de> (author)
* @author Oliver Hahm <oliver.hahm@inria.fr> (modifications)
* @author Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> (cleaning up the mess)
* @}
*/
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#define ENABLE_DEBUG (0)
#include "debug.h"
#include "irq.h"
#include "priority_queue.h"
#include "timex.h"
#include "hwtimer.h"
#include "msg.h"
#include "mutex.h"
#include "thread.h"
#include "kernel_macros.h"
#include "vtimer.h"
#if ENABLE_DEBUG
void vtimer_print_short_queue(void);
void vtimer_print_long_queue(void);
void vtimer_print(vtimer_t *t);
#endif
#define VTIMER_THRESHOLD 20UL
#define VTIMER_BACKOFF 10UL
#define SECONDS_PER_TICK (4096U)
#define MICROSECONDS_PER_TICK (4096UL * 1000000)
/*
* This is a workaround for missing support in clang on OSX,
* the alias is not needed in native.
* Compare https://github.com/RIOT-OS/RIOT/issues/2336
*/
#ifndef BOARD_NATIVE
void _gettimeofday(void) __attribute__ ((weak, alias("vtimer_gettimeofday")));
#endif
static void vtimer_callback(void *ptr);
static void vtimer_callback_tick(vtimer_t *timer);
static void vtimer_callback_msg(vtimer_t *timer);
static void vtimer_callback_wakeup(vtimer_t *timer);
static int vtimer_set(vtimer_t *timer);
static int set_longterm(vtimer_t *timer);
static int set_shortterm(vtimer_t *timer);
static priority_queue_t longterm_priority_queue_root = PRIORITY_QUEUE_INIT;
static priority_queue_t shortterm_priority_queue_root = PRIORITY_QUEUE_INIT;
static vtimer_t longterm_tick_timer;
static uint32_t longterm_tick_start;
static volatile int in_callback = false;
static int hwtimer_id = -1;
static uint32_t hwtimer_next_absolute;
static inline priority_queue_node_t *timer_get_node(vtimer_t *timer)
{
if (!timer) {
return NULL;
}
return &timer->priority_queue_entry;
}
static inline vtimer_t *node_get_timer(priority_queue_node_t *node)
{
if (!node) {
return NULL;
}
return container_of(node, vtimer_t, priority_queue_entry);
}
static int set_longterm(vtimer_t *timer)
{
timer->priority_queue_entry.priority = timer->absolute.seconds;
/* *** UGLY FIX BEGINS *** */
/* Workaround for a bug in a so far undiscovered location which causes the
* vtimer to add the same timer twice, locking the system in an infinite
* loop inside priority_queue_add. */
priority_queue_remove(&longterm_priority_queue_root, timer_get_node(timer));
/* *** UGLY FIX ENDS *** */
priority_queue_add(&longterm_priority_queue_root, timer_get_node(timer));
return 0;
}
static int update_shortterm(void)
{
if (shortterm_priority_queue_root.first == NULL) {
/* there is no vtimer to schedule, queue is empty */
DEBUG("update_shortterm: shortterm_priority_queue_root.next == NULL - dont know what to do here\n");
return 0;
}
if (hwtimer_id != -1) {
/* there is a running hwtimer for us */
if (hwtimer_next_absolute != shortterm_priority_queue_root.first->priority) {
/* the next timer in the vtimer queue is not the next hwtimer */
/* we have to remove the running hwtimer (and schedule a new one) */
hwtimer_remove(hwtimer_id);
}
else {
/* the next vtimer is the next hwtimer, nothing to do */
return 0;
}
}
/* short term part of the next vtimer */
hwtimer_next_absolute = shortterm_priority_queue_root.first->priority;
uint32_t next = hwtimer_next_absolute + longterm_tick_start;
/* current short term time */
uint32_t now_ticks = hwtimer_now();
uint32_t now = HWTIMER_TICKS_TO_US(now_ticks);
if((next - HWTIMER_TICKS_TO_US(VTIMER_THRESHOLD) - now) > MICROSECONDS_PER_TICK ) {
DEBUG("truncating next (next - HWTIMER_TICKS_TO_US(VTIMER_THRESHOLD) - now): %lu\n", (next - HWTIMER_TICKS_TO_US(VTIMER_THRESHOLD) - now));
next = now + HWTIMER_TICKS_TO_US(VTIMER_BACKOFF);
}
DEBUG("update_shortterm: Set hwtimer to %" PRIu32 " (now=%lu)\n", next, now);
unsigned long offset_ticks = (unsigned long)HWTIMER_TICKS(next - now);
hwtimer_id = hwtimer_set(offset_ticks, vtimer_callback, NULL);
return 0;
}
void vtimer_callback_tick(vtimer_t *timer)
{
(void) timer;
DEBUG("vtimer_callback_tick().\n");
longterm_tick_start += MICROSECONDS_PER_TICK;
longterm_tick_timer.absolute.seconds += SECONDS_PER_TICK;
longterm_tick_timer.absolute.microseconds = MICROSECONDS_PER_TICK; // Should never change, just for clarity.
set_shortterm(&longterm_tick_timer);
while (longterm_priority_queue_root.first) {
vtimer_t *timer = node_get_timer(longterm_priority_queue_root.first);
if (timer->absolute.seconds == longterm_tick_timer.absolute.seconds) {
priority_queue_remove_head(&longterm_priority_queue_root);
set_shortterm(timer);
}
else {
break;
}
}
}
static void vtimer_callback_msg(vtimer_t *timer)
{
msg_t msg;
msg.type = timer->type;
msg.content.value = (unsigned int) timer->arg;
msg_send_int(&msg, timer->pid);
}
static void vtimer_callback_wakeup(vtimer_t *timer)
{
thread_wakeup(timer->pid);
}
static void vtimer_callback_unlock(vtimer_t *timer)
{
mutex_t *mutex = (mutex_t *) timer->arg;
mutex_unlock(mutex);
}
static int set_shortterm(vtimer_t *timer)
{
DEBUG("set_shortterm(): Absolute: %" PRIu32 " %" PRIu32 "\n", timer->absolute.seconds, timer->absolute.microseconds);
timer->priority_queue_entry.priority = timer->absolute.microseconds;
/* *** UGLY FIX BEGINS *** */
/* Workaround for a bug in a so far undiscovered location which causes the
* vtimer to add the same timer twice, locking the system in an infinite
* loop inside priority_queue_add. */
priority_queue_remove(&shortterm_priority_queue_root, timer_get_node(timer));
/* *** UGLY FIX ENDS *** */
priority_queue_add(&shortterm_priority_queue_root, timer_get_node(timer));
return 1;
}
void vtimer_callback(void *ptr)
{
DEBUG("vtimer_callback ptr=%p\n", ptr);
(void) ptr;
in_callback = true;
hwtimer_id = -1;
/* get the vtimer that fired */
vtimer_t *timer = node_get_timer(priority_queue_remove_head(&shortterm_priority_queue_root));
if (timer) {
#if ENABLE_DEBUG
vtimer_print(timer);
#endif
DEBUG("vtimer_callback(): Shooting %" PRIu32 ".\n", timer->absolute.microseconds);
/* shoot timer */
timer->action(timer);
}
else {
DEBUG("vtimer_callback(): spurious call.\n");
}
in_callback = false;
update_shortterm();
}
void normalize_to_tick(timex_t *time)
{
DEBUG("Normalizing: %" PRIu32 " %" PRIu32 "\n", time->seconds, time->microseconds);
uint32_t seconds_tmp = time->seconds % SECONDS_PER_TICK;
time->seconds -= seconds_tmp;
uint32_t usecs_tmp = time->microseconds + (seconds_tmp * 1000000);
DEBUG("Normalizin2: %" PRIu32 " %" PRIu32 "\n", time->seconds, usecs_tmp);
if (usecs_tmp < time->microseconds) {
usecs_tmp -= MICROSECONDS_PER_TICK;
time->seconds += SECONDS_PER_TICK;
}
if (usecs_tmp > MICROSECONDS_PER_TICK) {
usecs_tmp -= MICROSECONDS_PER_TICK;
time->seconds += SECONDS_PER_TICK;
}
time->microseconds = usecs_tmp;
DEBUG(" Result: %" PRIu32 " %" PRIu32 "\n", time->seconds, time->microseconds);
}
static int vtimer_set(vtimer_t *timer)
{
DEBUG("vtimer_set(): New timer. Offset: %" PRIu32 " %" PRIu32 "\n", timer->absolute.seconds, timer->absolute.microseconds);
timex_t now;
vtimer_now(&now);
timer->absolute = timex_add(now, timer->absolute);
normalize_to_tick(&(timer->absolute));
DEBUG("vtimer_set(): Absolute: %" PRIu32 " %" PRIu32 "\n", timer->absolute.seconds, timer->absolute.microseconds);
DEBUG("vtimer_set(): NOW: %" PRIu32 " %" PRIu32 "\n", now.seconds, now.microseconds);
int result = 0;
if (timer->absolute.seconds == 0) {
if (timer->absolute.microseconds > 10) {
timer->absolute.microseconds -= 10;
}
}
unsigned state = disableIRQ();
if (timer->absolute.seconds != longterm_tick_timer.absolute.seconds) {
/* we're long-term */
DEBUG("vtimer_set(): setting long_term\n");
result = set_longterm(timer);
}
else {
DEBUG("vtimer_set(): setting short_term\n");
if (set_shortterm(timer)) {
/* delay update of next shortterm timer if we
* are called from within vtimer_callback. */
if (!in_callback) {
result = update_shortterm();
}
}
}
restoreIRQ(state);
return result;
}
void vtimer_now(timex_t *out)
{
uint32_t us = HWTIMER_TICKS_TO_US(hwtimer_now()) - longterm_tick_start;
static const uint32_t us_per_s = 1000ul * 1000ul;
out->seconds = longterm_tick_timer.absolute.seconds + us / us_per_s;
out->microseconds = us % us_per_s;
}
void vtimer_gettimeofday(struct timeval *tp) {
timex_t now;
vtimer_now(&now);
tp->tv_sec = now.seconds;
tp->tv_usec = now.microseconds;
}
void vtimer_get_localtime(struct tm *localt)
{
timex_t now;
vtimer_now(&now);
memset(localt, 0, sizeof(struct tm));
localt->tm_sec = now.seconds % 60;
localt->tm_min = (now.seconds / 60) % 60;
localt->tm_hour = (now.seconds / 60 / 60) % 24;
}
void vtimer_init(void)
{
DEBUG("vtimer_init().\n");
unsigned state = disableIRQ();
longterm_tick_start = 0;
longterm_tick_timer.action = vtimer_callback_tick;
longterm_tick_timer.arg = NULL;
longterm_tick_timer.absolute.seconds = 0;
longterm_tick_timer.absolute.microseconds = MICROSECONDS_PER_TICK;
DEBUG("vtimer_init(): Setting longterm tick to %" PRIu32 "\n", longterm_tick_timer.absolute.microseconds);
set_shortterm(&longterm_tick_timer);
update_shortterm();
restoreIRQ(state);
}
int vtimer_set_wakeup(vtimer_t *t, timex_t interval, kernel_pid_t pid)
{
t->action = vtimer_callback_wakeup;
t->arg = NULL;
t->absolute = interval;
t->pid = pid;
return vtimer_set(t);
}
int vtimer_usleep(uint32_t usecs)
{
timex_t offset = timex_set(0, usecs);
return vtimer_sleep(offset);
}
int vtimer_sleep(timex_t time)
{
/**
* Use spin lock for short periods.
* Assumes that hardware timer ticks are shorter than a second.
*/
if (time.seconds == 0) {
unsigned long ticks = HWTIMER_TICKS(time.microseconds);
if (ticks <= HWTIMER_SPIN_BARRIER) {
hwtimer_spin(ticks);
return 0;
}
}
int ret;
vtimer_t t;
mutex_t mutex = MUTEX_INIT;
mutex_lock(&mutex);
t.action = vtimer_callback_unlock;
t.arg = &mutex;
t.absolute = time;
ret = vtimer_set(&t);
mutex_lock(&mutex);
return ret;
}
void vtimer_remove(vtimer_t *t)
{
unsigned irq_state = disableIRQ();
priority_queue_remove(&shortterm_priority_queue_root, timer_get_node(t));
priority_queue_remove(&longterm_priority_queue_root, timer_get_node(t));
update_shortterm();
restoreIRQ(irq_state);
}
void vtimer_set_msg(vtimer_t *t, timex_t interval, kernel_pid_t pid, uint16_t type, void *ptr)
{
t->action = vtimer_callback_msg;
t->type = type;
t->arg = ptr;
t->absolute = interval;
t->pid = pid;
vtimer_set(t);
}
int vtimer_msg_receive_timeout(msg_t *m, timex_t timeout) {
msg_t timeout_message;
timeout_message.type = MSG_TIMER;
timeout_message.content.ptr = (char *) &timeout_message;
vtimer_t t;
vtimer_set_msg(&t, timeout, sched_active_pid, MSG_TIMER, &timeout_message);
msg_receive(m);
if (m->type == MSG_TIMER && m->content.ptr == (char *) &timeout_message) {
/* we hit the timeout */
return -1;
}
else {
vtimer_remove(&t);
return 1;
}
}
#if ENABLE_DEBUG
void vtimer_print_short_queue(void){
priority_queue_print(&shortterm_priority_queue_root);
}
void vtimer_print_long_queue(void){
priority_queue_print(&longterm_priority_queue_root);
}
void vtimer_print(vtimer_t *t)
{
printf("Seconds: %" PRIu32 " - Microseconds: %" PRIu32 "\n \
action: %p\n \
arg: %p\n \
pid: %" PRIkernel_pid "\n",
t->absolute.seconds, t->absolute.microseconds,
t->action,
t->arg,
t->pid);
}
#endif