From 12403e3c6b3105e92876ed40270a0300e217e456 Mon Sep 17 00:00:00 2001 From: Travis Geiselbrecht Date: Thu, 6 May 2010 13:36:57 -0700 Subject: [PATCH] [kernel] add some documentation --- include/kernel/event.h | 1 + kernel/debug.c | 10 ++ kernel/event.c | 83 ++++++++++++++++ kernel/mutex.c | 39 ++++++++ kernel/thread.c | 214 ++++++++++++++++++++++++++++++++++++++++- kernel/timer.c | 48 +++++++++ 6 files changed, 392 insertions(+), 3 deletions(-) diff --git a/include/kernel/event.h b/include/kernel/event.h index 866673787..d0ce7f5dc 100644 --- a/include/kernel/event.h +++ b/include/kernel/event.h @@ -58,6 +58,7 @@ status_t event_wait(event_t *); status_t event_wait_timeout(event_t *, time_t); /* wait on the event with a timeout */ status_t event_signal(event_t *, bool reschedule); status_t event_unsignal(event_t *); +#define event_initialized(e) ((e)->magic == EVENT_MAGIC) #endif diff --git a/kernel/debug.c b/kernel/debug.c index 7b7a64878..ec4b987e7 100644 --- a/kernel/debug.c +++ b/kernel/debug.c @@ -21,6 +21,16 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/** + * @defgroup debug Debug + * @{ + */ + +/** + * @file + * @brief Debug console functions. + */ + #include #include #include diff --git a/kernel/event.c b/kernel/event.c index 97eb9558d..bdb6ec28e 100644 --- a/kernel/event.c +++ b/kernel/event.c @@ -20,6 +20,26 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/** + * @file + * @brief Event wait and signal functions for threads. + * @defgroup event Events + * + * An event is a subclass of a wait queue. + * + * Threads wait for events, with optional timeouts. + * + * Events are "signaled", releasing waiting threads to continue. + * Signals may be one-shot signals (EVENT_FLAG_AUTOUNSIGNAL), in which + * case one signal releases only one thread, at which point it is + * automatically cleared. Otherwise, signals release all waiting threads + * to continue immediately until the signal is manually cleared with + * event_unsignal(). + * + * @{ + */ + #include #include #include @@ -28,6 +48,13 @@ #define EVENT_CHECK 1 #endif +/** + * @brief Initialize an event object + * + * @param e Event object to initialize + * @param initial Initial value for "signaled" state + * @param flags 0 or EVENT_FLAG_AUTOUNSIGNAL + */ void event_init(event_t *e, bool initial, uint flags) { #if EVENT_CHECK @@ -40,6 +67,15 @@ void event_init(event_t *e, bool initial, uint flags) wait_queue_init(&e->wait); } +/** + * @brief Destroy an event object. + * + * Event's resources are freed and it may no longer be + * used until event_init() is called again. Any threads + * still waiting on the event will be resumed. + * + * @param e Event object to initialize + */ void event_destroy(event_t *e) { enter_critical_section(); @@ -56,6 +92,21 @@ void event_destroy(event_t *e) exit_critical_section(); } +/** + * @brief Wait for event to be signaled + * + * If the event has already been signaled, this function + * returns immediately. Otherwise, the current thread + * goes to sleep until the event object is signaled, + * the timeout is reached, or the event object is destroyed + * by another thread. + * + * @param e Event object + * @param timeout Timeout value, in ms + * + * @return 0 on success, ERR_TIMED_OUT on timeout, + * other values on other errors. + */ status_t event_wait_timeout(event_t *e, time_t timeout) { status_t ret = NO_ERROR; @@ -85,11 +136,31 @@ status_t event_wait_timeout(event_t *e, time_t timeout) return ret; } +/** + * @brief Same as event_wait_timeout(), but without a timeout. + */ status_t event_wait(event_t *e) { return event_wait_timeout(e, INFINITE_TIME); } +/** + * @brief Signal an event + * + * Signals an event. If EVENT_FLAG_AUTOUNSIGNAL is set in the event + * object's flags, only one waiting thread is allowed to proceed. Otherwise, + * all waiting threads are allowed to proceed until such time as + * event_unsignal() is called. + * + * @param e Event object + * @param reschedule If true, waiting thread(s) are executed immediately, + * and the current thread resumes only after the + * waiting threads have been satisfied. If false, + * waiting threads are placed at the end of the run + * queue. + * + * @return Returns NO_ERROR on success. + */ status_t event_signal(event_t *e, bool reschedule) { enter_critical_section(); @@ -121,6 +192,18 @@ status_t event_signal(event_t *e, bool reschedule) return NO_ERROR; } +/** + * @brief Clear the "signaled" property of an event + * + * Used mainly for event objects without the EVENT_FLAG_AUTOUNSIGNAL + * flag. Once this function is called, threads that call event_wait() + * functions will once again need to wait until the event object + * is signaled. + * + * @param e Event object + * + * @return Returns NO_ERROR on success. + */ status_t event_unsignal(event_t *e) { enter_critical_section(); diff --git a/kernel/mutex.c b/kernel/mutex.c index 1f7015d3f..07d2b194e 100644 --- a/kernel/mutex.c +++ b/kernel/mutex.c @@ -20,6 +20,15 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/** + * @file + * @brief Mutex functions + * + * @defgroup mutex Mutex + * @{ + */ + #include #include #include @@ -29,6 +38,9 @@ #define MUTEX_CHECK 1 #endif +/** + * @brief Initialize a mutex_t + */ void mutex_init(mutex_t *m) { #if MUTEX_CHECK @@ -41,6 +53,12 @@ void mutex_init(mutex_t *m) wait_queue_init(&m->wait); } +/** + * @brief Destroy a mutex_t + * + * This function frees any resources that were allocated + * in mutex_init(). The mutex_t object itself is not freed. + */ void mutex_destroy(mutex_t *m) { enter_critical_section(); @@ -59,6 +77,14 @@ void mutex_destroy(mutex_t *m) exit_critical_section(); } +/** + * @brief Acquire a mutex; wait if needed. + * + * This function waits for a mutex to become available. It + * may wait forever if the mutex never becomes free. + * + * @return NO_ERROR on success, other values on error + */ status_t mutex_acquire(mutex_t *m) { status_t ret = NO_ERROR; @@ -94,6 +120,16 @@ status_t mutex_acquire(mutex_t *m) return ret; } +/** + * @brief Mutex wait with timeout + * + * This function waits up to \a timeout ms for the mutex to become available. + * Timeout may be zero, in which case this function returns immediately if + * the mutex is not free. + * + * @return NO_ERROR on success, ERR_TIMED_OUT on timeout, + * other values on error + */ status_t mutex_acquire_timeout(mutex_t *m, time_t timeout) { status_t ret = NO_ERROR; @@ -140,6 +176,9 @@ status_t mutex_acquire_timeout(mutex_t *m, time_t timeout) return ret; } +/** + * @brief Release mutex + */ status_t mutex_release(mutex_t *m) { if (current_thread != m->holder) diff --git a/kernel/thread.c b/kernel/thread.c index 860e7129b..58dff8df5 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -20,6 +20,16 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/** + * @file + * @brief Kernel threading + * + * This file is the core kernel threading interface. + * + * @defgroup thread Threads + * @{ + */ #include #include #include @@ -100,6 +110,33 @@ static void init_thread_struct(thread_t *t, const char *name) strlcpy(t->name, name, sizeof(t->name)); } +/** + * @brief Create a new thread + * + * This function creates a new thread. The thread is initially suspended, so you + * need to call thread_resume() to execute it. + * + * @param name Name of thread + * @param entry Entry point of thread + * @param arg Arbitrary argument passed to entry() + * @param priority Execution priority for the thread. + * @param stack_size Stack size for the thread. + * + * Thread priority is an integer from 0 (lowest) to 31 (highest). Some standard + * prioritys are defined in : + * + * HIGHEST_PRIORITY + * DPC_PRIORITY + * HIGH_PRIORITY + * DEFAULT_PRIORITY + * LOW_PRIORITY + * IDLE_PRIORITY + * LOWEST_PRIORITY + * + * Stack size is typically set to DEFAULT_STACK_SIZE + * + * @return Pointer to thread object, or NULL on failure. + */ thread_t *thread_create(const char *name, thread_start_routine entry, void *arg, int priority, size_t stack_size) { thread_t *t; @@ -143,6 +180,16 @@ thread_t *thread_create(const char *name, thread_start_routine entry, void *arg, return t; } +/** + * @brief Make a suspended thread executable. + * + * This function is typically called to start a thread which has just been + * created with thread_create() + * + * @param t Thread to resume + * + * @return NO_ERROR on success, ERR_NOT_SUSPENDED if thread was not suspended. + */ status_t thread_resume(thread_t *t) { #if THREAD_CHECKS @@ -186,6 +233,13 @@ static void thread_cleanup_dpc(void *thread) free(t); } +/** + * @brief Terminate the current thread + * + * Current thread exits with the specified return code. + * + * This function does not return. + */ void thread_exit(int retcode) { #if THREAD_CHECKS @@ -216,10 +270,15 @@ static void idle_thread_routine(void) arch_idle(); } -/* +/** + * @brief Cause another thread to be executed. + * * Internal reschedule routine. The current thread needs to already be in whatever * state and queues it needs to be in. This routine simply picks the next thread and * switches to it. + * + * This is probably not the function you're looking for. See + * thread_yield() instead. */ void thread_resched(void) { @@ -317,6 +376,15 @@ void thread_resched(void) arch_context_switch(oldthread, newthread); } +/** + * @brief Yield the cpu to another thread + * + * This function places the current thread at the end of the run queue + * and yields the cpu to another waiting thread (if any.) + * + * This function will return at some later time. Possibly immediately if + * no other threads are waiting to execute. + */ void thread_yield(void) { #if THREAD_CHECKS @@ -339,6 +407,21 @@ void thread_yield(void) exit_critical_section(); } +/** + * @brief Briefly yield cpu to another thread + * + * This function is similar to thread_yield(), except that it will + * restart more quickly. + * + * This function places the current thread at the head of the run + * queue and then yields the cpu to another thread. + * + * Exception: If the time slice for this thread has expired, then + * the thread goes to the end of the run queue. + * + * This function will return at some later time. Possibly immediately if + * no other threads are waiting to execute. + */ void thread_preempt(void) { #if THREAD_CHECKS @@ -364,6 +447,16 @@ void thread_preempt(void) exit_critical_section(); } +/** + * @brief Suspend thread until woken. + * + * This function schedules another thread to execute. This function does not + * return until the thread is made runable again by some other module. + * + * You probably don't want to call this function directly; it's meant to be called + * from other modules, such as mutex, which will presumably set the thread's + * state to blocked and add it to some queue or another. + */ void thread_block(void) { #if THREAD_CHECKS @@ -407,7 +500,16 @@ static enum handler_return thread_sleep_handler(timer_t *timer, time_t now, void return INT_RESCHEDULE; } -/* Put thread to sleep; delay specified in ms */ +/** + * @brief Put thread to sleep; delay specified in ms + * + * This function puts the current thread to sleep until the specified + * delay in ms has expired. + * + * Note that this function could sleep for longer than the specified delay if + * other threads are running. When the timer expires, this thread will + * be placed at the head of the run queue. + */ void thread_sleep(time_t delay) { timer_t timer; @@ -426,6 +528,11 @@ void thread_sleep(time_t delay) exit_critical_section(); } +/** + * @brief Initialize threading system + * + * This function is called once, from kmain() + */ void thread_init_early(void) { int i; @@ -449,6 +556,11 @@ void thread_init_early(void) current_thread = t; } +/** + * @brief Complete thread initialization + * + * This function is called once at boot time + */ void thread_init(void) { #if PLATFORM_HAS_DYNAMIC_TIMER @@ -456,11 +568,19 @@ void thread_init(void) #endif } +/** + * @brief Change name of current thread + */ void thread_set_name(const char *name) { strlcpy(current_thread->name, name, sizeof(current_thread->name)); } +/** + * @brief Change priority of current thread + * + * See thread_create() for a discussion of priority values. + */ void thread_set_priority(int priority) { if (priority < LOWEST_PRIORITY) @@ -470,6 +590,13 @@ void thread_set_priority(int priority) current_thread->priority = priority; } +/** + * @brief Become an idle thread + * + * This function marks the current thread as the idle thread -- the one which + * executes when there is nothing else to do. This function does not return. + * This function is called once at boot time. + */ void thread_become_idle(void) { thread_set_name("idle"); @@ -478,6 +605,9 @@ void thread_become_idle(void) idle_thread_routine(); } +/** + * @brief Dump debugging info about the specified thread. + */ void dump_thread(thread_t *t) { dprintf(INFO, "dump_thread: t %p (%s)\n", t, t->name); @@ -493,6 +623,9 @@ void dump_thread(thread_t *t) dprintf(INFO, "\n"); } +/** + * @brief Dump debugging info about all threads + */ void dump_all_threads(void) { thread_t *t; @@ -504,7 +637,17 @@ void dump_all_threads(void) exit_critical_section(); } -/* wait queue */ +/** @} */ + + +/** + * @defgroup wait Wait Queue + * @{ + */ + +/** + * @brief Initialize a wait queue + */ void wait_queue_init(wait_queue_t *wait) { wait->magic = WAIT_QUEUE_MAGIC; @@ -526,6 +669,24 @@ static enum handler_return wait_queue_timeout_handler(timer_t *timer, time_t now return INT_NO_RESCHEDULE; } +/** + * @brief Block until a wait queue is notified. + * + * This function puts the current thread at the end of a wait + * queue and then blocks until some other thread wakes the queue + * up again. + * + * @param wait The wait queue to enter + * @param timeout The maximum time, in ms, to wait + * + * If the timeout is zero, this function returns immediately with + * ERR_TIMED_OUT. If the timeout is INFINITE_TIME, this function + * waits indefinitely. Otherwise, this function returns with + * ERR_TIMED_OUT at the end of the timeout period. + * + * @return ERR_TIMED_OUT on timeout, else returns the return + * value specified when the queue was woken by wait_queue_wake_one(). + */ status_t wait_queue_block(wait_queue_t *wait, time_t timeout) { timer_t timer; @@ -561,6 +722,20 @@ status_t wait_queue_block(wait_queue_t *wait, time_t timeout) return current_thread->wait_queue_block_ret; } +/** + * @brief Wake up one thread sleeping on a wait queue + * + * This function removes one thread (if any) from the head of the wait queue and + * makes it executable. The new thread will be placed at the head of the + * run queue. + * + * @param wait The wait queue to wake + * @param reschedule If true, the newly-woken thread will run immediately. + * @param wait_queue_error The return value which the new thread will receive + * from wait_queue_block(). + * + * @return The number of threads woken (zero or one) + */ int wait_queue_wake_one(wait_queue_t *wait, bool reschedule, status_t wait_queue_error) { thread_t *t; @@ -598,6 +773,21 @@ int wait_queue_wake_one(wait_queue_t *wait, bool reschedule, status_t wait_queue return ret; } + +/** + * @brief Wake all threads sleeping on a wait queue + * + * This function removes all threads (if any) from the wait queue and + * makes them executable. The new threads will be placed at the head of the + * run queue. + * + * @param wait The wait queue to wake + * @param reschedule If true, the newly-woken threads will run immediately. + * @param wait_queue_error The return value which the new thread will receive + * from wait_queue_block(). + * + * @return The number of threads woken (zero or one) + */ int wait_queue_wake_all(wait_queue_t *wait, bool reschedule, status_t wait_queue_error) { thread_t *t; @@ -641,6 +831,11 @@ int wait_queue_wake_all(wait_queue_t *wait, bool reschedule, status_t wait_queue return ret; } +/** + * @brief Free all resources allocated in wait_queue_init() + * + * If any threads were waiting on this queue, they are all woken. + */ void wait_queue_destroy(wait_queue_t *wait, bool reschedule) { #if THREAD_CHECKS @@ -651,6 +846,19 @@ void wait_queue_destroy(wait_queue_t *wait, bool reschedule) wait->magic = 0; } +/** + * @brief Wake a specific thread in a wait queue + * + * This function extracts a specific thread from a wait queue, wakes it, and + * puts it at the head of the run queue. + * + * @param t The thread to wake + * @param reschedule If true, the newly-woken threads will run immediately. + * @param wait_queue_error The return value which the new thread will receive + * from wait_queue_block(). + * + * @return ERR_NOT_BLOCKED if thread was not in any wait queue. + */ status_t thread_unblock_from_wait_queue(thread_t *t, bool reschedule, status_t wait_queue_error) { enter_critical_section(); diff --git a/kernel/timer.c b/kernel/timer.c index c041d49df..dd5cf9fdd 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -20,6 +20,20 @@ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/** + * @file + * @brief Kernel timer subsystem + * @defgroup timer Timers + * + * The timer subsystem allows functions to be scheduled for later + * execution. Each timer object is used to cause one function to + * be executed at a later time. + * + * Timer callback functions are called in interrupt context. + * + * @{ + */ #include #include #include @@ -31,6 +45,9 @@ static struct list_node timer_queue; static enum handler_return timer_tick(void *arg, time_t now); +/** + * @brief Initialize a timer object + */ void timer_initialize(timer_t *timer) { timer->magic = TIMER_MAGIC; @@ -93,6 +110,20 @@ static void timer_set(timer_t *timer, time_t delay, time_t period, timer_callbac exit_critical_section(); } +/** + * @brief Set up a timer that executes once + * + * This function specifies a callback function to be called after a specified + * delay. The function will be called one time. + * + * @param timer The timer to use + * @param delay The delay, in ms, before the timer is executed + * @param callback The function to call when the timer expires + * @param arg The argument to pass to the callback + * + * The timer function is declared as: + * enum handler_return callback(struct timer *, time_t now, void *arg) { ... } + */ void timer_set_oneshot(timer_t *timer, time_t delay, timer_callback callback, void *arg) { if (delay == 0) @@ -100,6 +131,20 @@ void timer_set_oneshot(timer_t *timer, time_t delay, timer_callback callback, vo timer_set(timer, delay, 0, callback, arg); } +/** + * @brief Set up a timer that executes repeatedly + * + * This function specifies a callback function to be called after a specified + * delay. The function will be called repeatedly. + * + * @param timer The timer to use + * @param delay The delay, in ms, before the timer is executed + * @param callback The function to call when the timer expires + * @param arg The argument to pass to the callback + * + * The timer function is declared as: + * enum handler_return callback(struct timer *, time_t now, void *arg) { ... } + */ void timer_set_periodic(timer_t *timer, time_t period, timer_callback callback, void *arg) { if (period == 0) @@ -107,6 +152,9 @@ void timer_set_periodic(timer_t *timer, time_t period, timer_callback callback, timer_set(timer, period, period, callback, arg); } +/** + * @brief Cancel a pending timer + */ void timer_cancel(timer_t *timer) { DEBUG_ASSERT(timer->magic == TIMER_MAGIC);