PRIVILEGED_FUNCTION bool TaskManager_HandleFault(TaskManager_FaultType_t type, uint32_t pc, uint32_t faultAddr) { // FIXME check it was application code (not // ISR or library code) that faulted: bool will_handle = type & TaskManager_FaultFromThread; type &= ~TaskManager_FaultFromThread; if (will_handle) { // Get task handle xTaskHandle handle = xTaskGetCurrentTaskHandleFromISR(); // Suspend task vTaskSuspendFromISR(handle); // Add task to kill queue struct TaskKillInfo_t task = { .type = type, .handle = handle, .pc = pc, .faultAddr = faultAddr, }; signed portBASE_TYPE yield; xQueueSendFromISR(xKillQueue, &task, &yield); if (yield) portYIELD_WITHIN_API(); } return will_handle; }
static void prvProcessTimerOrBlockTask( const TickType_t xNextExpireTime, BaseType_t xListWasEmpty ) { TickType_t xTimeNow; BaseType_t xTimerListsWereSwitched; vTaskSuspendAll(); { /* Obtain the time now to make an assessment as to whether the timer has expired or not. If obtaining the time causes the lists to switch then don't process this timer as any timers that remained in the list when the lists were switched will have been processed within the prvSampleTimeNow() function. */ xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched ); if( xTimerListsWereSwitched == pdFALSE ) { /* The tick count has not overflowed, has the timer expired? */ if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) ) { ( void ) xTaskResumeAll(); prvProcessExpiredTimer( xNextExpireTime, xTimeNow ); } else { /* The tick count has not overflowed, and the next expire time has not been reached yet. This task should therefore block to wait for the next expire time or a command to be received - whichever comes first. The following line cannot be reached unless xNextExpireTime > xTimeNow, except in the case when the current timer list is empty. */ if( xListWasEmpty != pdFALSE ) { /* The current timer list is empty - is the overflow list also empty? */ xListWasEmpty = listLIST_IS_EMPTY( pxOverflowTimerList ); } vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ), xListWasEmpty ); if( xTaskResumeAll() == pdFALSE ) { /* Yield to wait for either a command to arrive, or the block time to expire. If a command arrived between the critical section being exited and this yield then the yield will not cause the task to block. */ portYIELD_WITHIN_API(); } else { mtCOVERAGE_TEST_MARKER(); } } } else { ( void ) xTaskResumeAll(); } } }
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait ) { EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; EventBits_t uxReturn, uxControlBits = 0; BaseType_t xWaitConditionMet, xAlreadyYielded; /* Check the user is not attempting to wait on the bits used by the kernel itself, and that at least one bit is being requested. */ configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); configASSERT( uxBitsToWaitFor != 0 ); #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) { configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); } #endif vTaskSuspendAll(); { const EventBits_t uxCurrentEventBits = pxEventBits->uxEventBits; traceEVENT_GROUP_WAIT_BITS_START( xEventGroup, uxBitsToWaitFor ); /* Check to see if the wait condition is already met or not. */ xWaitConditionMet = prvTestWaitCondition( uxCurrentEventBits, uxBitsToWaitFor, xWaitForAllBits ); if( xWaitConditionMet != pdFALSE ) { /* The wait condition has already been met so there is no need to block. */ uxReturn = uxCurrentEventBits; xTicksToWait = ( TickType_t ) 0; /* Clear the wait bits if requested to do so. */ if( xClearOnExit != pdFALSE ) { pxEventBits->uxEventBits &= ~uxBitsToWaitFor; } else { mtCOVERAGE_TEST_MARKER(); } } else if( xTicksToWait == ( TickType_t ) 0 ) { /* The wait condition has not been met, but no block time was specified, so just return the current value. */ uxReturn = uxCurrentEventBits; } else { /* The task is going to block to wait for its required bits to be set. uxControlBits are used to remember the specified behaviour of this call to xEventGroupWaitBits() - for use when the event bits unblock the task. */ if( xClearOnExit != pdFALSE ) { uxControlBits |= eventCLEAR_EVENTS_ON_EXIT_BIT; } else { mtCOVERAGE_TEST_MARKER(); } if( xWaitForAllBits != pdFALSE ) { uxControlBits |= eventWAIT_FOR_ALL_BITS; } else { mtCOVERAGE_TEST_MARKER(); } /* Store the bits that the calling task is waiting for in the task's event list item so the kernel knows when a match is found. Then enter the blocked state. */ vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | uxControlBits ), xTicksToWait ); /* This is obsolete as it will get set after the task unblocks, but some compilers mistakenly generate a warning about the variable being returned without being set if it is not done. */ uxReturn = 0; } } xAlreadyYielded = xTaskResumeAll(); if( xTicksToWait != ( TickType_t ) 0 ) { if( xAlreadyYielded == pdFALSE ) { portYIELD_WITHIN_API(); } else { mtCOVERAGE_TEST_MARKER(); } /* The task blocked to wait for its required bits to be set - at this point either the required bits were set or the block time expired. If the required bits were set they will have been stored in the task's event list item, and they should now be retrieved then cleared. */ uxReturn = uxTaskResetEventItemValue(); if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) { taskENTER_CRITICAL(); { /* The task timed out, just return the current event bit value. */ uxReturn = pxEventBits->uxEventBits; /* It is possible that the event bits were updated between this task leaving the Blocked state and running again. */ if( prvTestWaitCondition( uxReturn, uxBitsToWaitFor, xWaitForAllBits ) != pdFALSE ) { if( xClearOnExit != pdFALSE ) { pxEventBits->uxEventBits &= ~uxBitsToWaitFor; } else { mtCOVERAGE_TEST_MARKER(); } } else { mtCOVERAGE_TEST_MARKER(); } } taskEXIT_CRITICAL(); } else { /* The task unblocked because the bits were set. Clear the control bits before returning the value. */ uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; } } traceEVENT_GROUP_WAIT_BITS_END( xEventGroup, uxReturn ); return uxReturn; }
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet, const EventBits_t uxBitsToWaitFor, TickType_t xTicksToWait ) { EventBits_t uxOriginalBitValue, uxReturn; EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup; BaseType_t xAlreadyYielded; configASSERT( ( uxBitsToWaitFor & eventEVENT_BITS_CONTROL_BYTES ) == 0 ); configASSERT( uxBitsToWaitFor != 0 ); #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) { configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); } #endif vTaskSuspendAll(); { traceEVENT_GROUP_SYNC_START( xEventGroup, uxBitsToSet ); uxOriginalBitValue = pxEventBits->uxEventBits; ( void ) xEventGroupSetBits( xEventGroup, uxBitsToSet ); if( ( ( uxOriginalBitValue | uxBitsToSet ) & uxBitsToWaitFor ) == uxBitsToWaitFor ) { /* All the rendezvous bits are now set - no need to block. */ uxReturn = ( uxOriginalBitValue | uxBitsToSet ); /* Rendezvous always clear the bits. They will have been cleared already unless this is the only task in the rendezvous. */ pxEventBits->uxEventBits &= uxBitsToWaitFor; xTicksToWait = 0; } else { if( xTicksToWait != ( TickType_t ) 0 ) { /* Store the bits that the calling task is waiting for in the task's event list item so the kernel knows when a match is found. Then enter the blocked state. */ vTaskPlaceOnUnorderedEventList( &( pxEventBits->xTasksWaitingForBits ), ( uxBitsToWaitFor | eventCLEAR_EVENTS_ON_EXIT_BIT | eventWAIT_FOR_ALL_BITS ), xTicksToWait ); /* This assignment is obsolete as uxReturn will get set after the task unblocks, but some compilers mistakenly generate a warning about uxReturn being returned without being set if the assignment is omitted. */ uxReturn = 0; } else { /* The rendezvous bits were not set, but no block time was specified - just return the current event bit value. */ uxReturn = pxEventBits->uxEventBits; } } } xAlreadyYielded = xTaskResumeAll(); if( xTicksToWait != ( TickType_t ) 0 ) { if( xAlreadyYielded == pdFALSE ) { portYIELD_WITHIN_API(); } else { mtCOVERAGE_TEST_MARKER(); } /* The task blocked to wait for its required bits to be set - at this point either the required bits were set or the block time expired. If the required bits were set they will have been stored in the task's event list item, and they should now be retrieved then cleared. */ uxReturn = uxTaskResetEventItemValue(); if( ( uxReturn & eventUNBLOCKED_DUE_TO_BIT_SET ) == ( EventBits_t ) 0 ) { /* The task timed out, just return the current event bit value. */ taskENTER_CRITICAL(); { uxReturn = pxEventBits->uxEventBits; /* Although the task got here because it timed out before the bits it was waiting for were set, it is possible that since it unblocked another task has set the bits. If this is the case then it may be required to clear the bits before exiting. */ if( ( uxReturn & uxBitsToWaitFor ) == uxBitsToWaitFor ) { pxEventBits->uxEventBits &= ~uxBitsToWaitFor; } else { mtCOVERAGE_TEST_MARKER(); } } taskEXIT_CRITICAL(); } else { /* The task unblocked because the bits were set. Clear the control bits before returning the value. */ uxReturn &= ~eventEVENT_BITS_CONTROL_BYTES; } } traceEVENT_GROUP_SYNC_END( xEventGroup, uxReturn ); return uxReturn; }
/* * ======== MessageQCopy_send ======== */ Int MessageQCopy_send(UInt32 dstEndpt, UInt32 srcEndpt, Ptr data, UInt16 len, portTickType timeout) { Int16 token; MessageQCopy_Msg msg; Int length; xTimeOutType tmchk; /* Send to remote processor: */ taskENTER_CRITICAL(&virtQueLock); token = VirtQueue_getAvailBuf(vQueToHost, (Void **)&msg, &length); if(token < 0){ if(timeout == 0){ taskEXIT_CRITICAL(&virtQueLock); return MessageQCopy_E_TIMEOUT; } vTaskSetTimeOutState(&tmchk); waitAvaileBuf++; for(;;){ portTickType waitEvent; /* Because this function is not an application code, */ /* there is not the problem with using vTaskPlaceOnEventList. */ waitEvent = (timeout > 5) ? 5 : timeout; vTaskPlaceOnEventList(&availBufList, waitEvent); portYIELD_WITHIN_API(); taskEXIT_CRITICAL(&virtQueLock); taskENTER_CRITICAL(&virtQueLock); token = VirtQueue_getAvailBuf(vQueToHost, (Void **)&msg, &length); if(token < 0){ if(xTaskCheckForTimeOut(&tmchk, &timeout) == pdFALSE){ continue; } waitAvaileBuf--; taskEXIT_CRITICAL(&virtQueLock); return MessageQCopy_E_TIMEOUT; } waitAvaileBuf--; if(waitAvaileBuf == 0){ /* No need to know be kicked about added buffers anymore */ PROHIBIT_VRING_NOTIFY(vQueToHost); } break; } } if(len > RP_MSG_PAYLOAD_SIZE){ len = RP_MSG_PAYLOAD_SIZE; } /* Copy the payload and set message header: */ memcpy(msg->payload, data, len); msg->dataLen = len; msg->dstAddr = dstEndpt; msg->srcAddr = srcEndpt; msg->flags = 0; msg->reserved = 0; VirtQueue_addUsedBuf(vQueToHost, token, RP_MSG_BUF_SIZE); VirtQueue_kick(vQueToHost); taskEXIT_CRITICAL(&virtQueLock); return MessageQCopy_S_SUCCESS; }