Task

A task, along with the scheduler, forms the basis of the Mynewt OS. A task consists of two basic elements: a task stack and a task function. The task function is basically a forever loop, waiting for some “event” to wake it up. There are two methods used to signal a task that it has work to do: event queues and semaphores (see the appropriate manual sections for descriptions of these features).

The Mynewt OS is a multi-tasking, preemptive OS. Every task is assigned a task priority (from 0 to 255), with 0 being the highest priority task. If a higher priority task than the current task wants to run, the scheduler preempts the currently running task and switches context to the higher priority task. This is just a fancy way of saying that the processor stack pointer now points to the stack of the higher priority task and the task resumes execution where it left off.

Tasks run to completion unless they are preempted by a higher priority task. The developer must insure that tasks eventually “sleep”; otherwise lower priority tasks will never get a chance to run (actually, any task lower in priority than the task that never sleeps). A task will be put to sleep in the following cases: it puts itself to sleep using os_time_delay(), it waits on an event queue which is empty or attempts to obtain a mutex or a semaphore that is currently owned by another task.

Note that other sections of the manual describe these OS features in more detail.

Description

In order to create a task two data structures need to be defined: the task object (struct os_task) and its associated stack. Determining the stack size can be a bit tricky; generally developers should not declare large local variables on the stack so that task stacks can be of limited size. However, all applications are different and the developer must choose the stack size accordingly. NOTE: be careful when declaring your stack! The stack is in units of os_stack_t sized elements (generally 32-bits). Looking at the example given below and assuming os_stack_t is defined to be a 32-bit unsigned value, “my_task_stack” will use 256 bytes.

A task must also have an associated “task function”. This is the function that will be called when the task is first run. This task function should never return!

In order to inform the Mynewt OS of the new task and to have it added to the scheduler, the os_task_init() function is called. Once os_task_init() is called, the task is made ready to run and is added to the active task list. Note that a task can be initialized (started) before or after the os has started (i.e. before os_start() is called) but must be initialized after the os has been initialized (i.e. os_init() has been called). In most of the examples and current Mynewt projects, the os is initialized, tasks are initialized, and the the os is started. Once the os has started, the highest priority task will be the first task set to run.

Information about a task can be obtained using the os_task_info_get_next() API. Developers can walk the list of tasks to obtain information on all created tasks. This information is of type os_task_info.

The following is a very simple example showing a single application task. This task simply toggles an LED at a one second interval.

/* Create a simple "project" with a task that blinks a LED every second */

/* Define task stack and task object */
#define MY_TASK_PRI         (OS_TASK_PRI_HIGHEST)
#define MY_STACK_SIZE       (64)
struct os_task my_task;
os_stack_t my_task_stack[MY_STACK_SIZE];

/* This is the task function */
void my_task_func(void *arg) {
    /* Set the led pin as an output */
    hal_gpio_init_out(LED_BLINK_PIN, 1);

    /* The task is a forever loop that does not return */
    while (1) {
        /* Wait one second */
        os_time_delay(1000);

        /* Toggle the LED */
        hal_gpio_toggle(LED_BLINK_PIN);
    }
}

/* This is the main function for the project */
int main(int argc, char **argv)
{

    /* Perform system and package initialization */
    sysinit();

    /* Initialize the task */
    os_task_init(&my_task, "my_task", my_task_func, NULL, MY_TASK_PRIO,
                 OS_WAIT_FOREVER, my_task_stack, MY_STACK_SIZE);

    /*  Process events from the default event queue.  */
    while (1) {
       os_eventq_run(os_eventq_dflt_get());
    }
    /* main never returns */
}

API

enum OSTask::os_task_state

Task states.

Values:

OS_TASK_READY = 1

Task is ready to run.

OS_TASK_SLEEP = 2

Task is sleeping.

typedef enum os_task_state os_task_state_t

Task states.

typedef void(* os_task_func_t)(void *)
int os_task_init(struct os_task  *, const char *, os_task_func_t, void *, uint8_t, os_time_t, os_stack_t  *, uint16_t)

Initialize a task.

