rtask.c
Go to the documentation of this file.
00001
00040 #include "rtask.h"
00041 #include "cfg/cfg_rtask.h"
00042 #include <cfg/module.h> // MOD_CHECK
00043
00044 #define LOG_LEVEL RTASK_LOG_LEVEL
00045 #define LOG_FORMAT RTASK_LOG_FORMAT
00046 #include <cfg/log.h>
00047
00048 #include <cpu/types.h>
00049
00050 #include <drv/timer.h>
00051
00052 #include <struct/pool.h>
00053 #include <struct/list.h>
00054
00055 #include <kern/proc.h>
00056 #include <kern/signal.h>
00057 #include <kern/sem.h>
00058
00059 #define NEW_TASK SIG_USER0
00060 
00061 // TODO: Mixing static and dynamic tests in kernel must be tested with care,
00062 // until then use this workaround
00063 #if CONFIG_KERN_HEAP
00064     #define PROC_NEW() proc_new(rtask_proc, NULL, CONFIG_RTASK_STACK, NULL)
00065 #else
00066     PROC_DEFINE_STACK(rtask_stack, CONFIG_RTASK_STACK);
00067     #define PROC_NEW() proc_new(rtask_proc, NULL, sizeof(rtask_stack), rtask_stack)
00068 #endif
00069 
00070
00071 struct RTask
00072 {
00073     Timer t;
00074     rtask_cb_t callback;
00075     void *user_data;
00076 };
00077
00078 DEFINE_POOL_STATIC(rtask_pool, RTask, CONFIG_RTASK_POOL_SIZE);
00079 static Process *process = NULL;
00080 static List rt_list;
00081 static Semaphore rtask_sem;
00082 #define RTASK_ATOMIC(code) \
00083     do {                         \
00084         sem_obtain(&rtask_sem);  \
00085         code;                    \
00086         sem_release(&rtask_sem); \
00087     } while (0)
00088 
00089
00090 //TODO: "Remove synctimer_poll and use a list directly"
00091 static NORETURN void rtask_proc(void)
00092 {
00093     while (1)
00094     {
00095         bool empty;
00096         RTASK_ATOMIC(
00097             empty = LIST_EMPTY(&rt_list);
00098             sig_check(NEW_TASK);
00099         );
00100         if (empty)
00101             sig_wait(NEW_TASK);
00102
00103         ticks_t delay;
00104         RTASK_ATOMIC(delay = synctimer_nextTimeout(&rt_list));
00105         timer_delayTicks(delay);
00106         RTASK_ATOMIC(synctimer_poll(&rt_list));
00107     }
00108 }
00109
00110 static void rtask_trampoline(void *_rtask)
00111 {
00112     // Access the pool and the list freely since this callback is called
00113     // with the semaphore held in rtask_proc.
00114     RTask *rtask = _rtask;
00115     if (rtask->callback(rtask->user_data))
00116         synctimer_readd(&rtask->t, &rt_list);
00117     else
00118         pool_free(&rtask_pool, rtask);
00119 }
00120
00121 RTask *rtask_add(rtask_cb_t cb, mtime_t delay, void *cb_data)
00122 {
00123     // Beware: this function is called from a different process
00124     // than rtask_proc, so each access to rtask_pool and rt_list
00125     // must be protected with a semaphore.
00126
00127     // The semaphore is not yet initialized, disable preemption
00128     // altogether.
00129     proc_forbid();
00130     if (UNLIKELY(process == NULL))
00131     {
00132         MOD_CHECK(proc);
00133
00134         LIST_INIT(&rt_list);
00135         pool_init(rtask_pool, NULL);
00136         sem_init(&rtask_sem);
00137         process = PROC_NEW();
00138         ASSERT(process);
00139     }
00140     proc_permit();
00141
00142     RTask *rt = NULL;
00143     RTASK_ATOMIC(rt = (RTask *)pool_alloc(&rtask_pool));
00144     if (rt)
00145     {
00146         rt->callback = cb;
00147         rt->user_data = cb_data;
00148         timer_setSoftint(&rt->t, rtask_trampoline, rt);
00149         timer_setDelay(&rt->t, ms_to_ticks(delay));
00150         RTASK_ATOMIC(synctimer_add(&rt->t, &rt_list));
00151         sig_send(process, NEW_TASK);
00152     }
00153     else
00154         LOG_ERR("Failed to allocate RTask\n");
00155     return rt;
00156 }