From a923a46007f6ae63deac2183319ba064e7b2921c Mon Sep 17 00:00:00 2001 From: gdisirio Date: Wed, 4 Sep 2013 10:26:42 +0000 Subject: git-svn-id: svn://svn.code.sf.net/p/chibios/svn/branches/kernel_3_dev@6259 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/nil/include/nil.h | 107 ++++++++++-------- os/nil/osal/osal.h | 52 +++++++-- os/nil/ports/ARMCMx/compilers/GCC/niltypes.h | 1 + os/nil/src/nil.c | 157 ++++++++++++++++++++++----- 4 files changed, 235 insertions(+), 82 deletions(-) (limited to 'os/nil') diff --git a/os/nil/include/nil.h b/os/nil/include/nil.h index 30c8012b0..ea6839d6b 100644 --- a/os/nil/include/nil.h +++ b/os/nil/include/nil.h @@ -88,10 +88,27 @@ #define NIL_STATE_SLEEPING 1 /**< @brief Thread sleeping. */ #define NIL_STATE_SUSP 2 /**< @brief Thread suspended. */ #define NIL_STATE_WTSEM 3 /**< @brief Thread waiting on semaphore.*/ +#define NIL_STATE_WTOREVT 4 /**< @brief Thread waiting for events. */ #define NIL_THD_IS_READY(tr) ((tr)->state == NIL_STATE_READY) #define NIL_THD_IS_SLEEPING(tr) ((tr)->state == NIL_STATE_SLEEPING) #define NIL_THD_IS_SUSP(tr) ((tr)->state == NIL_STATE_SUSP) #define NIL_THD_IS_WTSEM(tr) ((tr)->state == NIL_STATE_WTSEM) +#define NIL_THD_IS_WTOREVT(tr) ((tr)->state == NIL_STATE_WTOREVT) +/** @} */ + +/** + * @name Events related macros + * @{ + */ +/** + * @brief All events allowed mask. + */ +#define ALL_EVENTS ((eventmask_t)-1) + +/** + * @brief Returns an event mask from an event identifier. + */ +#define EVENT_MASK(eid) ((eventmask_t)(1 << (eid))) /** @} */ /*===========================================================================*/ @@ -110,8 +127,8 @@ /** * @brief System timer resolution in Hz. */ -#if !defined(NIL_CFG_FREQUENCY) || defined(__DOXYGEN__) -#define NIL_CFG_FREQUENCY 100 +#if !defined(NIL_CFG_ST_FREQUENCY) || defined(__DOXYGEN__) +#define NIL_CFG_ST_FREQUENCY 100 #endif /** @@ -126,6 +143,16 @@ #define NIL_CFG_TIMEDELTA 0 #endif +/** + * @brief Events Flags APIs. + * @details If enabled then the event flags APIs are included in the kernel. + * + * @note The default is @p TRUE. + */ +#if !defined(NIL_CFG_USE_EVENTS) || defined(__DOXYGEN__) +#define NIL_CFG_USE_EVENTS TRUE +#endif + /** * @brief System assertions. */ @@ -154,8 +181,8 @@ "ChibiOS/RT instead" #endif -#if NIL_CFG_FREQUENCY <= 0 -#error "invalid NIL_CFG_FREQUENCY specified" +#if NIL_CFG_ST_FREQUENCY <= 0 +#error "invalid NIL_CFG_ST_FREQUENCY specified" #endif #if (NIL_CFG_TIMEDELTA < 0) || (NIL_CFG_TIMEDELTA == 1) @@ -228,9 +255,15 @@ struct nil_thread { void *p; /**< @brief Generic pointer. */ thread_reference_t *trp; /**< @brief Pointer to thread reference. */ semaphore_t *semp; /**< @brief Pointer to semaphore. */ +#if NIL_CFG_USE_EVENTS + eventmask_t ewmask; /**< @brief Enabled events mask. */ +#endif } u1; volatile systime_t timeout;/**< @brief Timeout counter, zero if disabled. */ +#if NIL_CFG_USE_EVENTS + eventmask_t epmask; /**< @brief Pending events mask. */ +#endif /* Optional extra fields.*/ NIL_CFG_THREAD_EXT_FIELDS }; @@ -244,40 +277,40 @@ typedef struct { /** * @brief Pointer to the running thread. */ - thread_reference_t current; + thread_reference_t current; /** * @brief Pointer to the next thread to be executed. * @note This pointer must point at the same thread pointed by @p currp * or to an higher priority thread if a switch is required. */ - thread_reference_t next; + thread_reference_t next; #if NIL_CFG_TIMEDELTA == 0 || defined(__DOXYGEN__) /** * @brief System time. */ - systime_t systime; + systime_t systime; #endif #if NIL_CFG_TIMEDELTA > 0 || defined(__DOXYGEN__) /** * @brief System time of the last tick event. */ - systime_t lasttime; + systime_t lasttime; /** * @brief Time of the next scheduled tick event. */ - systime_t nexttime; + systime_t nexttime; #endif /** * @brief Thread structures for all the defined threads. */ - thread_t threads[NIL_CFG_NUM_THREADS + 1]; + thread_t threads[NIL_CFG_NUM_THREADS + 1]; #if CH_DBG_ENABLED || defined(__DOXYGEN__) /** * @brief Panic message. * @note This field is only present if some debug options have been * activated. */ - const char *dbg_panic_msg; + const char *dbg_panic_msg; #endif } nil_system_t; @@ -424,7 +457,7 @@ typedef struct { * @api */ #define S2ST(sec) \ - ((systime_t)((sec) * NIL_CFG_FREQUENCY)) + ((systime_t)((sec) * NIL_CFG_ST_FREQUENCY)) /** * @brief Milliseconds to system ticks. @@ -437,8 +470,8 @@ typedef struct { * @api */ #define MS2ST(msec) \ - ((systime_t)(((((uint32_t)(msec)) * ((uint32_t)NIL_CFG_FREQUENCY) - 1UL) /\ - 1000UL) + 1UL)) + ((systime_t)(((((uint32_t)(msec)) * \ + ((uint32_t)NIL_CFG_ST_FREQUENCY) - 1UL) / 1000UL) + 1UL)) /** * @brief Microseconds to system ticks. @@ -451,8 +484,8 @@ typedef struct { * @api */ #define US2ST(usec) \ - ((systime_t)(((((uint32_t)(usec)) * ((uint32_t)NIL_CFG_FREQUENCY) - 1UL) /\ - 1000000UL) + 1UL)) + ((systime_t)(((((uint32_t)(usec)) * \ + ((uint32_t)NIL_CFG_ST_FREQUENCY) - 1UL) / 1000000UL) + 1UL)) /** @} */ /** @@ -572,7 +605,7 @@ typedef struct { * @sclass */ #define chThdSleepUntilS(time) \ - chSchGoSleepTimeoutS(NIL_STATE_SLEEPING, (time) - chTimeNow()) + chSchGoSleepTimeoutS(NIL_STATE_SLEEPING, (time) - chVTGetSystemTimeX()) /** * @brief Initializes a semaphore with the specified counter value. @@ -625,36 +658,20 @@ typedef struct { * @details Returns the number of system ticks since the @p chSysInit() * invocation. * @note The counter can reach its maximum and then restart from zero. - * @note This function is designed to work with the @p chThdSleepUntil(). + * @note This function can be called from any context but its atomicity + * is not guaranteed on architectures whose word size is less than + * @systime_t size. * * @return The system time in ticks. * - * @iclass + * @xclass */ #if NIL_CFG_TIMEDELTA == 0 || defined(__DOXYGEN__) -#define chTimeNowI() (nil.systime) +#define chVTGetSystemTimeX() (nil.systime) #else -#define chTimeNowI() port_timer_get_time() +#define chVTGetSystemTimeX() port_timer_get_time() #endif -/** - * @brief Checks if the specified time is within the specified time window. - * @note When start==end then the function returns always true because the - * whole time range is specified. - * - * @param[in] time the time to be verified - * @param[in] start the start of the time window (inclusive) - * @param[in] end the end of the time window (non inclusive) - * - * @retval true current time within the specified time window. - * @retval false current time not within the specified time window. - * - * @api - */ -#define chTimeIsWithin(time, start, end) \ - ((end) > (start) ? ((time) >= (start)) && ((time) < (end)) : \ - ((time) >= (start)) || ((time) < (end))) - #if NIL_CFG_ENABLE_ASSERTS || defined(__DOXYGEN__) /** * @brief Condition assertion. @@ -671,9 +688,9 @@ typedef struct { * @api */ #if !defined(chDbgAssert) -#define chDbgAssert(c, r) { \ +#define chDbgAssert(c, r) { \ if (!(c)) \ - chSysHalt("A:"__CH_QUOTE(__FUNCTION__)":"__CH_QUOTE(__LINE__)); \ + chSysHalt("A:"__CH_QUOTE(__FUNCTION__)":"__CH_QUOTE(__LINE__)); \ } #endif /* !defined(chDbgAssert) */ #else /* !NIL_CFG_ENABLE_ASSERTS */ @@ -696,6 +713,8 @@ extern "C" { void chSysInit(void); void chSysHalt(const char *reason); void chSysTimerHandlerI(void); + syssts_t chSysGetStatusAndLockX(void); + void chSysRestoreStatusX(syssts_t sts); thread_reference_t chSchReadyI(thread_reference_t trp, msg_t msg); msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t timeout); void chSchRescheduleS(void); @@ -703,14 +722,16 @@ extern "C" { void chThdResumeI(thread_reference_t *trp, msg_t msg); void chThdSleep(systime_t time); void chThdSleepUntil(systime_t time); - systime_t chTimeNow(void); - bool chTimeNowIsWithin(systime_t start, systime_t end); + bool chVTIsTimeWithinX(systime_t time, systime_t start, systime_t end); msg_t chSemWaitTimeout(semaphore_t *sp, systime_t time); msg_t chSemWaitTimeoutS(semaphore_t *sp, systime_t time); void chSemSignal(semaphore_t *sp); void chSemSignalI(semaphore_t *sp); void chSemReset(semaphore_t *sp, cnt_t n); void chSemResetI(semaphore_t *sp, cnt_t n); + void chEvtSignal(thread_t *tp, eventmask_t mask); + void chEvtSignalI(thread_t *tp, eventmask_t mask); + eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t timeout); #ifdef __cplusplus } #endif diff --git a/os/nil/osal/osal.h b/os/nil/osal/osal.h index 3e58154fa..a974452da 100644 --- a/os/nil/osal/osal.h +++ b/os/nil/osal/osal.h @@ -107,6 +107,10 @@ /* Derived constants and error checks. */ /*===========================================================================*/ +#if !NIL_CFG_USE_EVENTS +#error "OSAL requires NIL_CFG_USE_EVENTS=TRUE" +#endif + #if !(OSAL_ST_MODE == OSAL_ST_MODE_NONE) && \ !(OSAL_ST_MODE == OSAL_ST_MODE_PERIODIC) && \ !(OSAL_ST_MODE == OSAL_ST_MODE_FREERUNNING) @@ -152,24 +156,41 @@ typedef uint32_t rtcnt_t; typedef thread_t * thread_reference_t; #endif -typedef (*eventcallback_t)() +/** + * @brief Type of an event flags object. + * @note The content of this structure is not part of the API and should + * not be relied upon. Implementers may define this structure in + * an entirely different way. + * @note Retrieval and clearing of the flags are not defined in this + * API and are implementation-dependent. + */ +typedef struct event_source event_source_t; + +/** + * @brief Type of an event source callback. + * @note This type is not part of the OSAL API and is provided + * exclusively as an example and for convenience. + */ +typedef void (*eventcallback_t)(event_source_t *); + /** * @brief Type of an event flags mask. */ typedef uint32_t eventflags_t; /** - * @brief Type of an event flags object. + * @brief Events source object. * @note The content of this structure is not part of the API and should * not be relied upon. Implementers may define this structure in * an entirely different way. * @note Retrieval and clearing of the flags are not defined in this * API and are implementation-dependent. */ -typedef struct { - volatile eventflags_t flags; /**< @brief Flags stored into the - object. */ -} eventsource_t; +struct event_source { + volatile eventflags_t flags; /**< @brief Stored event flags. */ + eventcallback_t cb; /**< @brief Event source callback. */ + void *param; /**< @brief User defined field. */ +}; /** * @brief Type of a mutex. @@ -653,9 +674,11 @@ static inline msg_t osalQueueGoSleepTimeoutS(threads_queue_t *tqp, * * @init */ -static inline void osalEventObjectInit(eventsource_t *esp) { +static inline void osalEventObjectInit(event_source_t *esp) { - chEvtObjectInit(esp); + esp->flags = 0; + esp->cb = NULL; + esp->param = NULL; } /** @@ -666,10 +689,12 @@ static inline void osalEventObjectInit(eventsource_t *esp) { * * @iclass */ -static inline void osalEventBroadcastFlagsI(eventsource_t *esp, +static inline void osalEventBroadcastFlagsI(event_source_t *esp, eventflags_t flags) { - chEvtBroadcastFlagsI(esp, flags); + esp->flags |= flags; + if (esp->cb != NULL) + esp->cb(esp); } /** @@ -680,10 +705,13 @@ static inline void osalEventBroadcastFlagsI(eventsource_t *esp, * * @iclass */ -static inline void osalEventBroadcastFlags(eventsource_t *esp, +static inline void osalEventBroadcastFlags(event_source_t *esp, eventflags_t flags) { - chEvtBroadcastFlags(esp, flags); + chSysLock(); + osalEventBroadcastFlagsI(esp, flags); + chSchRescheduleS(); + chSysUnlock(); } /** diff --git a/os/nil/ports/ARMCMx/compilers/GCC/niltypes.h b/os/nil/ports/ARMCMx/compilers/GCC/niltypes.h index 88dba58b8..0925c1daf 100644 --- a/os/nil/ports/ARMCMx/compilers/GCC/niltypes.h +++ b/os/nil/ports/ARMCMx/compilers/GCC/niltypes.h @@ -55,6 +55,7 @@ typedef uint32_t systime_t; /**< System time. */ typedef uint32_t rtcnt_t; /**< Realtime counter. */ typedef uint8_t tstate_t; /**< Thread state. */ typedef int32_t msg_t; /**< Inter-thread message. */ +typedef uint32_t eventmask_t; /**< Mask of event identifiers. */ typedef int32_t cnt_t; /**< Generic signed counter. */ typedef uint32_t ucnt_t; /**< Generic unsigned counter. */ diff --git a/os/nil/src/nil.c b/os/nil/src/nil.c index d316f01e0..809887de3 100644 --- a/os/nil/src/nil.c +++ b/os/nil/src/nil.c @@ -210,6 +210,52 @@ void chSysTimerHandlerI(void) { #endif } +/** + * @brief Returns the execution status and enters a critical zone. + * @details This functions enters into a critical zone and can be called + * from any context. Because its flexibility it is less efficient + * than @p chSysLock() which is preferable when the calling context + * is known. + * @post The system is in a critical zone. + * + * @return The previous system status, the encoding of this + * status word is architecture-dependent and opaque. + * + * @xclass + */ +syssts_t chSysGetStatusAndLockX(void) { + + syssts_t sts = port_get_irq_status(); + if (port_irq_enabled(sts)) { + if (port_is_isr_context()) + chSysLockFromISR(); + else + chSysLock(); + } + return sts; +} + +/** + * @brief Restores the specified execution status and leaves a critical zone. + * @note A call to @p chSchRescheduleS() is automatically performed + * if exiting the critical zone and if not in ISR context. + * + * @param[in] sts the system status to be restored. + * + * @xclass + */ +void chSysRestoreStatusX(syssts_t sts) { + + if (port_irq_enabled(sts)) { + if (port_is_isr_context()) + chSysUnlockFromISR(); + else { + chSchRescheduleS(); + chSysUnlock(); + } + } +} + /** * @brief Makes the specified thread ready for execution. * @@ -409,43 +455,23 @@ void chThdSleepUntil(systime_t time) { } /** - * @brief Current system time. - * @details Returns the number of system ticks since the @p chSysInit() - * invocation. - * @note The counter can reach its maximum and then restart from zero. - * @note This function is designed to work with the @p chThdSleepUntil(). - * - * @return The system time in ticks. - * - * @api - */ -systime_t chTimeNow(void) { - systime_t time; - - chSysLock(); - time = chTimeNowI(); - chSysUnlock(); - return time; -} - -/** - * @brief Checks if the current system time is within the specified time - * window. + * @brief Checks if the specified time is within the specified time window. * @note When start==end then the function returns always true because the * whole time range is specified. + * @note This function can be called from any context. * + * @param[in] time the time to be verified * @param[in] start the start of the time window (inclusive) * @param[in] end the end of the time window (non inclusive) - * * @retval true current time within the specified time window. * @retval false current time not within the specified time window. * - * @api + * @xclass */ -bool chTimeNowIsWithin(systime_t start, systime_t end) { +bool chVTIsTimeWithinX(systime_t time, systime_t start, systime_t end) { - systime_t time = chTimeNow(); - return chTimeIsWithin(time, start, end); + return end > start ? (time >= start) && (time < end) : + (time >= start) || (time < end); } /** @@ -625,4 +651,81 @@ void chSemResetI(semaphore_t *sp, cnt_t n) { } } +/** + * @brief Adds a set of event flags directly to the specified @p thread_t. + * + * @param[in] tp the thread to be signaled + * @param[in] mask the event flags set to be ORed + * + * @api + */ +void chEvtSignal(thread_t *tp, eventmask_t mask) { + + chSysLock(); + chEvtSignalI(tp, mask); + chSchRescheduleS(); + chSysUnlock(); +} + +/** + * @brief Adds a set of event flags directly to the specified @p thread_t. + * @post This function does not reschedule so a call to a rescheduling + * function must be performed before unlocking the kernel. Note that + * interrupt handlers always reschedule on exit so an explicit + * reschedule must not be performed in ISRs. + * + * @param[in] tp the thread to be signaled + * @param[in] mask the event flags set to be ORed + * + * @iclass + */ +void chEvtSignalI(thread_t *tp, eventmask_t mask) { + + tp->epmask |= mask; + if (NIL_THD_IS_WTOREVT(tp) && ((tp->epmask & tp->u1.ewmask) != 0)) + chSchReadyI(tp, MSG_OK); +} + +/** + * @brief Waits for any of the specified events. + * @details The function waits for any event among those specified in + * @p mask to become pending then the events are cleared and + * returned. + * + * @param[in] mask mask of the event flags that the function should wait + * for, @p ALL_EVENTS enables all the events + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_IMMEDIATE immediate timeout. + * - @a TIME_INFINITE no timeout. + * . + * @return The mask of the served and cleared events. + * @retval 0 if the operation has timed out. + * + * @api + */ +eventmask_t chEvtWaitAnyTimeout(eventmask_t mask, systime_t timeout) { + thread_t *ctp = nil.current; + eventmask_t m; + + chSysLock(); + + if ((m = (ctp->epmask & mask)) == 0) { + if (TIME_IMMEDIATE == timeout) { + chSysUnlock(); + return (eventmask_t)0; + } + ctp->u1.ewmask = mask; + if (chSchGoSleepTimeoutS(NIL_STATE_WTOREVT, timeout) < MSG_OK) { + chSysUnlock(); + return (eventmask_t)0; + } + m = ctp->epmask & mask; + } + ctp->epmask &= ~m; + + chSysUnlock(); + return m; +} + /** @} */ -- cgit v1.2.3