This function initializes the task structure pointed to by t, clearing and setting it’s stack pointer, provides sane defaults and sets the task as ready to run, and inserts it into the operating system scheduler.

Return
0 on success, non-zero on failure.
Parameters
  • t: The task to initialize
  • name: The name of the task to initialize
  • func: The task function to call
  • arg: The argument to pass to this task function
  • prio: The priority at which to run this task
  • sanity_itvl: The time at which this task should check in with the sanity task. OS_WAIT_FOREVER means never check in here.
  • stack_bottom: A pointer to the bottom of a task’s stack
  • stack_size: The overall size of the task’s stack.

int os_task_remove(struct os_task * t)

Removes specified task XXX NOTE: This interface is currently experimental and not ready for common use.

uint8_t os_task_count(void)

Return the number of tasks initialized.

Return
number of tasks initialized

struct os_task* os_task_info_get_next(const struct os_task  *, struct os_task_info  *)

Iterate through tasks, and return the following information about them:

  • Priority
  • Task ID
  • State (READY, SLEEP)
  • Total Stack Usage
  • Stack Size
  • Context Switch Count
  • Runtime
  • Last & Next Sanity checkin
  • Task Name

To get the first task in the list, call os_task_info_get_next() with a NULL pointer in the prev argument, and os_task_info_get_next() will return a pointer to the task structure, and fill out the os_task_info structure pointed to by oti.

To get the next task in the list, provide the task structure returned by the previous call to os_task_info_get_next(), and os_task_info_get_next() will fill out the task structure pointed to by oti again, and return the next task in the list.

Return
A pointer to the OS task that has been read, or NULL when finished iterating through all tasks.
Parameters
  • prev: The previous task returned by os_task_info_get_next(), or NULL to begin iteration.
  • oti: The OS task info structure to fill out.

OS_TASK_STACK_DEFINE_NOSTATIC(__name, __size)
OS_TASK_STACK_DEFINE(__name, __size)
OS_TASK_PRI_HIGHEST

Highest priority task.

OS_TASK_PRI_LOWEST

Lowest priority task.

OS_TASK_FLAG_NO_TIMEOUT
OS_TASK_FLAG_SEM_WAIT

Task waiting on a semaphore.

OS_TASK_FLAG_MUTEX_WAIT

Task waiting on a mutex.

OS_TASK_FLAG_EVQ_WAIT

Task waiting on a event queue.

OS_TASK_MAX_NAME_LEN
struct os_task
#include <os_task.h>

Structure containing information about a running task.

Public Members

os_stack_t* t_stackptr

Current stack pointer for this task.

os_stack_t* t_stacktop

Pointer to top of this task’s stack.

uint16_t t_stacksize

Size of this task’s stack.

uint8_t t_taskid

Task ID.

uint8_t t_prio

Task Priority.

uint8_t t_flags

Task flags, bitmask.

const char* t_name

Task name.

os_task_func_t t_func

Task function that executes.

void* t_arg

Argument to pass to task function when called.

void* t_obj

Current object task is waiting on, either a semaphore or mutex.

struct os_sanity_check t_sanity_check

Default sanity check for this task.

os_time_t t_next_wakeup

Next scheduled wakeup if this task is sleeping.

os_time_t t_run_time

Total task run time.

uint32_t t_ctx_sw_cnt

Total number of times this task has been context switched during execution.

struct os_task_info
#include <os_task.h>

Information about an individual task, returned for management APIs.

Public Members

uint8_t oti_prio

Task priority.

uint8_t oti_taskid

Task identifier.

uint8_t oti_state

Task state, either READY or SLEEP.

uint16_t oti_stkusage

Task stack usage.

uint16_t oti_stksize

Task stack size.

uint32_t oti_cswcnt

Task context switch count.

uint32_t oti_runtime

Task runtime.

os_time_t oti_last_checkin

Last time this task checked in with sanity.

os_time_t oti_next_checkin

Next time this task is scheduled to check-in with sanity.

char os_task_info::oti_name[OS_TASK_MAX_NAME_LEN]

Name of this task.