zephyr/kernel/nanokernel/nano_fiber.c
Benjamin Walsh 0dcad8331b clarify use of term 'context'
The term 'context' is vague and overloaded. Its usage for 'an execution
context' is now referred as such, in both comments and some APIs' names.
When the execution context can only be a fiber or a task (i.e. not an
ISR), it is referred to as a 'thread', again in comments and everywhere
in the code.

APIs that had their names changed:

  - nano_context_id_t is now nano_thread_id_t
  - context_self_get() is now sys_thread_self_get()
  - context_type_get() is now sys_execution_context_type_get()
  - context_custom_data_set/get() are now
    sys_thread_custom_data_set/get()

The 'context' prefix namespace does not have to be reserved by the
kernel anymore.

The Context Control Structure (CCS) data structure is now the Thread
Control Structure (TCS):

  - struct ccs is now struct tcs
  - tCCS is now tTCS

Change-Id: I7526a76c5b01e7c86333078e2d2e77c9feef5364
Signed-off-by: Benjamin Walsh <benjamin.walsh@windriver.com>
2016-02-05 20:15:27 -05:00

240 lines
6.3 KiB
C

/*
* Copyright (c) 2010-2014 Wind River Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2) Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3) Neither the name of Wind River Systems nor the names of its contributors
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* @brief Nanokernel fiber support primitives
*
* This module provides various nanokernel fiber related primitives,
* either in the form of an actual function or an alias to a function.
*/
#include <nano_private.h>
#include <string.h>
#include <toolchain.h>
#include <sections.h>
/**
*
* @brief Add a fiber to the list of runnable fibers
*
* The list of runnable fibers is maintained via a single linked list
* in priority order. Numerically lower priorities represent higher priority
* fibers.
*
* Interrupts must already be locked to ensure list cannot change
* while this routine is executing!
*
* @return N/A
*/
void _nano_fiber_schedule(struct tcs *tcs)
{
struct tcs *pQ = (struct tcs *)&_nanokernel.fiber;
/*
* Search until end of list or until a fiber with numerically
* higher priority is located.
*/
while (pQ->link && (tcs->prio >= pQ->link->prio)) {
pQ = pQ->link;
}
/* Insert fiber, following any equal priority fibers */
tcs->link = pQ->link;
pQ->link = tcs;
}
/* currently the fiber and task implementations are identical */
FUNC_ALIAS(_fiber_start, fiber_fiber_start, void);
FUNC_ALIAS(_fiber_start, task_fiber_start, void);
FUNC_ALIAS(_fiber_start, fiber_start, void);
void _fiber_start(char *pStack,
unsigned stackSize, /* stack size in bytes */
nano_fiber_entry_t pEntry,
int parameter1,
int parameter2,
unsigned priority,
unsigned options)
{
struct tcs *tcs;
unsigned int imask;
tcs = (struct tcs *) pStack;
_new_thread(pStack,
stackSize,
(_thread_entry_t)pEntry,
(void *)parameter1,
(void *)parameter2,
(void *)0,
priority,
options);
/* _new_thread() has already set the flags depending on the 'options'
* and 'priority' parameters passed to it */
/* lock interrupts to prevent corruption of the runnable fiber list */
imask = irq_lock();
/* make the newly crafted TCS a runnable fiber */
_nano_fiber_schedule(tcs);
/*
* Simply return to the caller if the current thread is FIBER,
* otherwise swap into the newly created fiber
*/
if ((_nanokernel.current->flags & TASK) == TASK)
_Swap(imask);
else
irq_unlock(imask);
}
void fiber_yield(void)
{
unsigned int imask = irq_lock();
if ((_nanokernel.fiber != (struct tcs *)NULL) &&
(_nanokernel.current->prio >= _nanokernel.fiber->prio)) {
/*
* Reinsert current thread into the list of runnable threads,
* and
* then swap to the thread at the head of the fiber list.
*/
_nano_fiber_schedule(_nanokernel.current);
_Swap(imask);
} else
irq_unlock(imask);
}
/**
*
* @brief Pass control from the currently executing fiber
*
* This routine is used when a fiber voluntarily gives up control of the CPU.
*
* This routine can only be called from a fiber.
*
* @return This function never returns
*/
FUNC_NORETURN void _nano_fiber_swap(void)
{
unsigned int imask;
/*
* Since the currently running fiber is not queued onto the runnable
* fiber list, simply performing a _Swap() shall initiate a context
* switch to the highest priority fiber, or the highest priority task
* if there are no runnable fibers.
*/
imask = irq_lock();
_Swap(imask);
/*
* Compiler can't know that _Swap() won't return and will issue a
* warning
* unless we explicitly tell it that control never gets this far.
*/
CODE_UNREACHABLE;
}
#ifndef CONFIG_ARCH_HAS_NANO_FIBER_ABORT
FUNC_NORETURN void fiber_abort(void)
{
/* Do normal thread exit cleanup, then give up CPU control */
_thread_exit(_nanokernel.current);
_nano_fiber_swap();
}
#endif
#ifdef CONFIG_NANO_TIMEOUTS
#include <wait_q.h>
void fiber_sleep(int32_t timeout_in_ticks)
{
int key;
if (TICKS_NONE == timeout_in_ticks) {
fiber_yield();
return;
}
key = irq_lock();
_nano_timeout_add(_nanokernel.current, NULL, timeout_in_ticks);
_Swap(key);
}
FUNC_ALIAS(fiber_delayed_start, fiber_fiber_delayed_start, void *);
FUNC_ALIAS(fiber_delayed_start, task_fiber_delayed_start, void *);
void *fiber_delayed_start(char *stack, unsigned int stack_size_in_bytes,
nano_fiber_entry_t entry_point, int param1,
int param2, unsigned int priority,
unsigned int options, int32_t timeout_in_ticks)
{
unsigned int key;
struct tcs *tcs;
tcs = (struct tcs *)stack;
_new_thread(stack, stack_size_in_bytes, (_thread_entry_t)entry_point,
(void *)param1, (void *)param2, (void *)0, priority, options);
key = irq_lock();
_nano_timeout_add(tcs, NULL, timeout_in_ticks);
irq_unlock(key);
return tcs;
}
FUNC_ALIAS(fiber_delayed_start_cancel, fiber_fiber_delayed_start_cancel, void);
FUNC_ALIAS(fiber_delayed_start_cancel, task_fiber_delayed_start_cancel, void);
void fiber_delayed_start_cancel(void *handle)
{
int key = irq_lock();
_nano_timeout_abort((struct tcs *)handle);
irq_unlock(key);
}
#endif /* CONFIG_NANO_TIMEOUTS */