From 30f0bb1d66f016d6d8366aa483ca12a4724bd599 Mon Sep 17 00:00:00 2001 From: gdisirio Date: Tue, 18 Sep 2007 12:40:26 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- src/chthreads.c | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 src/chthreads.c (limited to 'src/chthreads.c') diff --git a/src/chthreads.c b/src/chthreads.c new file mode 100644 index 000000000..8f7112647 --- /dev/null +++ b/src/chthreads.c @@ -0,0 +1,265 @@ +/* + ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio. + + This file is part of ChibiOS/RT. + + ChibiOS/RT is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/RT is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/** + * @addtogroup Threads + * @{ + */ + +#include + +#ifndef CH_OPTIMIZE_SPEED +/* + * Removes a Thread from a list and returns it. + * @param tp the pointer to the thread to be removed from the list + * @return the removed thread pointer + */ +Thread *dequeue(Thread *tp) { + + tp->p_prev->p_next = tp->p_next; + tp->p_next->p_prev = tp->p_prev; + return tp; +} + +/* + * Inserts a thread into a bi-directional list in FIFO order. + * @param tp the pointer to the thread to be inserted in the list + * @param tqp the pointer to the threads list header + */ +void enqueue(Thread *tp, ThreadsQueue *tqp) { + + tp->p_next = (Thread *)tqp; + tp->p_prev = tqp->p_prev; + tqp->p_prev->p_next = tp; + tqp->p_prev = tp; +} +#endif /* CH_OPTIMIZE_SPEED */ + +/* + * Initializes a thread structure. + */ +void _InitThread(t_prio prio, t_tmode mode, Thread *tp) { + + tp->p_flags = mode; + tp->p_prio = prio; + tp->p_rdymsg = RDY_OK; +#ifdef CH_USE_RT_SEMAPHORES + tp->p_rtcnt = 0; + tp->p_bakprio = prio; +#endif +#ifdef CH_USE_WAITEXIT + tp->p_waiting.p_next = (Thread *)&tp->p_waiting; + tp->p_waiting.p_prev = (Thread *)&tp->p_waiting; +#endif +#ifdef CH_USE_MESSAGES + tp->p_msgqueue.p_next = (Thread *)&tp->p_msgqueue; + tp->p_msgqueue.p_prev = (Thread *)&tp->p_msgqueue; +#endif +#ifdef CH_USE_EVENTS + tp->p_epending = 0; +#endif +#ifdef CH_USE_EXIT_EVENT + chEvtInit(&tp->p_exitesource); +#endif +} + +/** + * Creates a new thread. + * @param prio the priority level for the new thread. Usually the threads are + * created with priority \p NORMALPRIO (128), priorities + * can range from \p LOWPRIO (1) to \p HIGHPRIO + * (255). + * @param mode the creation option flags for the thread. The following options + * can be OR'ed in this parameter:
+ *
    + *
  • \p P_SUSPENDED, the thread is created in the + * \p PRSUSPENDED state and a subsequent call to + * \p chThdResume() will make it ready for + * execution.
  • + *
  • \p P_TERMINATED, this flag is usually set + * by the \p chThdTerminate() function and it is not + * normally used as parameter for this function. The + * result would be to create a thread with a termination + * request already pending.
  • + *
