From 7911a6f01bc8a19f220f98e2fdc8595f65996853 Mon Sep 17 00:00:00 2001 From: asterix Date: Wed, 11 Jan 2012 18:14:35 +0000 Subject: [PATCH] Add rtask module. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@5251 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cfg/cfg_rtask.h | 70 +++++++++++++++++++ bertos/kern/rtask.c | 153 +++++++++++++++++++++++++++++++++++++++++ bertos/kern/rtask.h | 65 +++++++++++++++++ 3 files changed, 288 insertions(+) create mode 100644 bertos/cfg/cfg_rtask.h create mode 100644 bertos/kern/rtask.c create mode 100644 bertos/kern/rtask.h diff --git a/bertos/cfg/cfg_rtask.h b/bertos/cfg/cfg_rtask.h new file mode 100644 index 00000000..fecc60d4 --- /dev/null +++ b/bertos/cfg/cfg_rtask.h @@ -0,0 +1,70 @@ +/** + * \file + * + * + * \brief Recurrent task module configuration. + * + * \author Luca Ottaviano + */ + +#ifndef CFG_RTASK_H +#define CFG_RTASK_H + +/** + * Number of allocable RTasks. + * + * $WIZ$ type = "int" + */ +#define CONFIG_RTASK_POOL_SIZE 8 + +/** + * Stack size of the rtask process. + * + * $WIZ$ type = "int" + */ +#define CONFIG_RTASK_STACK 256 + +/** + * Module logging level. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_level" + */ +#define RTASK_LOG_LEVEL LOG_LVL_ERR + +/** + * Module logging format. + * + * $WIZ$ type = "enum" + * $WIZ$ value_list = "log_format" + */ +#define RTASK_LOG_FORMAT LOG_FMT_VERBOSE + +#endif /* CFG_RTASK_H */ diff --git a/bertos/kern/rtask.c b/bertos/kern/rtask.c new file mode 100644 index 00000000..dddbd6d7 --- /dev/null +++ b/bertos/kern/rtask.c @@ -0,0 +1,153 @@ +/** + * \file + * + * + * \brief Recurrent task module implementation. + * + * \author Luca Ottaviano + * \author Francesco Sacchi + * + */ + +#include "rtask.h" +#include "cfg/cfg_rtask.h" +#include // MOD_CHECK + +#define LOG_LEVEL RTASK_LOG_LEVEL +#define LOG_FORMAT RTASK_LOG_FORMAT +#include + +#include + +#include +#include + +#include +#include +#include + +#define NEW_TASK SIG_USER0 + +// TODO: Mixing static and dynamic tests in kernel must be tested with care, +// until then use this workaround +#if CONFIG_KERN_HEAP + #define PROC_NEW() proc_new(rtask_proc, NULL, CONFIG_RTASK_STACK, NULL) +#else + PROC_DEFINE_STACK(rtask_stack, CONFIG_RTASK_STACK); + #define PROC_NEW() proc_new(rtask_proc, NULL, sizeof(rtask_stack), rtask_stack) +#endif + + +struct RTask +{ + Timer t; + rtask_cb_t callback; + void *user_data; +}; + +DECLARE_POOL_STATIC(rtask_pool, RTask, CONFIG_RTASK_POOL_SIZE); +static Process *process = NULL; +static List rt_list; +static Semaphore rtask_sem; +#define RTASK_ATOMIC(code) \ + do { \ + sem_obtain(&rtask_sem); \ + code; \ + sem_release(&rtask_sem); \ + } while (0) + +#warning "Remove synctimer_poll and use a list directly" +static NORETURN void rtask_proc(void) +{ + while (1) + { + bool empty; + RTASK_ATOMIC( + empty = LIST_EMPTY(&rt_list); + sig_check(NEW_TASK); + ); + if (empty) + sig_wait(NEW_TASK); + + ticks_t delay; + RTASK_ATOMIC(delay = synctimer_nextTimeout(&rt_list)); + timer_delayTicks(delay); + RTASK_ATOMIC(synctimer_poll(&rt_list)); + } +} + +static void rtask_trampoline(void *_rtask) +{ + // Access the pool and the list freely since this callback is called + // with the semaphore held in rtask_proc. + RTask *rtask = _rtask; + if (rtask->callback(rtask->user_data)) + synctimer_readd(&rtask->t, &rt_list); + else + pool_free(&rtask_pool, rtask); +} + +RTask *rtask_add(rtask_cb_t cb, mtime_t delay, void *cb_data) +{ + // Beware: this function is called from a different process + // than rtask_proc, so each access to rtask_pool and rt_list + // must be protected with a semaphore. + + // The semaphore is not yet initialized, disable preemption + // altogether. + proc_forbid(); + if (UNLIKELY(process == NULL)) + { + MOD_CHECK(proc); + + LIST_INIT(&rt_list); + pool_init(rtask_pool, NULL); + sem_init(&rtask_sem); + process = PROC_NEW(); + ASSERT(process); + } + proc_permit(); + + RTask *rt = NULL; + RTASK_ATOMIC(rt = (RTask *)pool_alloc(&rtask_pool)); + if (rt) + { + rt->callback = cb; + rt->user_data = cb_data; + timer_setSoftint(&rt->t, rtask_trampoline, rt); + timer_setDelay(&rt->t, delay); + RTASK_ATOMIC(synctimer_add(&rt->t, &rt_list)); + sig_send(process, NEW_TASK); + } + else + LOG_ERR("Failed to allocate RTask\n"); + return rt; +} diff --git a/bertos/kern/rtask.h b/bertos/kern/rtask.h new file mode 100644 index 00000000..ce4e430c --- /dev/null +++ b/bertos/kern/rtask.h @@ -0,0 +1,65 @@ +/** + * \file + * + * + * \brief Recurrent task module. + * + * This module is a convenient method to handle multiple recurrent low priority + * tasks. It creates a process with the default priority and schedules all the + * tasks internally. + * You can execute all the operations you want in each callback, since they + * are executed in a different thread from the caller. + * + * Your callback may return true if you want the task to be scheduled + * again, or false if you want the task to end. + * + * Interval time for each task should be fairly high (>20 ms) to avoid + * blocking the whole CPU on this low priority job. + * + * \note rtask_add() may block. + * + * \author Luca Ottaviano + * \author Francesco Sacchi + * + */ + +#ifndef KERNEL_RTASK_H +#define KERNEL_RTASK_H + +#include + +struct RTask; +typedef bool (*rtask_cb_t)(void *user_data); +typedef struct RTask RTask; + +struct RTask *rtask_add(rtask_cb_t cb, mtime_t interval, void *cb_data); + +#endif /* KERNEL_RTASK_H */ -- 2.25.1