Threading

Support for multi-threading.

Priorities

As RIOT is using a fixed priority scheduling algorithm, threads are scheduled based on their priority. The priority is fixed for every thread and specified during the thread’s creation by the priority parameter.

The lower the priority value, the higher the priority of the thread, with 0 being the highest possible priority.

The lowest possible priority is thread.h::THREAD_PRIORITY_IDLE - 1.

Note

Assigning the same priority to two or more threads is usually not a good idea. A thread in RIOT may run until it yields (thread.h::thread_yield()) or another thread with higher priority is runnable (thread.h::STATUS_ON_RUNQUEUE) again. Multiple threads with the same priority will therefore be scheduled cooperatively: when one of them is running, all others with the same priority depend on it to yield (or be interrupted by a thread with higher priority). This may make it difficult to determine when which of them gets scheduled and how much CPU time they will get. In most applications, the number of threads in application is significantly smaller than the number of available priorities, so assigning distinct priorities per thread should not be a problem. Only assign the same priority to multiple threads if you know what you are doing!

Thread Behavior

In addition to the priority, flags can be used when creating a thread to alter the thread’s behavior after creation. The following flags are available:

Flags Description
thread.h::THREAD_CREATE_SLEEPING the thread will sleep until woken up manually
thread.h::THREAD_CREATE_WOUT_YIELD the thread might not run immediately after creation
thread.h::THREAD_CREATE_STACKTEST measures the stack’s memory usage

Thread creation

Creating a new thread is internally done in two steps:

  1. the new thread’s stack is initialized depending on the platform
  2. the new thread is added to the scheduler and the scheduler is run (if not indicated otherwise)

Note

Creating threads from within an ISR is currently supported, however it is considered to be a bad programming practice and we strongly discourage you from doing so.

Usage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "thread.h"

char rcv_thread_stack[THREAD_STACKSIZE_MAIN];

void *rcv_thread(void *arg)
{
    (void) arg;
    msg_t m;

    while (1) {
        msg_receive(&m);
        printf("Got msg from %" PRIkernel_pid "\n", m.sender_pid);
    }

    return NULL;
}

int main(void)
{
    thread_create(rcv_thread_stack, sizeof(rcv_thread_stack),
                  THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST,
                  rcv_thread, NULL, "rcv_thread");
}

Reading from the top down, you can see that first, stack memory for our thread rcv_thread is preallocated, followed by an implementation of the thread’s function. Communication between threads is done using Messaging / IPC. In this case, rcv_thread will print the process id of each thread that sent a message to rcv_thread.

After it has been properly defined, rcv_thread is created with a call to thread.h::thread_create() in main(). It is assigned a priority of THREAD_PRIORITY_MAIN - 1, i.e. a slightly higher priority than the main thread. Since neither the THREAD_CREATE_SLEEPING nor the THREAD_CREATE_WOUT_YIELD flag is set, rcv_thread will be executed immediately.

Note

If the messages to the thread are sent using msg.h::msg_try_send() or from an ISR, activate your thread’s message queue by calling msg.h::msg_init_queue() to prevent messages from being dropped when they can’t be handled right away. The same applies if you’d like msg.h::msg_send() to your thread to be non-blocking. For more details, see the Messaging documentation.

Usage

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "thread.h"

char rcv_thread_stack[THREAD_STACKSIZE_MAIN];

void *rcv_thread(void *arg)
{
    (void) arg;
    msg_t m;

    while (1) {
        msg_receive(&m);
        printf("Got msg from %" PRIkernel_pid "\n", m.sender_pid);
    }

    return NULL;
}

int main(void)
{
    thread_create(rcv_thread_stack, sizeof(rcv_thread_stack),
                  THREAD_PRIORITY_MAIN - 1, THREAD_CREATE_STACKTEST,
                  rcv_thread, NULL, "rcv_thread");
}

Reading from the top down, you can see that first, stack memory for our thread rcv_thread is preallocated, followed by an implementation of the thread’s function. Communication between threads is done using Messaging / IPC. In this case, rcv_thread will print the process id of each thread that sent a message to rcv_thread.

After it has been properly defined, rcv_thread is created with a call to thread.h::thread_create() in main(). It is assigned a priority of THREAD_PRIORITY_MAIN - 1, i.e. a slightly higher priority than the main thread. Since neither the THREAD_CREATE_SLEEPING nor the THREAD_CREATE_WOUT_YIELD flag is set, rcv_thread will be executed immediately.

Note

