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
os_task_state
¶ Task states.
Values:
-
enumerator
OS_TASK_READY
¶ Task is ready to run.
-
enumerator
OS_TASK_SLEEP
¶ Task is sleeping.
-
enumerator
-
typedef enum os_task_state
os_task_state_t
¶ Task states.
-
typedef void (*
os_task_func_t
)(void *arg)¶ Type definition for a task callback function.
- Parameters
arg
: Argument passed to the task function.
-
int
os_task_init
(struct os_task *t, const char *name, os_task_func_t func, void *arg, uint8_t prio, os_time_t sanity_itvl, os_stack_t *stack_bottom, uint16_t stack_size)¶ 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 initializename
: The name of the task to initializefunc
: The task function to callarg
: The argument to pass to this task functionprio
: The priority at which to run this tasksanity_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 stackstack_size
: The overall size of the task’s stack.
-
int
os_task_remove
(struct os_task *t)¶ Removes specified task.
- Return
0 on success; non-zero on failure
- Note
This interface is currently experimental and not ready for common use
- Parameters
t
: The task to remove
-
os_stack_t *
os_task_stacktop_get
(struct os_task *t)¶ Return a pointer to the top of the stack for a given task.
- Return
A pointer to the top of the stack
- Parameters
t
: The task to get the top of the stack from
-
uint8_t
os_task_count
(void)¶ Return the number of tasks initialized.
- Return
The number of tasks initialized
-
struct os_task *
os_task_info_get_next
(const struct os_task *prev, struct os_task_info *oti)¶ 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; 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.
-
void
os_task_info_get
(const struct os_task *task, struct os_task_info *oti)¶ Get following info about specified task.
Priority
Task ID
State (READY, SLEEP)
Total Stack Usage
Stack Size
Context Switch Count
Runtime
Last & Next Sanity checkin
Task Name
- Parameters
task
: The task to get info aboutoti
: The OS task info structure to fill out.
-
OS_TASK_STACK_DEFINE_NOSTATIC
(__name, __size)¶ Defines a non-static task stack.
- Parameters
__name
: The name of the stack.__size
: The size of the stack in bytes.
-
OS_TASK_STACK_DEFINE
(__name, __size)¶ Defines a static task stack.
- Parameters
__name
: The name of the stack.__size
: The size of the stack in bytes.
-
OS_TASK_PRI_HIGHEST
¶ Highest priority task.
-
OS_TASK_PRI_LOWEST
¶ Lowest priority task.
-
OS_TASK_FLAG_NO_TIMEOUT
¶ Task waiting forever.
-
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
¶ Maximum length of a task name.
-
struct
os_task_obj
¶ - #include <os_task.h>
Generic “object” structure.
All objects that a task can wait on must have a SLIST_HEAD(, os_task) head_name as the first element in the object structure. The element ‘head_name’ can be any name. See os_mutex.h or os_sem.h for an example.
Public Functions
-
SLIST_HEAD (, os_task) obj_head
Head of the list of waiting tasks.
-
-
struct
os_task
¶ - #include <os_task.h>
Structure containing information about a running task.
Public Functions
-
STAILQ_ENTRY (os_task) t_os_task_list
Entry for a singly-linked task list.
-
TAILQ_ENTRY (os_task) t_os_list
Entry for a doubly-linked list of tasks managed by the scheduler.
-
SLIST_ENTRY (os_task) t_obj_list
Entry for a singly-linked object list.
Public Members
-
os_stack_t *
t_stackptr
¶ Current stack pointer for this task.
-
os_stack_t *
t_stackbottom
¶ Pointer to bottom 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_state
¶ Task state, either READY or SLEEP.
-
uint8_t
t_flags
¶ Task flags, bitmask.
-
uint8_t
t_lockcnt
¶ Task lock count.
-
uint8_t
t_pad
¶ Padding for alignment.
-
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.
-
union os_task.[anonymous] [anonymous]¶
Current object task is waiting on, either a semaphore or mutex.
-
struct os_sanity_check
t_sanity_check
¶ Default sanity check for this task.
-
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.
-
char
oti_name
[OS_TASK_MAX_NAME_LEN
]¶ Name of this task.
-
uint8_t