Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ ifneq (,$(filter ndn-riot,$(USEPKG)))
USEPKG += micro-ecc
endif

ifneq (,$(filter core_tasklet,$(USEMODULE)))
USEMODULE += core_thread_flags
endif

ifneq (,$(filter csma_sender,$(USEMODULE)))
USEMODULE += random
USEMODULE += xtimer
Expand Down
2 changes: 1 addition & 1 deletion core/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# exclude submodule sources from *.c wildcard source selection
SRC := $(filter-out mbox.c msg.c thread_flags.c,$(wildcard *.c))
SRC := $(filter-out mbox.c msg.c tasklet.c thread_flags.c,$(wildcard *.c))

# enable submodules
SUBMODULES := 1
Expand Down
140 changes: 140 additions & 0 deletions core/include/tasklet.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright (C) 2019 HAW Hamburg
*
* 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 core_tasklet Tasklets
* @ingroup core
* @{
*
* @file
* @brief Support for kernel tasklets
*
* A tasklet is a function that is scheduled to run at a kernel-determined
* safe time. When scheduled, the OS will try to run the task as soon as possible.
*
* They might be scheduled several times, but will only run once
* (after that it's possible to schedule the same task again).
* Scheduling tasks is a thread safe operation.
*
* Internally the OS creates a thread with the highest priority that listens
* to a thread flag with type @ref THREAD_FLAG_TASKLET.
*
* Tasklets are ideal for offloading ISR (radio drivers, timers, etc).
*
* Tasklets are not ISR nor thread safe (although they run in the highest
* priority). Thus, synchronization between a module and its tasklets is up to
* the implementer.
*
* This API is optional and must be enabled by adding "core_tasklet" to USEMODULE.
*
* The current implementation doesn't support (yet) prorities for different
* tasklets.
*
* @author Jose I. Alamos <jose.alamos@haw-hamburg.de>
*/

#ifndef TASKLET_H
#define TASKLET_H

#include <string.h>

#include "clist.h"

/**
* @brief Stack size of the tasklets thread
*/
#ifndef THREAD_STACKSIZE_TASKLET
#define THREAD_STACKSIZE_TASKLET (THREAD_STACKSIZE_DEFAULT)
#endif

#ifdef __cplusplus
extern "C" {
#endif

/**
* @brief Tasklet descriptor
*/
typedef struct {
clist_node_t tasklet_node; /**< circular list node of the tasklet */
void (*task)(void *arg); /**< the function to be called when processing the tasklet */
void *arg; /**< the argument of the task */
} tasklet_t;

/**
* @brief Init a tasklet with a given function and argument.
*
* @param[in] tasklet Tasklet to be initialized.
* @param[in] task Function to be called when processing the tasklet.
* @param[in] arg The argument of the task.
*/
static inline void tasklet_init(tasklet_t *tasklet, void (*task)(void *arg), void *arg)
{
memset(tasklet, '\0', sizeof(tasklet_t));
tasklet->task = task;
tasklet->arg = arg;
}

/**
* @brief Schedule a tasklet.
*
* The task function assigned to @p tasklet will be called as soon as possible
* in kernel thread context. It's possible to schedule a task from within an
* Interrupt Service Routine.
*
* This function is thread safe.
*
* @note A tasklet must be initialized with @ref tasklet_init!.
*
* @param[in] tasklet Tasklet to be scheduled.
*/
void tasklet_schedule(tasklet_t *tasklet);

/**
* @brief Create the tasklet thread.
*
* This function is internally called by the kernel in order to
* initialize the tasklet mechanism.
*/
void tasklet_thread_create(void);

/**
* @brief Pop a tasklet from the tasklet FIFO list.
*
* This function is thread safe.
*
* @return First (leftmost) element of the tasklet list.
* @return NULL if the list is empty.
*/
tasklet_t *tasklet_pop(void);

/**
* @brief Add a tasklet to the tasklet list.
*
* This function is thread safe
*
* @note This function is exposed only for testing reasons. To schedule
* a tasklet, use @ref tasklet_schedule instead.
*
* @param[in] tasklet Tasklet to be added.
*/
void tasklet_add(tasklet_t *tasklet);

/**
* @brief Reset the tasklet list
*
* @note This function is exposed only for testing reasons. It shouldn't be
* called outside of the kernel!
*/
void tasklet_list_reset(void);

#ifdef __cplusplus
}
#endif

#endif /* TASKLET_H */
/** @} */
8 changes: 8 additions & 0 deletions core/include/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,14 @@ struct _thread {
#define THREAD_PRIORITY_MAIN (THREAD_PRIORITY_MIN - (SCHED_PRIO_LEVELS/2))
#endif

/**
* @def THREAD_PRIORITY_TASKLET
* @brief Priority of the tasklet thread (see @ref core_tasklet)
*/
#ifndef THREAD_PRIORITY_TASKLET
#define THREAD_PRIORITY_TASKLET (0)
#endif

/**
* @name Optional flags for controlling a threads initial state
* @{
Expand Down
5 changes: 5 additions & 0 deletions core/include/thread_flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ extern "C" {
* @see xtimer_set_timeout_flag
*/
#define THREAD_FLAG_TIMEOUT (1u << 14)

/**
* @brief Set by @ref tasklet_schedule
*/
#define THREAD_FLAG_TASKLET (1u << 13)
/** @} */

/**
Expand Down
8 changes: 8 additions & 0 deletions core/kernel_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
#include <auto_init.h>
#endif

#ifdef MODULE_CORE_TASKLET
#include "tasklet.h"
#endif

extern int main(void);
static void *main_trampoline(void *arg)
{
Expand Down Expand Up @@ -72,6 +76,10 @@ void kernel_init(void)
{
(void) irq_disable();

#ifdef MODULE_CORE_TASKLET
tasklet_thread_create();
#endif

thread_create(idle_stack, sizeof(idle_stack),
THREAD_PRIORITY_IDLE,
THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST,
Expand Down
75 changes: 75 additions & 0 deletions core/tasklet.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright (C) 2019 HAW Hamburg
*
* 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.
*/

#include <string.h>

#include "irq.h"
#include "tasklet.h"
#include "thread.h"
#include "thread_flags.h"

static thread_t *__tasklet_thread;
static clist_node_t tasklet_list;

static char tasklet_stack[THREAD_STACKSIZE_TASKLET];
const char *tasklet_name = "tasklet";

void tasklet_add(tasklet_t *tasklet)
{
unsigned state = irq_disable();
if (!tasklet->tasklet_node.next) {
clist_rpush(&tasklet_list, &tasklet->tasklet_node);
}
irq_restore(state);
}

void tasklet_schedule(tasklet_t *tasklet)
{
assert(tasklet);
assert(__tasklet_thread);

tasklet_add(tasklet);
thread_flags_set(__tasklet_thread, THREAD_FLAG_TASKLET);
}

tasklet_t *tasklet_pop(void)
{
tasklet_t *res;
unsigned state = irq_disable();
res = (tasklet_t *)clist_lpop(&tasklet_list);
if(res) {
res->tasklet_node.next = NULL;
}
irq_restore(state);
return res;
}

static void *tasklet_thread(void *arg)
{
(void) arg;
tasklet_t *res;
while(thread_flags_wait_any(THREAD_FLAG_TASKLET)) {
while((res = tasklet_pop())) {
res->task(res->arg);
}
}
return NULL;
}

void tasklet_list_reset(void)
{
memset(&tasklet_list, '\0', sizeof(clist_node_t));
}

void tasklet_thread_create(void)
{
__tasklet_thread = (thread_t*) thread_get(thread_create(tasklet_stack, sizeof(tasklet_stack),
THREAD_PRIORITY_TASKLET,
THREAD_CREATE_WOUT_YIELD | THREAD_CREATE_STACKTEST,
tasklet_thread, NULL, tasklet_name));
}
1 change: 1 addition & 0 deletions tests/unittests/tests-tasklet/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
1 change: 1 addition & 0 deletions tests/unittests/tests-tasklet/Makefile.include
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
USEMODULE += core_tasklet
Loading