If the messages to the thread are sent using msg.h::msg_try_send() or from an ISR, activate your thread’s message queue by calling msg.h::msg_init_queue() to prevent messages from being dropped when they can’t be handled right away. The same applies if you’d like msg.h::msg_send() to your thread to be non-blocking. For more details, see the Messaging documentation.

STATUS_NOT_FOUND

Describes an illegal thread status.

1
(-1)
STATUS_STOPPED

has terminated

1
0
STATUS_SLEEPING

sleeping

1
1
STATUS_MUTEX_BLOCKED

waiting for a locked mutex

1
2
STATUS_RECEIVE_BLOCKED

waiting for a message

1
3
STATUS_SEND_BLOCKED

waiting for message to be delivered

1
4
STATUS_REPLY_BLOCKED

waiting for a message response

1
5
STATUS_FLAG_BLOCKED_ANY

waiting for any flag from flag_mask

1
6
STATUS_FLAG_BLOCKED_ALL

waiting for all flags in flag_mask

1
7
STATUS_MBOX_BLOCKED

waiting for get/put on mbox

1
8
STATUS_ON_RUNQUEUE

to check if on run queue: st >= STATUS_ON_RUNQUEUE

1
STATUS_RUNNING
STATUS_RUNNING

currently running

1
9
STATUS_PENDING

waiting to be scheduled to run

1
10
THREAD_CREATE_SLEEPING

Set the new thread to sleeping.

1
(1)

It must be woken up manually.

THREAD_AUTO_FREE

Currently not implemented.

1
(2)
THREAD_CREATE_WOUT_YIELD

Do not automatically call thread.h::thread_yield() after creation: the newly created thread might not run immediately.

1
(4)

Purely for optimization. Any other context switch (i.e. an interrupt) can still start the thread at any time!

THREAD_CREATE_STACKTEST

Write markers into the thread’s stack to measure stack usage (for debugging and profiling purposes)

