/* * Copyright (c) 1997-2015, Wind River Systems, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * * @brief Public APIs for the nanokernel. */ #ifndef __NANOKERNEL_H__ #define __NANOKERNEL_H__ /** * @defgroup nanokernel_services Nanokernel Services */ /* fundamental include files */ #include #include #include /* generic kernel public APIs */ #include #include #include #ifdef __cplusplus extern "C" { #endif /* * @cond internal * nanokernel private APIs that are exposed via the public API * * THESE ITEMS SHOULD NOT BE REFERENCED EXCEPT BY THE KERNEL ITSELF! */ struct _nano_queue { void *head; void *tail; }; #include struct _nano_timeout { sys_dlist_t node; struct _nano_queue *wait_q; int32_t delta_ticks_from_prev; }; /** * @endcond */ struct tcs; /* architecture-independent nanokernel public APIs */ typedef struct tcs *nano_thread_id_t; typedef void (*nano_fiber_entry_t)(int i1, int i2); typedef int nano_context_type_t; #define NANO_CTX_ISR (0) #define NANO_CTX_FIBER (1) #define NANO_CTX_TASK (2) /* timeout special values */ #define TICKS_UNLIMITED (-1) #define TICKS_NONE 0 /* * execution context APIs */ /** * @brief Return the currently executing thread * * This routine returns a pointer to the thread control block of the currently * executing thread. It is cast to a nano_thread_id_t for use publicly. * * @return nano_thread_id_t of the currently executing thread. */ extern nano_thread_id_t sys_thread_self_get(void); /** * * @brief Return the type of the current execution context * * This routine returns the type of execution context currently executing. * * @return nano_context_type_t of the currently executing thread. */ extern nano_context_type_t sys_execution_context_type_get(void); extern int _is_thread_essential(nano_thread_id_t pCtx); /** * * @brief Busy wait the currently executing thread * * This routine causes the current task or fiber to execute a "do nothing" * loop for a specified period of time. * * @warning This routine utilizes the system clock, so it must not be invoked * until the system clock is fully operational or while interrupts * are locked. * * @param usec_to_wait Number of microseconds to busy wait. * * @return N/A */ extern void sys_thread_busy_wait(uint32_t usec_to_wait); /** * @brief Nanokernel Fibers * @defgroup nanokernel_fiber Nanokernel Fibers * @ingroup nanokernel_services * @{ */ /* execution context-independent method (when context is not known) */ /** * @brief Initialize and start a fiber * * This routine initializes and starts a fiber; it can be called from * either a fiber or a task. When this routine is called from a * task, the newly created fiber will start executing immediately. * * @internal * Given that this routine is _not_ ISR-callable, the following code is used * to differentiate between a task and fiber: * * if ((_nanokernel.current->flags & TASK) == TASK) * * Given that the _fiber_start() primitive is not considered real-time * performance critical, a runtime check to differentiate between a calling * task or fiber is performed in order to conserve footprint. * @endinternal * * @param stack Pointer to the stack space * @param stack_size Stack size in bytes * @param entry Fiber entry * @param arg1 1st parameter to entry point * @param arg2 2nd parameter to entry point * @param prio Fiber priority * @param options unused * @return N/A */ void fiber_start(char *stack, unsigned stack_size, nano_fiber_entry_t entry, int arg1, int arg2, unsigned prio, unsigned options); /* methods for fibers */ /** * @brief Initialize and start a fiber * * This routine initializes and starts a fiber; it can be called from * a fiber. * * @param pStack Pointer to the stack space * @param stackSize Stack size in bytes * @param entry Fiber entry * @param arg1 1st parameter to entry point * @param arg2 2nd parameter to entry point * @param prio Fiber priority * @param options unused * @return N/A */ extern void fiber_fiber_start(char *pStack, unsigned int stackSize, nano_fiber_entry_t entry, int arg1, int arg2, unsigned prio, unsigned options); /** * @brief Yield the current fiber * * Invocation of this routine results in the current fiber yielding to * another fiber of the same or higher priority. If there doesn't exist * any other fibers of the same or higher priority that are runnable, this * routine will return immediately. * * This routine can only be called from a fiber. * * @return N/A */ extern void fiber_yield(void); /** * @brief Abort the currently executing fiber * * This routine is used to abort the currently executing fiber. This can occur * because: * - the fiber has explicitly aborted itself (by calling this routine), * - the fiber has implicitly aborted itself (by returning from its entry point), * - the fiber has encountered a fatal exception. * * This routine can only be called from a fiber. * * @return This function never returns */ extern void fiber_abort(void); #ifdef CONFIG_NANO_TIMEOUTS /** * @brief Put the current fiber to sleep * * Put the currently running fiber to sleep for an amount of system ticks * passed in the timeout_in_ticks parameter. * * @param timeout number of system ticks to sleep * * @return None */ extern void fiber_sleep(int32_t timeout); /** * @brief start a fiber, but delay its execution * * @param stack pointer to the stack space * @param stack_size_in_bytes stack size in bytes * @param entry_point fiber entry point * @param param1 1st parameter to entry point * @param param2 2nd parameter to entry point * @param priority fiber priority * @param options unused * @param timeout_in_ticks timeout in ticks * * @return a handle to allow canceling the delayed start */ extern void *fiber_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); extern 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); extern void fiber_delayed_start_cancel(void *handle); /** * @brief Cancel a delayed fiber start * * @param handle A handle returned when asking to start the fiber * * @return None */ extern void fiber_fiber_delayed_start_cancel(void *handle); #endif /** * @} * @brief Nanokernel Task * @defgroup nanokernel_task Nanokernel Task * @ingroup nanokernel_services * @{ */ /* methods for tasks */ /** * @brief Initialize and start a fiber from a task * * @sa fiber_fiber_start */ extern void task_fiber_start(char *pStack, unsigned int stackSize, nano_fiber_entry_t entry, int arg1, int arg2, unsigned prio, unsigned options); #ifdef CONFIG_NANO_TIMEOUTS /** * @brief Start a fiber from a task, but delay its execution * * @sa fiber_fiber_delayed_start */ extern void *task_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); /** * @brief Cancel a delayed fiber start in task * * @sa fiber_fiber_delayed_start */ extern void task_fiber_delayed_start_cancel(void *handle); #endif /** * @} * @brief Nanokernel FIFOs * @defgroup nanokernel_fifo Nanokernel FIFO * @ingroup nanokernel_services * @{ */ struct nano_fifo { union { struct _nano_queue wait_q; struct _nano_queue data_q; }; int stat; #ifdef CONFIG_DEBUG_TRACING_KERNEL_OBJECTS struct nano_fifo *next; #endif }; /** * * @brief Initialize a nanokernel multiple-waiter fifo (fifo) object * * This function initializes a nanokernel multiple-waiter fifo (fifo) object * structure. * * It may be called from either a fiber or task. * * The wait queue and data queue occupy the same space since there cannot * be both queued data and pending fibers in the FIFO. Care must be taken * that, when one of the queues becomes empty, it is reset to a state * that reflects an empty queue to both the data and wait queues. * * If the 'stat' field is a positive value, it indicates how many data * elements reside in the FIFO. If the 'stat' field is a negative value, * its absolute value indicates how many fibers are pending on the LIFO * object. Thus a value of '0' indicates that there are no data elements * in the LIFO _and_ there are no pending fibers. * * @param fifo FIFO to initialize. * * @return N/A */ extern void nano_fifo_init(struct nano_fifo *fifo); /* execution context-independent methods (when context is not known) */ /** * * @brief Add an element to the end of a fifo * * This is a convenience wrapper for the execution context-specific APIs. This * is helpful whenever the exact execution context is not known, but should be * avoided when the context is known up-front (to avoid unnecessary overhead). * * @param fifo FIFO on which to interact. * @param data Data to send. * * @return N/A */ extern void nano_fifo_put(struct nano_fifo *fifo, void *data); /** * * @brief Get an element from the head a fifo * * Remove the head element from the specified nanokernel multiple-waiter fifo * linked list fifo; it may be called from a fiber, task, or ISR context. * * If no elements are available, NULL is returned. The first word in the * element contains invalid data because that memory location was used to store * a pointer to the next element in the linked list. * * @param fifo FIFO on which to interact. * * @return Pointer to head element in the list if available, otherwise NULL */ extern void *nano_fifo_get(struct nano_fifo *fifo); /** * * @brief Get the head element of a fifo, poll/pend if empty * * This is a convenience wrapper for the execution context-specific APIs. This * is helpful whenever the exact execution context is not known, but should be * avoided when the context is known up-front (to avoid unnecessary overhead). * * @warning It's only valid to call this API from a fiber or a task. * * @param fifo FIFO on which to interact. * * @return Pointer to head element in the list */ extern void *nano_fifo_get_wait(struct nano_fifo *fifo); /* * methods for ISRs */ /** * * @brief Add an element to the end of a FIFO from an ISR context. * * This is an alias for the execution context-specific API. This is * helpful whenever the exact execution context is known. Its use * avoids unnecessary overhead. * * @param fifo FIFO on which to interact. * @param data Data to send. * * @return N/A */ extern void nano_isr_fifo_put(struct nano_fifo *fifo, void *data); /** * @brief Get an element from the head of a FIFO from an ISR context. * * Remove the head element from the specified nanokernel multiple-waiter fifo * linked list fifo. It may be called from an ISR context. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked list. * * @param fifo FIFO on which to interact. * * @return Pointer to head element in the list if available, otherwise NULL */ extern void *nano_isr_fifo_get(struct nano_fifo *fifo); /* methods for fibers */ /** * * @brief Add an element to the end of a FIFO from a fiber. * * This is an alias for the execution context-specific API. This is * helpful whenever the exact execution context is known. Its use * avoids unnecessary overhead. * * @param fifo FIFO on which to interact. * @param data Data to send. * * @return N/A */ extern void nano_fiber_fifo_put(struct nano_fifo *fifo, void *data); /** * @brief Get an element from the head of a FIFO from a fiber. * * Remove the head element from the specified nanokernel multiple-waiter fifo * linked list fifo. It may be called from a fiber. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked list. * * @param fifo FIFO on which to interact. * * @return Pointer to head element in the list if available, otherwise NULL */ extern void *nano_fiber_fifo_get(struct nano_fifo *fifo); /** * * @brief Get the head element of a fifo, wait if empty * * Remove the head element from the specified system-level multiple-waiter * fifo; it can only be called from a fiber. * * If no elements are available, the calling fiber will pend until an element * is put onto the fifo. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked list. * * @param fifo FIFO on which to interact. * * @return Pointer to head element in the list * * @note There exists a separate nano_task_fifo_get_wait() implementation * since a task cannot pend on a nanokernel object. Instead tasks will * poll the fifo object. */ extern void *nano_fiber_fifo_get_wait(struct nano_fifo *fifo); #ifdef CONFIG_NANO_TIMEOUTS /** * @brief get the head element of a fifo, pend with a timeout if empty * * Remove the head element from the specified nanokernel fifo; it can only be * called from a fiber. * * If no elements are available, the calling fiber will pend until an element * is put onto the fifo, or the timeout expires, whichever comes first. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked * list. * * @sa nano_task_stack_pop_wait() * * @param fifo the FIFO on which to interact. * @param timeout_in_ticks time to wait in ticks * * @return Pointer to head element in the list, NULL if timed out */ extern void *nano_fiber_fifo_get_wait_timeout(struct nano_fifo *fifo, int32_t timeout_in_ticks); #endif /* methods for tasks */ /** * * @brief Add an element to the end of a fifo * * This routine adds an element to the end of a fifo object; it can be called * from only a task. A fiber pending on the fifo object will be made * ready, and will preempt the running task immediately. * * If a fiber is waiting on the fifo, the address of the element is returned to * the waiting fiber. Otherwise, the element is linked to the end of the list. * * @param fifo FIFO on which to interact. * @param data Data to send. * * @return N/A */ extern void nano_task_fifo_put(struct nano_fifo *fifo, void *data); extern void *nano_task_fifo_get(struct nano_fifo *fifo); /** * * @brief Get the head element of a fifo, poll if empty * * Remove the head element from the specified system-level multiple-waiter * fifo; it can only be called from a task. * * If no elements are available, the calling task will poll until an * until an element is put onto the fifo. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked list. * * @param fifo FIFO on which to interact. * * @sa nano_task_stack_pop_wait() * * @return Pointer to head element in the list */ extern void *nano_task_fifo_get_wait(struct nano_fifo *fifo); #ifdef CONFIG_NANO_TIMEOUTS /** * @brief get the head element of a fifo, poll with a timeout if empty * * Remove the head element from the specified nanokernel fifo; it can only be * called from a task. * * If no elements are available, the calling task will poll until an element * is put onto the fifo, or the timeout expires, whichever comes first. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked * list. * * @sa nano_task_stack_pop_wait() * * @param fifo the FIFO on which to operate * @param timeout_in_ticks time to wait in ticks * * @return Pointer to head element in the list, NULL if timed out */ extern void *nano_task_fifo_get_wait_timeout(struct nano_fifo *fifo, int32_t timeout_in_ticks); #endif /* LIFO APIs */ /** * @} * @brief Nanokernel LIFOs * @defgroup nanokernel_lifo Nanokernel LIFOs * @ingroup nanokernel_services * @{ */ struct nano_lifo { struct _nano_queue wait_q; void *list; #ifdef CONFIG_DEBUG_TRACING_KERNEL_OBJECTS struct nano_lifo *next; #endif }; /** * @brief Initialize a nanokernel linked list lifo object * * This function initializes a nanokernel system-level linked list lifo * object structure. * * It may be called from either a fiber or task. * * @param lifo LIFO to initialize. * * @return N/A */ extern void nano_lifo_init(struct nano_lifo *lifo); /* methods for ISRs */ /** * @brief Prepend an element to a LIFO without a context switch. * * This routine adds an element to the head of a LIFO object; it may be * called from an ISR context. A fiber pending on the LIFO * object will be made ready, but will NOT be scheduled to execute. * * @param lifo LIFO on which to put. * @param data Data to insert. * * @return N/A */ extern void nano_isr_lifo_put(struct nano_lifo *lifo, void *data); /** * @brief Remove the first element from a linked list LIFO * * Remove the first element from the specified nanokernel linked list LIFO; * it may be called from an ISR context. * * If no elements are available, NULL is returned. The first word in the * element contains invalid data because that memory location was used to store * a pointer to the next element in the linked list. * * @param lifo LIFO from which to receive. * * @return Pointer to first element in the list if available, otherwise NULL */ extern void *nano_isr_lifo_get(struct nano_lifo *lifo); /* methods for fibers */ /** * @brief Prepend an element to a LIFO without a context switch. * * This routine adds an element to the head of a LIFO object; it may be * called from a fiber. A fiber pending on the LIFO * object will be made ready, but will NOT be scheduled to execute. * * @param lifo LIFO from which to put. * @param data Data to insert. * * @return N/A */ extern void nano_fiber_lifo_put(struct nano_lifo *lifo, void *data); /** * @brief Remove the first element from a linked list LIFO * * Remove the first element from the specified nanokernel linked list LIFO; * it may be called from a fiber. * * If no elements are available, NULL is returned. The first word in the * element contains invalid data because that memory location was used to store * a pointer to the next element in the linked list. * * @param lifo LIFO from which to receive * * @return Pointer to first element in the list if available, otherwise NULL */ extern void *nano_fiber_lifo_get(struct nano_lifo *lifo); /** * @brief Get the first element from a LIFO, wait if empty. * * Remove the first element from the specified system-level linked list LIFO; * it can only be called from a fiber. * * If no elements are available, the calling fiber will pend until an element * is put onto the list. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked list. * * @param lifo LIFO from which to receive. * * @return Pointer to first element in the list */ extern void *nano_fiber_lifo_get_wait(struct nano_lifo *lifo); #ifdef CONFIG_NANO_TIMEOUTS /** * @brief get the first element from a LIFO, wait with a timeout if empty * * Remove the first element from the specified system-level linked list lifo; * it can only be called from a fiber. * * If no elements are available, the calling fiber will pend until an element * is put onto the list, or the timeout expires, whichever comes first. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked list. * * @param lifo LIFO on which to operate. * @param timeout_in_ticks Time to wait in ticks. * * @return Pointer to first element in the list, NULL if timed out. */ extern void *nano_fiber_lifo_get_wait_timeout(struct nano_lifo *lifo, int32_t timeout_in_ticks); #endif /* methods for tasks */ /** * @brief Add an element to the head of a linked list LIFO * * This routine adds an element to the head of a LIFO object; it can be * called only from a task. A fiber pending on the LIFO * object will be made ready and will preempt the running task immediately. * * This API can only be called by a task. * * @param lifo LIFO from which to put. * @param data Data to insert. * * @return N/A */ extern void nano_task_lifo_put(struct nano_lifo *lifo, void *data); /** * @brief Remove the first element from a linked list LIFO * * Remove the first element from the specified nanokernel linked list LIFO; * it may be called from a task. * * If no elements are available, NULL is returned. The first word in the * element contains invalid data because that memory location was used to store * a pointer to the next element in the linked list. * * @param lifo LIFO from which to receive. * * @return Pointer to first element in the list if available, otherwise NULL. */ extern void *nano_task_lifo_get(struct nano_lifo *lifo); /** * @brief Get the first element from a LIFO, poll if empty. * * Remove the first element from the specified nanokernel linked list LIFO; it * can only be called from a task. * * If no elements are available, the calling task will poll until an element is * put onto the list. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked list. * * @param lifo LIFO from which to receive. * * @sa nano_task_stack_pop_wait() * * @return Pointer to first element in the list */ extern void *nano_task_lifo_get_wait(struct nano_lifo *lifo); #ifdef CONFIG_NANO_TIMEOUTS /** * @brief get the first element from a lifo, poll if empty. * * Remove the first element from the specified nanokernel linked list lifo; it * can only be called from a task. * * If no elements are available, the calling task will poll until an element is * put onto the list, or the timeout expires, whichever comes first. * * The first word in the element contains invalid data because that memory * location was used to store a pointer to the next element in the linked list. * * @param lifo LIFO on which to operate * @param timeout_in_ticks time to wait in ticks * * @return Pointer to first element in the list, NULL if timed out. */ extern void *nano_task_lifo_get_wait_timeout(struct nano_lifo *lifo, int32_t timeout_in_ticks); #endif /** * @} * @brief Nanokernel Semaphores * @defgroup nanokernel_semaphore Nanokernel Semaphores * @ingroup nanokernel_services * @{ */ struct nano_sem { struct _nano_queue wait_q; int nsig; #ifdef CONFIG_DEBUG_TRACING_KERNEL_OBJECTS struct nano_sem *next; #endif }; /** * * @brief Initialize a nanokernel semaphore object * * This function initializes a nanokernel semaphore object structure. After * initialization, the semaphore count will be 0. * * It may be called from either a fiber or task. * * @param sem Pointer to a nano_sem structure. * * @return N/A */ extern void nano_sem_init(struct nano_sem *sem); /* execution context-independent methods (when context is not known) */ /** * * @brief Give a nanokernel semaphore * * This is a convenience wrapper for the execution context-specific APIs. This * is helpful whenever the exact execution context is not known, but should be * avoided when the context is known up-front (to avoid unnecessary overhead). * * @param sem Pointer to a nano_sem structure. * * @return N/A */ extern void nano_sem_give(struct nano_sem *sem); /** * * @brief Take a nanokernel semaphore, poll/pend if not available * * This is a convenience wrapper for the execution context-specific APIs. This * is helpful whenever the exact execution context is not known, but should be * avoided when the context is known up-front (to avoid unnecessary overhead). * * It's only valid to call this API from a fiber or a task. * * @param sem Pointer to a nano_sem structure. * * @return N/A */ extern void nano_sem_take_wait(struct nano_sem *sem); /* methods for ISRs */ /** * * @brief Give a nanokernel semaphore (no context switch) * * This routine performs a "give" operation on a nanokernel semaphore object; * it may be call from an ISR context. A fiber pending on * the semaphore object will be made ready, but will NOT be scheduled to * execute. * * @param sem Pointer to a nano_sem structure. * * @return N/A */ extern void nano_isr_sem_give(struct nano_sem *sem); /** * * @brief Take a nanokernel semaphore, fail if unavailable * * Attempt to take a nanokernel semaphore; it may be called from a * ISR context. * * If the semaphore is not available, this function returns immediately, i.e. * a wait (pend) operation will NOT be performed. * * @param sem Pointer to a nano_sem structure. * * @return 1 if semaphore is available, 0 otherwise */ extern int nano_isr_sem_take(struct nano_sem *sem); /* methods for fibers */ /** * * @brief Give a nanokernel semaphore (no context switch) * * This routine performs a "give" operation on a nanokernel semaphore object; * it may be call from a fiber. A fiber pending on * the semaphore object will be made ready, but will NOT be scheduled to * execute. * * @param sem Pointer to a nano_sem structure. * * @return N/A */ extern void nano_fiber_sem_give(struct nano_sem *sem); /** * * @brief Take a nanokernel semaphore, fail if unavailable * * Attempt to take a nanokernel semaphore; it may be called from a fiber. * * If the semaphore is not available, this function returns immediately, i.e. * a wait (pend) operation will NOT be performed. * * @param sem Pointer to a nano_sem structure. * * @return 1 if semaphore is available, 0 otherwise */ extern int nano_fiber_sem_take(struct nano_sem *sem); /** * * @brief Test a nanokernel semaphore, wait if unavailable * * Take a nanokernel semaphore; it can only be called from a fiber. * * If the nanokernel semaphore is not available, i.e. the event counter * is 0, the calling fiber will wait (pend) until the semaphore is * given (via nano_fiber_sem_give/nano_task_sem_give/nano_isr_sem_give). * * @param sem Pointer to a nano_sem structure. * * @return N/A */ extern void nano_fiber_sem_take_wait(struct nano_sem *sem); #ifdef CONFIG_NANO_TIMEOUTS /** * @brief test a nanokernel semaphore, wait with a timeout if unavailable * * Take a nanokernel semaphore; it can only be called from a fiber. * * If the nanokernel semaphore is not available, i.e. the event counter * is 0, the calling fiber will wait (pend) until the semaphore is * given (via nano_fiber_sem_give/nano_task_sem_give/nano_isr_sem_give). A * timeout can be specified. * * @param sem Pointer to the semaphore to take * @param timeout time to wait in ticks * * @return 1 if semaphore is available, 0 if timed out */ extern int nano_fiber_sem_take_wait_timeout(struct nano_sem *sem, int32_t timeout); #endif /* methods for tasks */ /** * * @brief Give a nanokernel semaphore * * This routine performs a "give" operation on a nanokernel semaphore object; * it can only be called from a task. A fiber pending on the * semaphore object will be made ready, and will preempt the running task * immediately. * * @param sem Pointer to a nano_sem structure. * * @return N/A */ extern void nano_task_sem_give(struct nano_sem *sem); /** * * @brief Take a nanokernel semaphore, fail if unavailable * * Attempt to take a nanokernel semaphore; it can only be called from a task. * * If the semaphore is not available, this function returns immediately, i.e. * a wait (pend) operation will NOT be performed. * * @param sem Pointer to a nano_sem structure. * * @return 1 if semaphore is available, 0 otherwise */ extern int nano_task_sem_take(struct nano_sem *sem); /** * * @brief Take a nanokernel semaphore, poll if unavailable * * Take a nanokernel semaphore; it can only be called from a task. * * If the nanokernel semaphore is not available, i.e. the event counter * is 0, the calling task will poll until the semaphore is given * (via nano_fiber_sem_give/nano_task_sem_give/nano_isr_sem_give). * * @param sem Pointer to a nano_sem structure. * * @return N/A */ extern void nano_task_sem_take_wait(struct nano_sem *sem); #ifdef CONFIG_NANO_TIMEOUTS /** * @brief test a nanokernel semaphore, poll with a timeout if unavailable * * Take a nanokernel semaphore; it can only be called from a task. * * If the nanokernel semaphore is not available, i.e. the event counter is 0, * the calling task will poll until the semaphore is given (via * nano_fiber_sem_give/nano_task_sem_give/nano_isr_sem_give). A timeout can be * specified. * * @param sem the semaphore to take * @param timeout time to wait in ticks * * @return 1 if semaphore is available, 0 if timed out */ extern int nano_task_sem_take_wait_timeout(struct nano_sem *sem, int32_t timeout); #endif /** * @} * @brief Nanokernel Stacks * @defgroup nanokernel_stack Nanokernel Stacks * @ingroup nanokernel_services * @{ */ struct nano_stack { nano_thread_id_t fiber; uint32_t *base; uint32_t *next; }; /** * * @brief Initialize a nanokernel stack object * * This function initializes a nanokernel stack object structure. * * It may be called from either a fiber or a task. * * @return N/A * */ extern void nano_stack_init(struct nano_stack *stack, uint32_t *data); /* methods for ISRs */ /** * * @brief Push data onto a stack (no context switch) * * This routine pushes a data item onto a stack object; it may be called from * an ISR context. A fiber pending on the stack object will be * made ready, but will NOT be scheduled to execute. * * @param stack Stack on which to interact * @param data Data to push on stack * * @return N/A * */ extern void nano_isr_stack_push(struct nano_stack *stack, uint32_t data); /** * * @brief Pop data from a nanokernel stack * * Pop the first data word from a nanokernel stack object; it may be called * from an ISR context. * * If the stack is not empty, a data word is popped and copied to the provided * address @a data and a non-zero value is returned. If the stack is empty, * zero is returned. * * @param stack Stack on which to interact * @param data Container for data to pop * @return 1 if stack is not empty, 0 otherwise * */ extern int nano_isr_stack_pop(struct nano_stack *stack, uint32_t *data); /* methods for fibers */ /** * * @brief Push data onto a stack (no context switch) * * This routine pushes a data item onto a stack object; it may be called from * a fiber context. A fiber pending on the stack object will be * made ready, but will NOT be scheduled to execute. * * @param stack Stack on which to interact * @param data Data to push on stack * * @return N/A * */ extern void nano_fiber_stack_push(struct nano_stack *stack, uint32_t data); /** * * @brief Pop data from a nanokernel stack * * Pop the first data word from a nanokernel stack object; it may be called * from a fiber context. * * If the stack is not empty, a data word is popped and copied to the provided * address @a data and a non-zero value is returned. If the stack is empty, * zero is returned. * * @param stack Stack on which to interact * @param data Container for data to pop * * @return 1 if stack is not empty, 0 otherwise * */ extern int nano_fiber_stack_pop(struct nano_stack *stack, uint32_t *data); /** * * @brief Pop data from a nanokernel stack, wait if empty * * Pop the first data word from a nanokernel stack object; it can only be * called from a fiber. * * If data is not available the calling fiber will pend until data is pushed * onto the stack. * * @param stack Stack on which to interact * * @return the data popped from the stack * */ extern uint32_t nano_fiber_stack_pop_wait(struct nano_stack *stack); /* methods for tasks */ /** * * @brief Push data onto a nanokernel stack * * This routine pushes a data item onto a stack object; it may be called only * from a task. A fiber pending on the stack object will be * made ready, and will preempt the running task immediately. * * @param stack Stack on which to interact * @param data Data to push on stack * * @return N/A */ extern void nano_task_stack_push(struct nano_stack *stack, uint32_t data); /** * * @brief Pop data from a nanokernel stack * * Pop the first data word from a nanokernel stack object; it may be called * from a task context. * * If the stack is not empty, a data word is popped and copied to the provided * address @a data and a non-zero value is returned. If the stack is empty, * zero is returned. * * @param stack Stack on which to interact * @param data Container for data to pop * * @return 1 if stack is not empty, 0 otherwise */ extern int nano_task_stack_pop(struct nano_stack *stack, uint32_t *data); /** * * @brief Pop data from a nanokernel stack, poll if empty * * Pop the first data word from a nanokernel stack; it can only be called * from a task. * * If data is not available the calling task will poll until data is pushed * onto the stack. * * @param stack Stack on which to interact * * @return the data popped from the stack */ extern uint32_t nano_task_stack_pop_wait(struct nano_stack *stack); /* thread custom data APIs */ #ifdef CONFIG_THREAD_CUSTOM_DATA extern void sys_thread_custom_data_set(void *value); extern void *sys_thread_custom_data_get(void); #endif /* CONFIG_THREAD_CUSTOM_DATA */ /** * @} * @brief Nanokernel Timers * @defgroup nanokernel_timer Nanokernel Timers * @ingroup nanokernel_services * @{ */ struct nano_timer { struct nano_timer *link; uint32_t ticks; struct nano_lifo lifo; void *userData; #ifdef CONFIG_DEBUG_TRACING_KERNEL_OBJECTS struct nano_timer *next; #endif }; /** * @brief Initialize a nanokernel timer object * * This function initializes a nanokernel timer object structure. * * It may be called from either a fiber or task. * * The @a data passed to this function must have enough space for a pointer * in its first field, that may be overwritten when the timer expires, plus * whatever data the user wishes to store and recover when the timer expires. * * @param timer Timer * @param data User Data * @return N/A */ extern void nano_timer_init(struct nano_timer *timer, void *data); /* methods for fibers */ /** * * @brief Start a nanokernel timer from a fiber * * This function starts a previously initialized nanokernel timer object. * The timer will expire in @a ticks system clock ticks. * * @param timer Timer * @param ticks Number of ticks * * @return N/A */ extern void nano_fiber_timer_start(struct nano_timer *timer, int ticks); /** * @brief Make the current fiber check for a timer expiry * * This function will check if a timer has expired. The timer must * have been initialized by nano_timer_init() and started via either * nano_fiber_timer_start() or nano_task_timer_start() first. * * @param timer Timer to check * * @return pointer to timer initialization data, or NULL if timer not expired */ extern void *nano_fiber_timer_test(struct nano_timer *timer); /** * * @brief Make the current fiber wait for a timer to expire * * This function will pend on a timer if it hasn't expired yet. The timer must * have been initialized by nano_timer_init() and started via either * nano_fiber_timer_start() or nano_task_timer_start() first and must not * have been stopped via nano_task_timer_stop() or nano_fiber_timer_stop(). * * @param timer Timer to pend on * * @return pointer to timer initialization data * */ extern void *nano_fiber_timer_wait(struct nano_timer *timer); /** * @brief Stop a nanokernel timer from a fiber * * This function stops a previously started nanokernel timer object. * * @param timer Timer to stop * * @return N/A */ extern void nano_fiber_timer_stop(struct nano_timer *timer); /* methods for tasks */ /** * @brief Start a nanokernel timer from a task * * This function starts a previously initialized nanokernel timer object. * The timer will expire in @a ticks system clock ticks. * * @param timer Timer * @param ticks Number of ticks * * @return N/A */ extern void nano_task_timer_start(struct nano_timer *timer, int ticks); /** * @brief Make the current task check for a timer expiry * * This function will check if a timer has expired. The timer must * have been initialized by nano_timer_init() and started via either * nano_fiber_timer_start() or nano_task_timer_start() first. * * @param timer Timer to check * * @return pointer to timer initialization data, or NULL if timer not expired */ extern void *nano_task_timer_test(struct nano_timer *timer); /** * * @brief Make the current task wait for a timer to expire * * This function will pend on a timer if it hasn't expired yet. The timer must * have been initialized by nano_timer_init() and started via either * nano_fiber_timer_start() or nano_task_timer_start() first and must not * have been stopped via nano_task_timer_stop() or nano_fiber_timer_stop(). * * @param timer Timer to pend on * * @return pointer to timer initialization data * */ extern void *nano_task_timer_wait(struct nano_timer *timer); /** * @brief Stop a nanokernel timer from a task * * This function stops a previously started nanokernel timer object. * * @param timer Timer to stop * * @return N/A */ extern void nano_task_timer_stop(struct nano_timer *timer); /* methods for tasks and fibers for handling time and ticks */ /** * * @brief Return the current system tick count * * @return the current system tick count * */ extern int64_t nano_tick_get(void); /** * * @brief Return the lower part of the current system tick count * * @return the current system tick count * */ extern uint32_t nano_tick_get_32(void); /** * @brief Return a high resolution time stamp * * @return the current timer hardware count */ extern uint32_t nano_cycle_get_32(void); /** * * @brief Return number of ticks since a reference time * * @param reftime Reference time * * @return tick count since reference time; undefined for first invocation */ extern int64_t nano_tick_delta(int64_t *reftime); /** * * @brief Return 32-bit number of ticks since a reference time * * @param reftime Reference time * * @return 32-bit tick count since reference time; undefined for first invocation */ extern uint32_t nano_tick_delta_32(int64_t *reftime); /* * Lists for object tracing */ #ifdef CONFIG_DEBUG_TRACING_KERNEL_OBJECTS struct nano_sem *_track_list_nano_sem; struct nano_fifo *_track_list_nano_fifo; struct nano_lifo *_track_list_nano_lifo; struct nano_timer *_track_list_nano_timer; #define DEBUG_TRACING_OBJ_INIT(type, obj, list) { \ obj->next = NULL; \ if (list == NULL) { \ list = obj; \ } \ else { \ if (list != obj) { \ type link = list; \ while ((link->next != NULL) && (link->next != obj)) { \ link = link->next; \ } \ if (link->next == NULL) { \ link->next = obj; \ } \ } \ } \ } #else #define DEBUG_TRACING_OBJ_INIT(type, obj, list) do { } while ((0)) #endif /** * @} * @} nanokernel services */ #ifdef __cplusplus } #endif /* architecture-specific nanokernel public APIs */ #include #endif /* __NANOKERNEL_H__ */