/* * Copyright (c) 2013-2019 Arm Limited. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * 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 * * 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. * * ----------------------------------------------------------------------------- * * Project: CMSIS-RTOS RTX * Title: Event Flags functions * * ----------------------------------------------------------------------------- */ #include "rtx_lib.h" // OS Runtime Object Memory Usage #if ((defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0))) osRtxObjectMemUsage_t osRtxEventFlagsMemUsage __attribute__((section(".data.os.evflags.obj"))) = {0U, 0U, 0U}; #endif // ==== Helper functions ==== /// Set Event Flags. /// \param[in] ef event flags object. /// \param[in] flags specifies the flags to set. /// \return event flags after setting. static uint32_t EventFlagsSet(os_event_flags_t *ef, uint32_t flags) { #if (EXCLUSIVE_ACCESS == 0) uint32_t primask = __get_PRIMASK(); #endif uint32_t event_flags; #if (EXCLUSIVE_ACCESS == 0) __disable_irq(); ef->event_flags |= flags; event_flags = ef->event_flags; if (primask == 0U) { __enable_irq(); } #else event_flags = atomic_set32(&ef->event_flags, flags); #endif return event_flags; } /// Clear Event Flags. /// \param[in] ef event flags object. /// \param[in] flags specifies the flags to clear. /// \return event flags before clearing. static uint32_t EventFlagsClear(os_event_flags_t *ef, uint32_t flags) { #if (EXCLUSIVE_ACCESS == 0) uint32_t primask = __get_PRIMASK(); #endif uint32_t event_flags; #if (EXCLUSIVE_ACCESS == 0) __disable_irq(); event_flags = ef->event_flags; ef->event_flags &= ~flags; if (primask == 0U) { __enable_irq(); } #else event_flags = atomic_clr32(&ef->event_flags, flags); #endif return event_flags; } /// Check Event Flags. /// \param[in] ef event flags object. /// \param[in] flags specifies the flags to check. /// \param[in] options specifies flags options (osFlagsXxxx). /// \return event flags before clearing or 0 if specified flags have not been /// set. static uint32_t EventFlagsCheck(os_event_flags_t *ef, uint32_t flags, uint32_t options) { #if (EXCLUSIVE_ACCESS == 0) uint32_t primask; #endif uint32_t event_flags; if ((options & osFlagsNoClear) == 0U) { #if (EXCLUSIVE_ACCESS == 0) primask = __get_PRIMASK(); __disable_irq(); event_flags = ef->event_flags; if ((((options & osFlagsWaitAll) != 0U) && ((event_flags & flags) != flags)) || (((options & osFlagsWaitAll) == 0U) && ((event_flags & flags) == 0U))) { event_flags = 0U; } else { ef->event_flags &= ~flags; } if (primask == 0U) { __enable_irq(); } #else if ((options & osFlagsWaitAll) != 0U) { event_flags = atomic_chk32_all(&ef->event_flags, flags); } else { event_flags = atomic_chk32_any(&ef->event_flags, flags); } #endif } else { event_flags = ef->event_flags; if ((((options & osFlagsWaitAll) != 0U) && ((event_flags & flags) != flags)) || (((options & osFlagsWaitAll) == 0U) && ((event_flags & flags) == 0U))) { event_flags = 0U; } } return event_flags; } // ==== Post ISR processing ==== /// Event Flags post ISR processing. /// \param[in] ef event flags object. static void osRtxEventFlagsPostProcess(os_event_flags_t *ef) { os_thread_t *thread; os_thread_t *thread_next; uint32_t event_flags; // Check if Threads are waiting for Event Flags thread = ef->thread_list; while (thread != NULL) { thread_next = thread->thread_next; event_flags = EventFlagsCheck(ef, thread->wait_flags, thread->flags_options); if (event_flags != 0U) { osRtxThreadListRemove(thread); osRtxThreadWaitExit(thread, event_flags, FALSE); EvrRtxEventFlagsWaitCompleted(ef, thread->wait_flags, thread->flags_options, event_flags); } thread = thread_next; } } // ==== Service Calls ==== /// Create and Initialize an Event Flags object. /// \note API identical to osEventFlagsNew static osEventFlagsId_t svcRtxEventFlagsNew(const osEventFlagsAttr_t *attr) { os_event_flags_t *ef; uint8_t flags; const char *name; // Process attributes if (attr != NULL) { name = attr->name; // lint -e{9079} "conversion from pointer to void to pointer to other type" // [MISRA Note 6] ef = attr->cb_mem; if (ef != NULL) { // lint -e(923) -e(9078) "cast from pointer to unsigned int" [MISRA Note // 7] if ((((uint32_t)ef & 3U) != 0U) || (attr->cb_size < sizeof(os_event_flags_t))) { EvrRtxEventFlagsError(NULL, osRtxErrorInvalidControlBlock); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return NULL; } } else { if (attr->cb_size != 0U) { EvrRtxEventFlagsError(NULL, osRtxErrorInvalidControlBlock); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return NULL; } } } else { name = NULL; ef = NULL; } // Allocate object memory if not provided if (ef == NULL) { if (osRtxInfo.mpi.event_flags != NULL) { // lint -e{9079} "conversion from pointer to void to pointer to other // type" [MISRA Note 5] ef = osRtxMemoryPoolAlloc(osRtxInfo.mpi.event_flags); } else { // lint -e{9079} "conversion from pointer to void to pointer to other // type" [MISRA Note 5] ef = osRtxMemoryAlloc(osRtxInfo.mem.common, sizeof(os_event_flags_t), 1U); } #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)) if (ef != NULL) { uint32_t used; osRtxEventFlagsMemUsage.cnt_alloc++; used = osRtxEventFlagsMemUsage.cnt_alloc - osRtxEventFlagsMemUsage.cnt_free; if (osRtxEventFlagsMemUsage.max_used < used) { osRtxEventFlagsMemUsage.max_used = used; } } #endif flags = osRtxFlagSystemObject; } else { flags = 0U; } if (ef != NULL) { // Initialize control block ef->id = osRtxIdEventFlags; ef->flags = flags; ef->name = name; ef->thread_list = NULL; ef->event_flags = 0U; // Register post ISR processing function osRtxInfo.post_process.event_flags = osRtxEventFlagsPostProcess; EvrRtxEventFlagsCreated(ef, ef->name); } else { EvrRtxEventFlagsError(NULL, (int32_t)osErrorNoMemory); } return ef; } /// Get name of an Event Flags object. /// \note API identical to osEventFlagsGetName static const char *svcRtxEventFlagsGetName(osEventFlagsId_t ef_id) { os_event_flags_t *ef = osRtxEventFlagsId(ef_id); // Check parameters if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) { EvrRtxEventFlagsGetName(ef, NULL); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return NULL; } EvrRtxEventFlagsGetName(ef, ef->name); return ef->name; } /// Set the specified Event Flags. /// \note API identical to osEventFlagsSet static uint32_t svcRtxEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) { os_event_flags_t *ef = osRtxEventFlagsId(ef_id); os_thread_t *thread; os_thread_t *thread_next; uint32_t event_flags; uint32_t event_flags0; // Check parameters if ((ef == NULL) || (ef->id != osRtxIdEventFlags) || ((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) { EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return ((uint32_t)osErrorParameter); } // Set Event Flags event_flags = EventFlagsSet(ef, flags); // Check if Threads are waiting for Event Flags thread = ef->thread_list; while (thread != NULL) { thread_next = thread->thread_next; event_flags0 = EventFlagsCheck(ef, thread->wait_flags, thread->flags_options); if (event_flags0 != 0U) { if ((thread->flags_options & osFlagsNoClear) == 0U) { event_flags = event_flags0 & ~thread->wait_flags; } else { event_flags = event_flags0; } osRtxThreadListRemove(thread); osRtxThreadWaitExit(thread, event_flags0, FALSE); EvrRtxEventFlagsWaitCompleted(ef, thread->wait_flags, thread->flags_options, event_flags0); } thread = thread_next; } osRtxThreadDispatch(NULL); EvrRtxEventFlagsSetDone(ef, event_flags); return event_flags; } /// Clear the specified Event Flags. /// \note API identical to osEventFlagsClear static uint32_t svcRtxEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) { os_event_flags_t *ef = osRtxEventFlagsId(ef_id); uint32_t event_flags; // Check parameters if ((ef == NULL) || (ef->id != osRtxIdEventFlags) || ((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) { EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return ((uint32_t)osErrorParameter); } // Clear Event Flags event_flags = EventFlagsClear(ef, flags); EvrRtxEventFlagsClearDone(ef, event_flags); return event_flags; } /// Get the current Event Flags. /// \note API identical to osEventFlagsGet static uint32_t svcRtxEventFlagsGet(osEventFlagsId_t ef_id) { os_event_flags_t *ef = osRtxEventFlagsId(ef_id); // Check parameters if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) { EvrRtxEventFlagsGet(ef, 0U); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return 0U; } EvrRtxEventFlagsGet(ef, ef->event_flags); return ef->event_flags; } /// Wait for one or more Event Flags to become signaled. /// \note API identical to osEventFlagsWait static uint32_t svcRtxEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) { os_event_flags_t *ef = osRtxEventFlagsId(ef_id); os_thread_t *thread; uint32_t event_flags; // Check parameters if ((ef == NULL) || (ef->id != osRtxIdEventFlags) || ((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) { EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return ((uint32_t)osErrorParameter); } // Check Event Flags event_flags = EventFlagsCheck(ef, flags, options); if (event_flags != 0U) { EvrRtxEventFlagsWaitCompleted(ef, flags, options, event_flags); } else { // Check if timeout is specified if (timeout != 0U) { EvrRtxEventFlagsWaitPending(ef, flags, options, timeout); // Suspend current Thread if (osRtxThreadWaitEnter(osRtxThreadWaitingEventFlags, timeout)) { thread = osRtxThreadGetRunning(); osRtxThreadListPut(osRtxObject(ef), thread); // Store waiting flags and options thread->wait_flags = flags; thread->flags_options = (uint8_t)options; } else { EvrRtxEventFlagsWaitTimeout(ef); } event_flags = (uint32_t)osErrorTimeout; } else { EvrRtxEventFlagsWaitNotCompleted(ef, flags, options); event_flags = (uint32_t)osErrorResource; } } return event_flags; } /// Delete an Event Flags object. /// \note API identical to osEventFlagsDelete static osStatus_t svcRtxEventFlagsDelete(osEventFlagsId_t ef_id) { os_event_flags_t *ef = osRtxEventFlagsId(ef_id); os_thread_t *thread; // Check parameters if ((ef == NULL) || (ef->id != osRtxIdEventFlags)) { EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return osErrorParameter; } // Unblock waiting threads if (ef->thread_list != NULL) { do { thread = osRtxThreadListGet(osRtxObject(ef)); osRtxThreadWaitExit(thread, (uint32_t)osErrorResource, FALSE); } while (ef->thread_list != NULL); osRtxThreadDispatch(NULL); } // Mark object as invalid ef->id = osRtxIdInvalid; // Free object memory if ((ef->flags & osRtxFlagSystemObject) != 0U) { if (osRtxInfo.mpi.event_flags != NULL) { (void)osRtxMemoryPoolFree(osRtxInfo.mpi.event_flags, ef); } else { (void)osRtxMemoryFree(osRtxInfo.mem.common, ef); } #if (defined(OS_OBJ_MEM_USAGE) && (OS_OBJ_MEM_USAGE != 0)) osRtxEventFlagsMemUsage.cnt_free++; #endif } EvrRtxEventFlagsDestroyed(ef); return osOK; } // Service Calls definitions // lint ++flb "Library Begin" [MISRA Note 11] SVC0_1(EventFlagsNew, osEventFlagsId_t, const osEventFlagsAttr_t *) SVC0_1(EventFlagsGetName, const char *, osEventFlagsId_t) SVC0_2(EventFlagsSet, uint32_t, osEventFlagsId_t, uint32_t) SVC0_2(EventFlagsClear, uint32_t, osEventFlagsId_t, uint32_t) SVC0_1(EventFlagsGet, uint32_t, osEventFlagsId_t) SVC0_4(EventFlagsWait, uint32_t, osEventFlagsId_t, uint32_t, uint32_t, uint32_t) SVC0_1(EventFlagsDelete, osStatus_t, osEventFlagsId_t) // lint --flb "Library End" // ==== ISR Calls ==== /// Set the specified Event Flags. /// \note API identical to osEventFlagsSet __STATIC_INLINE uint32_t isrRtxEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) { os_event_flags_t *ef = osRtxEventFlagsId(ef_id); uint32_t event_flags; // Check parameters if ((ef == NULL) || (ef->id != osRtxIdEventFlags) || ((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) { EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return ((uint32_t)osErrorParameter); } // Set Event Flags event_flags = EventFlagsSet(ef, flags); // Register post ISR processing osRtxPostProcess(osRtxObject(ef)); EvrRtxEventFlagsSetDone(ef, event_flags); return event_flags; } /// Wait for one or more Event Flags to become signaled. /// \note API identical to osEventFlagsWait __STATIC_INLINE uint32_t isrRtxEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) { os_event_flags_t *ef = osRtxEventFlagsId(ef_id); uint32_t event_flags; // Check parameters if ((ef == NULL) || (ef->id != osRtxIdEventFlags) || (timeout != 0U) || ((flags & ~(((uint32_t)1U << osRtxEventFlagsLimit) - 1U)) != 0U)) { EvrRtxEventFlagsError(ef, (int32_t)osErrorParameter); // lint -e{904} "Return statement before end of function" [MISRA Note 1] return ((uint32_t)osErrorParameter); } // Check Event Flags event_flags = EventFlagsCheck(ef, flags, options); if (event_flags != 0U) { EvrRtxEventFlagsWaitCompleted(ef, flags, options, event_flags); } else { EvrRtxEventFlagsWaitNotCompleted(ef, flags, options); event_flags = (uint32_t)osErrorResource; } return event_flags; } // ==== Public API ==== /// Create and Initialize an Event Flags object. osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr) { osEventFlagsId_t ef_id; EvrRtxEventFlagsNew(attr); if (IsIrqMode() || IsIrqMasked()) { EvrRtxEventFlagsError(NULL, (int32_t)osErrorISR); ef_id = NULL; } else { ef_id = __svcEventFlagsNew(attr); } return ef_id; } /// Get name of an Event Flags object. const char *osEventFlagsGetName(osEventFlagsId_t ef_id) { const char *name; if (IsIrqMode() || IsIrqMasked()) { EvrRtxEventFlagsGetName(ef_id, NULL); name = NULL; } else { name = __svcEventFlagsGetName(ef_id); } return name; } /// Set the specified Event Flags. uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags) { uint32_t event_flags; EvrRtxEventFlagsSet(ef_id, flags); if (IsIrqMode() || IsIrqMasked()) { event_flags = isrRtxEventFlagsSet(ef_id, flags); } else { event_flags = __svcEventFlagsSet(ef_id, flags); } return event_flags; } /// Clear the specified Event Flags. uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags) { uint32_t event_flags; EvrRtxEventFlagsClear(ef_id, flags); if (IsIrqMode() || IsIrqMasked()) { event_flags = svcRtxEventFlagsClear(ef_id, flags); } else { event_flags = __svcEventFlagsClear(ef_id, flags); } return event_flags; } /// Get the current Event Flags. uint32_t osEventFlagsGet(osEventFlagsId_t ef_id) { uint32_t event_flags; if (IsIrqMode() || IsIrqMasked()) { event_flags = svcRtxEventFlagsGet(ef_id); } else { event_flags = __svcEventFlagsGet(ef_id); } return event_flags; } /// Wait for one or more Event Flags to become signaled. uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout) { uint32_t event_flags; EvrRtxEventFlagsWait(ef_id, flags, options, timeout); if (IsIrqMode() || IsIrqMasked()) { event_flags = isrRtxEventFlagsWait(ef_id, flags, options, timeout); } else { event_flags = __svcEventFlagsWait(ef_id, flags, options, timeout); } return event_flags; } /// Delete an Event Flags object. osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id) { osStatus_t status; EvrRtxEventFlagsDelete(ef_id); if (IsIrqMode() || IsIrqMasked()) { EvrRtxEventFlagsError(ef_id, (int32_t)osErrorISR); status = osErrorISR; } else { status = __svcEventFlagsDelete(ef_id); } return status; }