1
(8)
void *(* thread_task_func_t()

Prototype for a thread entry function.

kernel_types.h::kernel_pid_t thread_create(char * stack, int stacksize, char priority, int flags, thread.h::thread_task_func_t task_func, void * arg, const char * name)

Creates a new thread.

For an in-depth discussion of thread priorities, behavior and and flags, see Threading.

Note

Avoid assigning the same priority to two or more threads.

Note

Creating threads from within an ISR is currently supported, however it is considered to be a bad programming practice and we strongly discourage you from doing so.

Parameters

stack:start address of the preallocated stack memory
stacksize:the size of the thread’s stack in bytes
priority:priority of the new thread, lower mean higher priority
flags:optional flags for the creation of the new thread
task_func:pointer to the code that is executed in the new thread
arg:the argument to the function
name:a human readable descriptor for the thread

Return values

  • PID of newly created task on success
  • -EINVAL, if priority is greater than or equal to sched.h::SCHED_PRIO_LEVELS
  • -EOVERFLOW, if there are too many threads running already
sched.h::thread_t * thread_get(kernel_types.h::kernel_pid_t pid)

Retreive a thread control block by PID.

This is a bound-checked variant of accessing sched_threads[pid] directly. If you know that the PID is valid, then don’t use this function.

Parameters

pid:Thread to retreive.

Return values

  • NULL if the PID is invalid or there is no such thread.
int thread_getstatus(kernel_types.h::kernel_pid_t pid)

Returns the status of a process.

Parameters

pid:the PID of the thread to get the status from

Return values

  • status of the thread
  • STATUS_NOT_FOUND if pid is unknown
void thread_sleep(void)

Puts the current thread into sleep mode.

Has to be woken up externally.

void thread_yield(void)

Lets current thread yield.

The current thread will resume operation immediately, if there is no other ready thread with the same or a higher priority.

Differently from thread.h::thread_yield_higher() the current thread will be put to the end of the thread’s in its priority class.

void thread_yield_higher(void)

Lets current thread yield in favor of a higher prioritized thread.

The current thread will resume operation immediately, if there is no other ready thread with a higher priority.

Differently from thread.h::thread_yield() the current thread will be scheduled next in its own priority class, i.e. it stays the first thread in its priority class.

int thread_wakeup(kernel_types.h::kernel_pid_t pid)

Wakes up a sleeping thread.

Parameters

pid:the PID of the thread to be woken up

Return values

  • 1 on success
  • STATUS_NOT_FOUND if pid is unknown or not sleeping
kernel_types.h::kernel_pid_t thread_getpid(void)

Returns the process ID of the currently running thread.

Return values

  • obviously you are not a golfer.
char * thread_stack_init(thread.h::thread_task_func_t task_func, void * arg, void * stack_start, int stack_size)

Gets called upon thread creation to set CPU registers.

Parameters

task_func:First function to call within the thread
arg:Argument to supply to task_func
stack_start:Start address of the stack
stack_size:Stack size

Return values

  • stack pointer
void thread_add_to_list(list.h::list_node_t * list, sched.h::thread_t * thread)

Add thread to list, sorted by priority (internal)

This will add thread to list sorted by the thread priority. It reuses the thread’s rq_entry field. Used internally by msg and mutex implementations.

Note

Only use for threads not on any runqueue and with interrupts disabled.

Parameters

list:ptr to list root node
thread:thread to add

const char * thread_getname(kernel_types.h::kernel_pid_t pid)

Returns the name of a process.

Note

when compiling without DEVELHELP, this always returns NULL!

Parameters

pid:the PID of the thread to get the name from

Return values

  • the threads name
  • NULL if pid is unknown
uintptr_t thread_measure_stack_free(char * stack)

Measures the stack usage of a stack.

Only works if the thread was created with the flag THREAD_CREATE_STACKTEST.

Parameters

stack:the stack you want to measure. try sched_active_thread->stack_start

Return values

  • the amount of unused space of the thread’s stack
int thread_isr_stack_usage(void)

Get the number of bytes used on the ISR stack.

void * thread_isr_stack_pointer(void)

Get the current ISR stack pointer.

void * thread_isr_stack_start(void)

Get the start of the ISR stack.

void thread_stack_print(void)

Print the current stack to stdout.

void thread_print_stack(void)

Prints human readable, ps-like thread information for debugging purposes.

THREAD_STACKSIZE_DEFAULT

A reasonable default stack size that will suffice most smaller tasks.

Note

This value must be defined by the CPU specific implementation, please take a look at cpu/$CPU/include/cpu_conf.h

THREAD_STACKSIZE_IDLE

Size of the idle task’s stack in bytes.

Note

This value must be defined by the CPU specific implementation, please take a look at cpu/$CPU/include/cpu_conf.h

THREAD_EXTRA_STACKSIZE_PRINTF

Size of the task’s printf stack in bytes.

Note

This value must be defined by the CPU specific implementation, please take a look at cpu/$CPU/include/cpu_conf.h

THREAD_STACKSIZE_MAIN

Size of the main task’s stack in bytes.

1
(THREAD_STACKSIZE_DEFAULT + THREAD_EXTRA_STACKSIZE_PRINTF)
THREAD_STACKSIZE_LARGE

Large stack size.

1
(THREAD_STACKSIZE_MEDIUM * 2)
THREAD_STACKSIZE_MEDIUM

Medium stack size.

1
THREAD_STACKSIZE_DEFAULT
THREAD_STACKSIZE_SMALL

Small stack size.

1
(THREAD_STACKSIZE_MEDIUM / 2)
THREAD_STACKSIZE_TINY

Tiny stack size.

1
(THREAD_STACKSIZE_MEDIUM / 4)
THREAD_STACKSIZE_MINIMUM

Minimum stack size.

1
(sizeof(thread_t))
THREAD_PRIORITY_MIN

Least priority a thread can have.

1
(SCHED_PRIO_LEVELS-1)
THREAD_PRIORITY_IDLE

Priority of the idle thread.

1
(THREAD_PRIORITY_MIN)
THREAD_PRIORITY_MAIN

Priority of the main thread.

1
(THREAD_PRIORITY_MIN - (SCHED_PRIO_LEVELS/2))
struct _thread

thread_t holds thread’s context data.

char * sp

thread’s stack pointer

uint8_t status

thread’s status

uint8_t priority

thread’s priority

kernel_types.h::kernel_pid_t pid

thread’s process id

thread_flags.h::thread_flags_t flags

currently set flags

clist.h::clist_node_t rq_entry

run queue entry

void * wait_data

used by msg, mbox and thread flags

list.h::list_node_t msg_waiters

threads waiting for their message to be delivered to this thread (i.e.

all blocked sends)

cib_t msg_queue

index of this [thread’s message queue] (thread.h::_thread::msg_array), if any

msg_t * msg_array

memory holding messages sent to this thread’s message queue

char * stack_start

thread’s stack start address

const char * name

thread’s name

int stack_size

thread’s stack size