+ * @param workspace pointer to a working area dedicated to the thread stack + * @param wsize size of the working area. + * @param pf the thread function. Returning from this function automatically + * terminates the thread. + * @param arg an argument passed to the thread function. It can be \p NULL. + * @return the pointer to the \p Thread structure allocated for the + * thread into the working space area. + * @note A thread can terminate by calling \p chThdExit() or by simply + * returning from its main function. + */ +Thread *chThdCreate(t_prio prio, t_tmode mode, void *workspace, + t_size wsize, t_tfunc pf, void *arg) { + Thread *tp = workspace; + + _InitThread(prio, mode, tp); + SETUP_CONTEXT(workspace, wsize, pf, arg); +#ifdef CH_USE_RESUME + if (tp->p_flags & P_SUSPENDED) + tp->p_state = PRSUSPENDED; + else { +#endif + chSysLock(); + + chSchWakeupI(tp, RDY_OK); + + chSysUnlock(); +#ifdef CH_USE_RESUME + } +#endif + return tp; +} + +/** + * Verifies if the specified thread is in the \p PREXIT state. + * @param tp the pointer to the thread + * @return \p TRUE if the thread is ended else \p FALSE. \p TRUE ensures that + * a subsequent call to \p chThdWait() would not block. + */ +BOOL chThdTerminated(Thread *tp) { + + return tp->p_state == PREXIT; +} + +#ifdef CH_USE_RESUME +/** + * Resumes a thread created with the \p P_SUSPENDED option. + * @param tp the pointer to the thread + * @note The function has no effect on threads in any other state than + * \p PRSUSPENDED. + * @note The function is available only if the \p CH_USE_RESUME + * option is enabled in \p chconf.h. + */ +void chThdResume(Thread *tp) { + + chSysLock(); + + if (tp->p_state == PRSUSPENDED) + chSchWakeupI(tp, RDY_OK); + + chSysUnlock(); +} +#endif + +#ifdef CH_USE_TERMINATE +/** + * Requests a thread termination. + * @param tp the pointer to the thread + * @note The thread is not termitated but a termination request is added to + * its \p p_flags field. The thread can read this status by + * invoking \p chThdShouldTerminate() and then terminate cleanly. + */ +void chThdTerminate(Thread *tp) { + + chSysLock(); + + tp->p_flags |= P_TERMINATE; + + chSysUnlock(); +} + +/** + * Verifies if the current thread has a termination request pending. + * @return \p TRUE if the termination was requested. The thread should terminate + * as soon it is ready to do so. + */ +BOOL chThdShouldTerminate(void) { + + return currp->p_flags & P_TERMINATE ? TRUE : FALSE; +} + +#endif + +/** + * Terminates the current thread by specifying an exit status code. + * @param msg the thread exit code. The code can be retrieved by using + * \p chThdWait(). + */ +void chThdExit(t_msg msg) { + + chSysLock(); + + currp->p_exitcode = msg; /* Post mortem info. */ +#ifdef CH_USE_WAITEXIT + while (notempty(&currp->p_waiting)) + chSchReadyI(dequeue(currp->p_waiting.p_next)); +#endif +#ifdef CH_USE_EXIT_EVENT + chEvtSendI(&currp->p_exitesource); +#endif + chSchGoSleepI(PREXIT); + + chSysUnlock(); /* Never executed. */ +} + +#ifdef CH_USE_WAITEXIT +/** + * Blocks the execution of the invoking thread until the specified thread + * terminates then the exit code is returned. + * @param tp the pointer to the thread + * @return the exit code + * @note The function is available only if the \p CH_USE_WAITEXIT + * option is enabled in \p chconf.h. + */ +t_msg chThdWait(Thread *tp) { + + chSysLock(); + + if (tp->p_state != PREXIT) { + enqueue(currp, &tp->p_waiting); + chSchGoSleepI(PRWAIT); + } + + chSysUnlock(); + return tp->p_exitcode; +} +#endif /* CH_USE_WAITEXIT */ + +#ifdef CH_USE_EXIT_EVENT +/** + * Returns the exit event source for the specified thread. The source is + * signaled when the thread terminates. + * @param tp the pointer to the thread + * @note When registering on a thread termination make sure the thread + * is still alive, if you do that after the thread termination + * then you would miss the event. There are two ways to ensure + * this:
+ *
    + *
  • Create the thread suspended, register on the event source + * and then resume the thread (recommended).
  • + *
  • Create the thread with a lower priority then register on it. + * This does not work if the hardware is capable of multiple + * physical threads.
  • + *
+ * @note You dont need to unregister from a terminated thread because + * the event source becomes inactive. + * @note The function is available only if the \p CH_USE_EXIT_EVENT + * option is enabled in \p chconf.h. + */ +EventSource *chThdGetExitEventSource(Thread *tp) { + + return &tp->p_exitesource; +} +#endif /* CH_USE_EXIT_EVENT */ + +/** @} */ -- cgit v1.2.3