/* Flag that allows the master task to control when the interrupt gives or does\r
not give the mutex. There is no mutual exclusion on this variable, but this is\r
only test code and it should be fine in the 32=bit test environment. */\r
-static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE;\r
+static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE, xOkToGiveMasterSlaveMutex = pdFALSE;\r
\r
/* Used to coordinate timing between tasks and the interrupt. */\r
const TickType_t xInterruptGivePeriod = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS );\r
\r
static void prvTakeAndGiveInTheSameOrder( void )\r
{\r
+static BaseType_t xGiveFromTask = pdTRUE;\r
+\r
/* Ensure the slave is suspended, and that this task is running at the\r
lower priority as expected as the start conditions. */\r
#if( INCLUDE_eTaskGetState == 1 )\r
/* Finally give back the shared mutex. This time the higher priority\r
task should run before this task runs again - so this task should have\r
disinherited the priority and the higher priority task should be in the\r
- suspended state again. */\r
- if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )\r
+ suspended state again. Alternatve beetween giving the mutex from this task,\r
+ and giving it from the interrupt. */\r
+ if( xGiveFromTask == pdTRUE )\r
{\r
- xErrorDetected = pdTRUE;\r
+ if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )\r
+ {\r
+ xErrorDetected = pdTRUE;\r
+ }\r
+\r
+ /* Give the mutex from the interrupt on the next go around. */\r
+ xGiveFromTask = pdFALSE;\r
+ }\r
+ else\r
+ {\r
+ /* Wait for the mutex to be given from the interrupt. */\r
+ xOkToGiveMasterSlaveMutex = pdTRUE;\r
+ vTaskDelay( xInterruptGivePeriod + ( xInterruptGivePeriod >> 1 ) );\r
+ xOkToGiveMasterSlaveMutex = pdFALSE;\r
+\r
+ /* Give the mutex from the task on the next go around. */\r
+ xGiveFromTask = pdTRUE;\r
}\r
\r
if( uxTaskPriorityGet( NULL ) != intsemMASTER_PRIORITY )\r
xTimeNow = xTaskGetTickCountFromISR();\r
if( ( ( TickType_t ) ( xTimeNow - xLastGiveTime ) ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) )\r
{\r
- configASSERT( xISRMutex );\r
if( xOkToGiveMutex != pdFALSE )\r
{\r
+ configASSERT( xISRMutex );\r
+\r
/* Null is used as the second parameter in this give, and non-NULL\r
- in the other gives for code coverage reasons. */\r
- xSemaphoreGiveFromISR( xISRMutex, NULL );\r
+ in the other gives, for code coverage reasons. NOTE: This is a\r
+ Mutex, so xQueueGiveFromISR() should be used in place of\r
+ xSemaphoreGiveFromISR() in case there is a mutex holder that has\r
+ inherited a priority (although, in the case of xISRMutex, there\r
+ isn't). The "item to queue" parameter is set to NULL as no data is \r
+ copied into a mutex.*/\r
+ xQueueSendFromISR( ( QueueHandle_t ) xISRMutex, NULL, NULL );\r
+\r
+ /* Second give attempt should fail. */\r
+ configASSERT( xQueueSendFromISR( xISRMutex, NULL, &xHigherPriorityTaskWoken ) == pdFAIL );\r
+ }\r
+\r
+ if( xOkToGiveMasterSlaveMutex != pdFALSE )\r
+ {\r
+ configASSERT( xOkToGiveMasterSlaveMutex );\r
+\r
+ /* NOTE: This is a Mutex, so xQueueGiveFromISR() should be used in \r
+ place of xSemaphoreGiveFromISR() in case there is a mutex holder \r
+ that has inherited a priority (as indeed there is in this case). \r
+ The "item to queue" parameter is set to NULL as no data is copied \r
+ into a mutex. */\r
+ xQueueSendFromISR( ( QueueHandle_t ) xMasterSlaveMutex, NULL, NULL );\r
\r
/* Second give attempt should fail. */\r
- configASSERT( xSemaphoreGiveFromISR( xISRMutex, &xHigherPriorityTaskWoken ) == pdFAIL );\r
+ configASSERT( xQueueSendFromISR( xMasterSlaveMutex, NULL, &xHigherPriorityTaskWoken ) == pdFAIL );\r
}\r
\r
if( xOkToGiveCountingSemaphore != pdFALSE )\r
\r
void xNotifyTaskFromISR( void )\r
{\r
-static BaseType_t xCallCount = 0;\r
+static BaseType_t xCallCount = 0, xAPIToUse = 0;\r
const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );\r
+uint32_t ulPreviousValue;\r
+const uint32_t ulUnexpectedValue = 0xff;\r
\r
/* The task performs some tests before starting the timer that gives the\r
notification from this interrupt. If the timer has not been created yet\r
/* It is time to 'give' the notification again. */\r
xCallCount = 0;\r
\r
- vTaskNotifyGiveFromISR( xTaskToNotify, NULL );\r
+ /* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()\r
+ and xTaskNotifyAndQueryFromISR(). */\r
+ switch( xAPIToUse )\r
+ {\r
+ case 0: vTaskNotifyGiveFromISR( xTaskToNotify, NULL );\r
+ xAPIToUse++;\r
+ break;\r
+\r
+ case 1: xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );\r
+ xAPIToUse++;\r
+ break;\r
+\r
+ case 2: ulPreviousValue = ulUnexpectedValue;\r
+ xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );\r
+ configASSERT( ulPreviousValue != ulUnexpectedValue );\r
+ xAPIToUse = 0;\r
+ break;\r
+\r
+ default:/* Should never get here!. */\r
+ break; \r
+ }\r
+ \r
ulTimerNotificationsSent++;\r
}\r
}\r
( void ) ulLine;\r
( void ) pcFileName;\r
\r
+ printf( "ASSERT! Line %d, file %s\r\n", ulLine, pcFileName );\r
+\r
taskENTER_CRITICAL();\r
{\r
/* Stop the trace recording. */\r
* @param eAction Specifies how the notification updates the task's notification\r
* value, if at all. Valid values for eAction are as follows:\r
*\r
- * eSetBits -\r
- * The task's notification value is bitwise ORed with ulValue. xTaskNofify()\r
- * always returns pdPASS in this case.\r
- *\r
- * eIncrement -\r
- * The task's notification value is incremented. ulValue is not used and\r
- * xTaskNotify() always returns pdPASS in this case.\r
- *\r
- * eSetValueWithOverwrite -\r
- * The task's notification value is set to the value of ulValue, even if the\r
- * task being notified had not yet processed the previous notification (the\r
- * task already had a notification pending). xTaskNotify() always returns\r
- * pdPASS in this case.\r
- *\r
- * eSetValueWithoutOverwrite -\r
- * If the task being notified did not already have a notification pending then\r
- * the task's notification value is set to ulValue and xTaskNotify() will\r
- * return pdPASS. If the task being notified already had a notification\r
- * pending then no action is performed and pdFAIL is returned.\r
- *\r
- * eNoAction -\r
- * The task receives a notification without its notification value being\r
- * updated. ulValue is not used and xTaskNotify() always returns pdPASS in\r
- * this case.\r
+ * eSetBits -\r
+ * The task's notification value is bitwise ORed with ulValue. xTaskNofify()\r
+ * always returns pdPASS in this case.\r
+ *\r
+ * eIncrement -\r
+ * The task's notification value is incremented. ulValue is not used and\r
+ * xTaskNotify() always returns pdPASS in this case.\r
+ *\r
+ * eSetValueWithOverwrite -\r
+ * The task's notification value is set to the value of ulValue, even if the\r
+ * task being notified had not yet processed the previous notification (the\r
+ * task already had a notification pending). xTaskNotify() always returns\r
+ * pdPASS in this case.\r
+ *\r
+ * eSetValueWithoutOverwrite -\r
+ * If the task being notified did not already have a notification pending then\r
+ * the task's notification value is set to ulValue and xTaskNotify() will\r
+ * return pdPASS. If the task being notified already had a notification\r
+ * pending then no action is performed and pdFAIL is returned.\r
+ *\r
+ * eNoAction -\r
+ * The task receives a notification without its notification value being\r
+ * updated. ulValue is not used and xTaskNotify() always returns pdPASS in\r
+ * this case.\r
*\r
* pulPreviousNotificationValue -\r
* Can be used to pass out the subject task's notification value before any\r
* @param eAction Specifies how the notification updates the task's notification\r
* value, if at all. Valid values for eAction are as follows:\r
*\r
- * eSetBits -\r
- * The task's notification value is bitwise ORed with ulValue. xTaskNofify()\r
- * always returns pdPASS in this case.\r
+ * eSetBits -\r
+ * The task's notification value is bitwise ORed with ulValue. xTaskNofify()\r
+ * always returns pdPASS in this case.\r
*\r
- * eIncrement -\r
- * The task's notification value is incremented. ulValue is not used and\r
- * xTaskNotify() always returns pdPASS in this case.\r
+ * eIncrement -\r
+ * The task's notification value is incremented. ulValue is not used and\r
+ * xTaskNotify() always returns pdPASS in this case.\r
*\r
- * eSetValueWithOverwrite -\r
- * The task's notification value is set to the value of ulValue, even if the\r
- * task being notified had not yet processed the previous notification (the\r
- * task already had a notification pending). xTaskNotify() always returns\r
- * pdPASS in this case.\r
+ * eSetValueWithOverwrite -\r
+ * The task's notification value is set to the value of ulValue, even if the\r
+ * task being notified had not yet processed the previous notification (the\r
+ * task already had a notification pending). xTaskNotify() always returns\r
+ * pdPASS in this case.\r
*\r
- * eSetValueWithoutOverwrite -\r
- * If the task being notified did not already have a notification pending then\r
- * the task's notification value is set to ulValue and xTaskNotify() will\r
- * return pdPASS. If the task being notified already had a notification\r
- * pending then no action is performed and pdFAIL is returned.\r
+ * eSetValueWithoutOverwrite -\r
+ * If the task being notified did not already have a notification pending then\r
+ * the task's notification value is set to ulValue and xTaskNotify() will\r
+ * return pdPASS. If the task being notified already had a notification\r
+ * pending then no action is performed and pdFAIL is returned.\r
*\r
- * eNoAction -\r
- * The task receives a notification without its notification value being\r
- * updated. ulValue is not used and xTaskNotify() always returns pdPASS in\r
- * this case.\r
+ * eNoAction -\r
+ * The task receives a notification without its notification value being\r
+ * updated. ulValue is not used and xTaskNotify() always returns pdPASS in\r
+ * this case.\r
*\r
* @param pxHigherPriorityTaskWoken xTaskNotifyFromISR() will set\r
* *pxHigherPriorityTaskWoken to pdTRUE if sending the notification caused the\r
* \defgroup xTaskNotify xTaskNotify\r
* \ingroup TaskNotifications\r
*/\r
-BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;\r
+BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;\r
+#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) )\r
+#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) )\r
\r
/**\r
* task. h\r
if the item size is not 0. */\r
configASSERT( pxQueue->uxItemSize == 0 );\r
\r
- /* Normally a mutex would not be given from an interrupt, and doing so is\r
- definitely wrong if there is a mutex holder as priority inheritance makes no\r
- sense for an interrupts, only tasks. */\r
+ /* Normally a mutex would not be given from an interrupt, especially if \r
+ there is a mutex holder, as priority inheritance makes no sense for an \r
+ interrupts, only tasks. However, on occasions when it is wanted to give\r
+ a mutex from an interrupt, use xQueueSendFromISR() in place of\r
+ xSemaphoreGiveFromISR(). */\r
configASSERT( !( ( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) && ( pxQueue->pxMutexHolder != NULL ) ) );\r
\r
/* RTOS ports that support interrupt nesting have the concept of a maximum\r
\r
if( pxMutexHolder != NULL )\r
{\r
- /* A task can only have an inherited priority if it holds the mutex.\r
- If the mutex is held by a task then it cannot be given from an\r
- interrupt, and if a mutex is given by the holding task then it must\r
- be the running state task. */\r
- configASSERT( pxTCB == pxCurrentTCB );\r
-\r
configASSERT( pxTCB->uxMutexesHeld );\r
( pxTCB->uxMutexesHeld )--;\r
\r
\r
#if( configUSE_TASK_NOTIFICATIONS == 1 )\r
\r
- BaseType_t xTaskNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, BaseType_t *pxHigherPriorityTaskWoken )\r
+ BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )\r
{\r
TCB_t * pxTCB;\r
eNotifyValue eOriginalNotifyState;\r
\r
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();\r
{\r
- eOriginalNotifyState = pxTCB->eNotifyState;\r
+ if( pulPreviousNotificationValue != NULL )\r
+ {\r
+ *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;\r
+ }\r
\r
+ eOriginalNotifyState = pxTCB->eNotifyState;\r
pxTCB->eNotifyState = eNotified;\r
\r
switch( eAction )\r