Chapter 3

Working With the Library

3.1  Initializing the Library

Functions

void threads_init(void)   function

This function initializes the library and must be called before calling any other library function. This also designates the current execution state as the primordial thread.

3.2  Starting and Stopping Threads

Functions

void threads_start(volatile thread_data_t* thread, void (*fn)(void), uint16_t* stack, uint16_t stack_size)   function

This function schedules a new thread and sets that thread to the “runnable” state. The caller needs to provide the space for thread and stack. The stack_size argument is the size of stack, in words. The stack space provided is initialized with a particular bit pattern to help detect stack usage.

The new thread is scheduled to follow the current thread. The thread starts life by calling fn. If fn returns, the thread is unscheduled and an implicit task switch occurs.

The call to threads_start() does not force a task switch.

bool threads_stop_current(void)   function

This function unschedules the current thread, even if that thread is the primordial thread. The only limitation is that the last thread in the queue cannot be unscheduled. If the current thread cannot be unscheduled, threads_stop_current() returns false.

The call to threads_stop_current() does not force a task switch, so a task switch must be explicitly performed to move on to the next thread. For example, the following pattern can be used when stopping the current thread:

  // Try to stop the thread
  if (threads_stop_current()) {
    // Stop succeeded, now task switch
    threads_task_switch();
    // Will never get here
  } else {
    // Will get here if stop failed
  }

bool threads_stop(volatile thread_data_t* thread)   function

This function unschedules the given thread, even if that thread is the primordial thread. The only limitation is that the last thread in the queue cannot be unscheduled. If thread cannot be unscheduled, threads_stop() returns false.

3.3  Task Switching

This library uses a cooperative multitasking scheme, so all threads must explicitly request task switches to allow other threads to run.

Functions

void threads_task_switch(void)   function

This function forces a task switch.

Because the library uses cooperative multitasking, this function must be called to allow another thread to run. For smooth multitasking, you should arrange your code so that each thread calls this function periodically.

There is only one situation that leads to an implicit task switch: If the thread function passed to threads_start() ever returns, the thread is unscheduled and an implicit task switch is performed.

3.4  Thread-local Storage

Functions and Macros

void threads_tls_set(volatile thread_data_t* thread, void* tls)   function

This function associates pointer tls with the given thread. This pointer can be retrieved by using threads_tls_get() or threads_tls_current_get().

void* threads_tls_get(volatile thread_data_t* thread)   macro

This function retrieves the pointer associated by threads_tls_set() with the given thread.

void* threads_tls_current_get(void)   macro

This function retrieves the pointer associated by threads_tls_set() with the current thread.

3.5  Thread Management

Functions and Macros

thread_data_t* threads_current_get(void)   macro

This macro retrieves a pointer to the internal thread data for the currently running thread. This pointer can be passed to any of the functions requiring a thread_data_t pointer.

uint16_t threads_stack_usage(const volatile thread_data_t* thread)   function

This function returns the number of stack words that have been used by thread. If thread is the primordial thread, this function returns 0.

void threads_runnable(volatile thread_data_t* thread, bool run_p)   macro

This macro sets the “runnable” state to run_p for thread. Only threads in the “runnable” state will be considered during a task switch. Note that if no thread is in the “runnable” state, a call to threads_task_switch() will result in an infinite loop.