]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c
Update trace recorder to include heap tracing and new v8 features.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-Trace / trcUser.c
index 74dc8079e47d0d5bd9e1a631f339ec2d6d9b0d31..5f46a809de9879f9df94da9cc51a464e65888cd1 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************\r
- * Tracealyzer v2.5.0 Recorder Library\r
+ * Tracealyzer v2.6.0 Recorder Library\r
  * Percepio AB, www.percepio.com\r
  *\r
  * trcUser.c\r
@@ -34,6 +34,8 @@
  * Copyright Percepio AB, 2013.\r
  * www.percepio.com\r
  ******************************************************************************/\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
 \r
 #include "trcUser.h"\r
 \r
@@ -47,7 +49,7 @@ TRACE_STOP_HOOK vTraceStopHookPtr = (TRACE_STOP_HOOK)0;
 \r
 extern uint8_t inExcludedTask;\r
 extern uint8_t nISRactive;\r
-extern uint8_t handle_of_last_logged_task;\r
+extern objectHandleType handle_of_last_logged_task;\r
 extern uint32_t dts_min;\r
 extern uint32_t hwtc_count_max_after_tick;\r
 extern uint32_t hwtc_count_sum_after_tick;\r
@@ -99,12 +101,15 @@ void vTraceSetRecorderData(void* pRecorderData)
  ******************************************************************************/\r
 void vTraceClear(void)\r
 {\r
+    TRACE_SR_ALLOC_CRITICAL_SECTION();\r
     trcCRITICAL_SECTION_BEGIN();\r
 \r
     RecorderDataPtr->absTimeLastEvent = 0;\r
     RecorderDataPtr->nextFreeIndex = 0;\r
     RecorderDataPtr->numEvents = 0;\r
     RecorderDataPtr->bufferIsFull = 0;\r
+       traceErrorMessage = NULL;\r
+       RecorderDataPtr->internalErrorOccured = 0;\r
 \r
     trcCRITICAL_SECTION_END();\r
 \r
@@ -125,7 +130,10 @@ void vTraceClear(void)
 \r
 uint32_t uiTraceStart(void)\r
 {\r
-       objectHandleType handle = 0;\r
+       objectHandleType handle;\r
+    TRACE_SR_ALLOC_CRITICAL_SECTION();\r
+\r
+       handle = 0;\r
 \r
        if (RecorderDataPtr == NULL)\r
        {\r
@@ -300,6 +308,103 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio
     vTraceSetPriorityProperty(TRACE_CLASS_ISR, handle, priority);\r
 }\r
 \r
+#if (SELECTED_PORT == PORT_ARM_CortexM)\r
+/******************************************************************************\r
+ * (Advanced...)\r
+ *\r
+ * ISR_TAILCHAINING_THRESHOLD (For Cortex-M devices only)\r
+ *\r
+ * ARM Cortex-M devices may execute ISRs back-to-back (tail-chained) without \r
+ * resuming the previous context in between. Since this is decided in \r
+ * hardware, we can only detect this indirectly, in the following manner:\r
+ *\r
+ * When entering vTraceStoreISRBegin, we check the number of CPU cycles since \r
+ * the last return of vTraceStoreISREnd. If less or equal to the constant\r
+ * ISR_TAILCHAINING_THRESHOLD it is assumed that the ISRs executed back-to-back\r
+ * (tail-chained). In that case, the previously stored RESUME event \r
+ * (pointed to by ptrLastISRExitEvent) is then deleted to avoid showing a \r
+ * fragment of the previous context in between the ISR events. The delete is\r
+ * made by replacing the event code with a XTS16L event, that serves to keep\r
+ * the differential timestamp from the earlier event.\r
+ *\r
+ * The value of ISR_TAILCHAINING_THRESHOLD depends on the interrupt latency of \r
+ * the processor, on the compiler and on the compiler settings, but should be \r
+ * around 70 cycles. The default value is 66 cycles, which should be correct when \r
+ * using GCC with optimizations disabled (-O0) and Cortex-M3/M4.\r
+ *\r
+ * To measure this value, see MEASURE_ISR_TAILCHAINING_THRESHOLD below.\r
+ *\r
+ * If this value set too low, tail-chained ISRs will incorrectly be shown \r
+ * separated, with a short fragment of the previous task or ISR in between.\r
+ * If this value is set too high, you get the opposite effect - separate ISRs \r
+ * will appear to execute tail-chained and will appear to have higher execution \r
+ * time and response time (maximum ISR_TAILCHAINING_THRESHOLD cycles more).\r
+ *****************************************************************************/\r
+#define ISR_TAILCHAINING_THRESHOLD 66\r
+\r
+uint8_t* ptrLastISRExitEvent = NULL;\r
+uint32_t DWTCycleCountAtLastISRExit = 0;\r
+\r
+/******************************************************************************\r
+ * (Advanced...)\r
+ *\r
+ * MEASURE_ISR_TAILCHAINING_THRESHOLD (For Cortex-M devices only)\r
+ *\r
+ * Allows for measuring the value of ISR_TAILCHAINING_THRESHOLD (see above).\r
+ *\r
+ * This is intended to measure the minimum number of clock cycles from the end\r
+ * of vTraceStoreISREnd to the beginning of the following vTraceStoreISRBegin.\r
+ * For this purpose, we assume a test setup using the SysTick interrupt, which \r
+ * is available on most Cortex-M devices and typically used by the RTOS kernel. \r
+ * To do the measurement, follow these steps:\r
+ * \r
+ * 1. Make sure MEASURE_ISR_TAILCHAINING_THRESHOLD is enabled (defined as 1)\r
+ *\r
+ * 2. Temporarily replace your SysTick handler with the following:\r
+ *    \r
+ *    void xPortSysTickHandler( void )\r
+ *    {\r
+ *       vTraceStoreISRBegin(1); \r
+ *       vTraceStoreISREnd();\r
+ *    }\r
+ *\r
+ * 3. To make sure that the ISRs execute back-to-back, increase the OS tick \r
+ *    frequency to a very high level so that the OS tick interrupt execute \r
+ *    continuously with no application tasks in between. A tick frequency of \r
+ *    1 MHz (1.000.000) should be sufficient.\r
+ *\r
+ * 4. Put a breakpoint in the highest priority task and make sure it is not \r
+ *    reached. This means that the SysTick handler is executing at maximum rate\r
+ *    and thereby tail-chained, where the interrupt latency is 6 cycles.\r
+ *\r
+ * 5. Let the system run without breakpoints and inspect the value of \r
+ *    threshold_low_watermark. This is the minimum total latency observed. \r
+ *    The hardware latency is 6 clock cycles due to the tail-chaining, so the \r
+ *    software latency (SL) is then SL = threshold_low_watermark - 6.\r
+ * \r
+ * The threshold value ISR_TAILCHAINING_THRESHOLD should be SL + 2 * HL, where \r
+ * HL is the normal hardware interrupt latency, i.e., the number of CPU \r
+ * cycles to enter or exit the exception handler for an exception in task \r
+ * context. The HL value is 12-16 depending on core, as shown below.\r
+ * \r
+ * Values for ISR_TAILCHAINING_THRESHOLD, assuming SL = 42\r
+ *   Cortex-M3 and M4 (HL = 12):       66 cycles\r
+ *   Cortex-M0 (HL = 16):                      74 cycles\r
+ *   Cortex-M0+ (HL = 15):          72 cycles\r
+ *\r
+ * If the ISR_TAILCHAINING_THRESHOLD value is set too low, some tail-chained\r
+ * ISRs be shown separated, with a short fragment of the previous actor. If \r
+ * the value is set too high, separate ISRs will appear to execute tail-chained\r
+ * and for too long time.\r
+ *****************************************************************************/\r
+#define MEASURE_ISR_TAILCHAINING_THRESHOLD 1\r
+\r
+#if (MEASURE_ISR_TAILCHAINING_THRESHOLD == 1)\r
+volatile uint32_t threshold_low_watermark = 2000000000;\r
+#endif\r
+\r
+#endif\r
+\r
 /*******************************************************************************\r
  * vTraceStoreISRBegin\r
  *\r
@@ -318,34 +423,64 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio
  *         vTraceStoreISREnd();\r
  *     }\r
  *\r
- * NOTE: You need to make sure that any traced interrupts actually are\r
- * disabled by trcCRITICAL_SECTION_BEGIN().\r
- * If an invalid call to vTraceStoreISRBegin is detected (i.e., that preempted\r
- * a critical section of the recorder) this will generate a recorder error\r
- * using vTraceError.\r
  ******************************************************************************/\r
 void vTraceStoreISRBegin(objectHandleType handle)\r
 {\r
     uint16_t dts4;\r
-    TSEvent* ts = NULL;\r
+       #if (SELECTED_PORT == PORT_ARM_CortexM)\r
+       uint32_t CPUCyclesSinceLastISRExit = DWT_CYCLE_COUNTER - DWTCycleCountAtLastISRExit;\r
+       #endif  \r
+    TSEvent* ts;\r
+    TRACE_SR_ALLOC_CRITICAL_SECTION();\r
 \r
-    TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid value for handle", );\r
+       ts = NULL;\r
 \r
+#if (SELECTED_PORT == PORT_ARM_CortexM)\r
+       if (DWTCycleCountAtLastISRExit > 0)     \r
+       {\r
+               #if (MEASURE_ISR_TAILCHAINING_THRESHOLD == 1)           \r
+               /* Allows for verifying the value of ISR_TAILCHAINING_THRESHOLD */\r
+               if (CPUCyclesSinceLastISRExit < threshold_low_watermark)\r
+               {\r
+                       threshold_low_watermark = CPUCyclesSinceLastISRExit;\r
+               }\r
+               #endif\r
+               \r
+               if (CPUCyclesSinceLastISRExit <= ISR_TAILCHAINING_THRESHOLD)            \r
+               {                       \r
+                       /* This is judged to be a case of ISR tail-chaining since the \r
+                       number of cycles since the last vTraceStoreISREnd is shorter or equal to\r
+                       the threshold (ISR_TAILCHAINING_THRESHOLD) */\r
+                       \r
+                       if (ptrLastISRExitEvent != NULL)\r
+                       {                               \r
+                               /* Overwrite the last ISR exit event with a "neutral" event that only\r
+                   accounts for the time passed */\r
+                               *ptrLastISRExitEvent = XTS16L;                                                  \r
+                       }                       \r
+               }\r
+               \r
+       }\r
+#endif\r
+       \r
     if (recorder_busy)\r
     {\r
       vTraceError("Illegal call to vTraceStoreISRBegin, recorder busy!");\r
       return;\r
     }\r
+       trcCRITICAL_SECTION_BEGIN();\r
     if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
     {\r
-        trcCRITICAL_SECTION_BEGIN();\r
+\r
+           TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid value for handle", );\r
+\r
         dts4 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
 \r
         if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
         {\r
-\r
             if (nISRactive < MAX_ISR_NESTING)\r
             {\r
+                               uint8_t hnd8 = prvTraceGet8BitHandle(handle);\r
                 isrstack[nISRactive] = handle;\r
                 nISRactive++;\r
                 ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
@@ -353,7 +488,7 @@ void vTraceStoreISRBegin(objectHandleType handle)
                 {\r
                     ts->type = TS_ISR_BEGIN;\r
                     ts->dts = dts4;\r
-                    ts->objHandle = handle;\r
+                    ts->objHandle = hnd8;\r
                     prvTraceUpdateCounters();\r
                 }\r
             }\r
@@ -362,40 +497,11 @@ void vTraceStoreISRBegin(objectHandleType handle)
                 /* This should not occur unless something is very wrong */\r
                 vTraceError("Too many nested interrupts!");\r
             }\r
-        }\r
-        trcCRITICAL_SECTION_END();\r
-    }\r
-}\r
-\r
-\r
-#if (SELECTED_PORT == PORT_ARM_CortexM)\r
-\r
-static int tailchain_irq_pending(void);\r
-\r
-/*******************************************************************************\r
- * tailchain_irq_pending\r
- *\r
- * For Cortex-M chips only. Returns 1 if an interrupt is pending, by checking\r
- * the 8 NVIC IRQ pend registers at 0xE000E200 to 0xE000E21C. Returns 0 if no\r
- * interrupt is pending. This is used to predict tailchaining of ISRs.\r
- ******************************************************************************/\r
-static int tailchain_irq_pending(void)\r
-{\r
-  uint32_t* pend_reg = ((uint32_t*)0xE000E200);\r
-  int i;\r
-\r
-  for (i=0; i<8; i++)\r
-  {\r
-    if (pend_reg[i] != 0)\r
-    {\r
-      return 1;\r
+        }        \r
     }\r
-  }\r
-  return 0;\r
+       trcCRITICAL_SECTION_END();\r
 }\r
 \r
-#endif\r
-\r
 /*******************************************************************************\r
  * vTraceStoreISREnd\r
  *\r
@@ -414,63 +520,61 @@ static int tailchain_irq_pending(void)
  *         vTraceStoreISREnd();\r
  *     }\r
  *\r
- * NOTE: You need to make sure that any traced interrupts actually are\r
- * disabled by trcCRITICAL_SECTION_BEGIN().\r
- * If an invalid call to vTraceStoreISREnd is detected (i.e., that preempted\r
- * a critical section of the recorder) this will generate a recorder error\r
- * using vTraceError.\r
  ******************************************************************************/\r
 void vTraceStoreISREnd(void)\r
 {\r
-    TSEvent* ts;\r
-    uint16_t dts5;\r
+       TSEvent* ts;\r
+       uint16_t dts5;\r
+       TRACE_SR_ALLOC_CRITICAL_SECTION();\r
 \r
-    if (recorder_busy)\r
-    {\r
-      vTraceError("Illegal call to vTraceStoreISREnd, recorder busy!");\r
-      return;\r
-    }\r
+       if (recorder_busy)\r
+       {\r
+               vTraceError("Illegal call to vTraceStoreISREnd, recorder busy!");\r
+               return;\r
+       }\r
 \r
-    if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
-    {\r
-        #if (SELECTED_PORT == PORT_ARM_CortexM)\r
-        if (tailchain_irq_pending() > 0)\r
-        {\r
-            nISRactive--; /* If an IRQ strikes exactly here, the resulting\r
-            ISR tailchaining is not detected. The trace instead shows a very\r
-            short fragment of the earlier preempted task/ISR, and then the new\r
-            ISR begins. */\r
-            return;\r
-        }\r
-        #endif\r
+       trcCRITICAL_SECTION_BEGIN();\r
+       if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
+       {               \r
+               dts5 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
 \r
-        trcCRITICAL_SECTION_BEGIN();\r
-        dts5 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
+               if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+               {\r
+                       uint8_t hnd8, type;\r
 \r
-        if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
-        {\r
-            ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
-            if (ts != NULL)\r
-            {\r
-                if (nISRactive > 1)\r
-                {\r
-                    /* return to another isr */\r
-                    ts->type = TS_ISR_RESUME;\r
-                    ts->objHandle = isrstack[nISRactive];\r
-                }\r
-                else\r
-                {\r
-                    /* return to task */\r
-                    ts->type = TS_TASK_RESUME;\r
-                    ts->objHandle = handle_of_last_logged_task;\r
-                }\r
-                ts->dts = dts5;\r
-                nISRactive--;\r
-                prvTraceUpdateCounters();\r
-            }\r
-        }\r
-        trcCRITICAL_SECTION_END();\r
-    }\r
+                       if (nISRactive > 1)\r
+                       {\r
+                               /* return to another isr */\r
+                               type = TS_ISR_RESUME;\r
+                               hnd8 = prvTraceGet8BitHandle(isrstack[nISRactive]);\r
+                       }\r
+                       else\r
+                       {\r
+                               /* return to task */\r
+                               type = TS_TASK_RESUME;\r
+                               hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task);\r
+                       }\r
+\r
+                       ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
+\r
+                       if (ts != NULL)\r
+                       {\r
+                               ts->type = type;\r
+                               ts->objHandle = hnd8;\r
+                               ts->dts = dts5;\r
+                               nISRactive--;\r
+                               prvTraceUpdateCounters();\r
+                       }\r
+                                               \r
+               }\r
+               \r
+               #if (SELECTED_PORT == PORT_ARM_CortexM)\r
+               /* Remember the last ISR exit event, as the event needs to be modified in case of a following ISR entry (if tail-chained ISRs) */\r
+               ptrLastISRExitEvent = (uint8_t*)ts;\r
+               DWTCycleCountAtLastISRExit = DWT_CYCLE_COUNTER;\r
+               #endif  \r
+       }\r
+       trcCRITICAL_SECTION_END();\r
 }\r
 \r
 #else\r
@@ -605,7 +709,7 @@ static uint8_t writeDouble(void * buffer, uint8_t i, double value)
 {\r
        TRACE_ASSERT(buffer != NULL, "writeDouble: buffer == NULL", 0);\r
 \r
-    uint32_t * dest = buffer;\r
+    uint32_t * dest\r
     uint32_t * src = (void*)&value;\r
     /* The double is written as two 32 bit values, and should begin at an even\r
     4-byte address (to avoid having to align with 8 byte) */\r
@@ -624,9 +728,11 @@ static uint8_t writeDouble(void * buffer, uint8_t i, double value)
     {\r
         return 255;\r
     }\r
+       \r
+       dest = &(((uint32_t *)buffer)[i]);\r
 \r
-    dest[i/4+0] = src[0];\r
-    dest[i/4+1] = src[1];\r
+    dest[0] = src[0];\r
+    dest[1] = src[1];\r
 \r
     return i + 8;\r
 }\r
@@ -1049,6 +1155,7 @@ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list v
        uint32_t noOfSlots;\r
     UserEvent* ue1;\r
     uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];\r
+    TRACE_SR_ALLOC_CRITICAL_SECTION();\r
 \r
     /**************************************************************************\r
     * The array tempDataBuffer is a local buffer used in a two-phase commit of\r
@@ -1063,108 +1170,102 @@ void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list v
 \r
        TRACE_ASSERT(formatStr != NULL, "vTracePrintF: formatStr == NULL", );\r
 \r
+       trcCRITICAL_SECTION_BEGIN();\r
+       \r
     if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task)\r
     {\r
         /* First, write the "primary" user event entry in the local buffer, but\r
         let the event type be "EVENT_BEING_WRITTEN" for now...*/\r
 \r
         ue1 = (UserEvent*)(&tempDataBuffer[0]);\r
+               \r
         ue1->type = EVENT_BEING_WRITTEN;      /* Update this as the last step */\r
 \r
         noOfSlots = prvTraceUserEventFormat(formatStr, vl, (uint8_t*)tempDataBuffer, 4);\r
 \r
         /* Store the format string, with a reference to the channel symbol */\r
-        ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel);\r
-\r
-        trcCRITICAL_SECTION_BEGIN();\r
+        ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel);                      \r
 \r
         ue1->dts = (uint8_t)prvTraceGetDTS(0xFF);\r
-        if (! RecorderDataPtr->recorderActive)\r
+               \r
+                /* prvTraceGetDTS might stop the recorder in some cases... */\r
+        if (RecorderDataPtr->recorderActive)\r
         {\r
 \r
-            /* Abort, since an XTS event (created by prvTraceGetDTS) filled the\r
-            buffer, and the recorder stopped since not circular buffer. */\r
-            trcCRITICAL_SECTION_END();\r
-\r
-            return;\r
-        }\r
-\r
-        /* If the data does not fit in the remaining main buffer, wrap around to\r
-        0 if allowed, otherwise stop the recorder and quit). */\r
-        if (RecorderDataPtr->nextFreeIndex + noOfSlots > RecorderDataPtr->maxEvents)\r
-        {\r
-#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
-            (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],\r
-                   0,\r
-                   (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4);\r
-            RecorderDataPtr->nextFreeIndex = 0;\r
-            RecorderDataPtr->bufferIsFull = 1;\r
-#else\r
-            /* Abort and stop recorder, since the event data will not fit in the\r
-            buffer and not circular buffer in this case... */\r
-            trcCRITICAL_SECTION_END();\r
-            vTraceStop();\r
-\r
-\r
-            return;\r
-#endif\r
-        }\r
-\r
-#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
-        /* Check that the buffer to be overwritten does not contain any user\r
-        events that would be partially overwritten. If so, they must be "killed"\r
-        by replacing the user event and following data with NULL events (i.e.,\r
-        using a memset to zero).*/\r
-        prvCheckDataToBeOverwrittenForMultiEntryEvents((uint8_t)noOfSlots);\r
-#endif\r
-        /* Copy the local buffer to the main buffer */\r
-        (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],\r
-               tempDataBuffer,\r
-               noOfSlots * 4);\r
-\r
-        /* Update the event type, i.e., number of data entries following the\r
-        main USER_EVENT entry (Note: important that this is after the memcpy,\r
-        but within the critical section!)*/\r
-        RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] =\r
-          (uint8_t) ( USER_EVENT + noOfSlots - 1 );\r
-\r
-        /* Update the main buffer event index (already checked that it fits in\r
-        the buffer, so no need to check for wrapping)*/\r
-\r
-        RecorderDataPtr->nextFreeIndex += noOfSlots;\r
-        RecorderDataPtr->numEvents += noOfSlots;\r
-\r
-\r
-\r
-               if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE)\r
-               {\r
-#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
-                       /* We have reached the end, but this is a ring buffer. Start from the beginning again. */\r
-                       RecorderDataPtr->bufferIsFull = 1;\r
-                       RecorderDataPtr->nextFreeIndex = 0;\r
-#else\r
-                       /* We have reached the end so we stop. */\r
-                       vTraceStop();\r
-#endif\r
-               }\r
-\r
-#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
-               /* Make sure the next entry is cleared correctly */\r
-               prvCheckDataToBeOverwrittenForMultiEntryEvents(1);\r
-#endif\r
-\r
-#ifdef STOP_AFTER_N_EVENTS\r
-#if (STOP_AFTER_N_EVENTS > -1)\r
-               /* Check if we have reached the desired number of events */\r
-               if (RecorderDataPtr->numEvents >= STOP_AFTER_N_EVENTS)\r
-               {\r
-                       vTraceStop();\r
+                       /* If the data does not fit in the remaining main buffer, wrap around to\r
+                       0 if allowed, otherwise stop the recorder and quit). */\r
+                       if (RecorderDataPtr->nextFreeIndex + noOfSlots > RecorderDataPtr->maxEvents)\r
+                       {\r
+                               #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
+                               (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],\r
+                                          0,\r
+                                          (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4);\r
+                               RecorderDataPtr->nextFreeIndex = 0;\r
+                               RecorderDataPtr->bufferIsFull = 1;\r
+                               #else\r
+                               \r
+                               /* Stop recorder, since the event data will not fit in the\r
+                               buffer and not circular buffer in this case... */                               \r
+                               vTraceStop();                           \r
+                               #endif\r
+                       }\r
+                       \r
+                       /* Check if recorder has been stopped (i.e., vTraceStop above) */\r
+                       if (RecorderDataPtr->recorderActive)\r
+                       {                               \r
+                               /* Check that the buffer to be overwritten does not contain any user\r
+                               events that would be partially overwritten. If so, they must be "killed"\r
+                               by replacing the user event and following data with NULL events (i.e.,\r
+                               using a memset to zero).*/\r
+                               #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
+                               prvCheckDataToBeOverwrittenForMultiEntryEvents((uint8_t)noOfSlots);\r
+                               #endif\r
+                               /* Copy the local buffer to the main buffer */\r
+                               (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],\r
+                                          tempDataBuffer,\r
+                                          noOfSlots * 4);\r
+\r
+                               /* Update the event type, i.e., number of data entries following the\r
+                               main USER_EVENT entry (Note: important that this is after the memcpy,\r
+                               but within the critical section!)*/\r
+                               RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] =\r
+                                 (uint8_t) ( USER_EVENT + noOfSlots - 1 );\r
+\r
+                               /* Update the main buffer event index (already checked that it fits in\r
+                               the buffer, so no need to check for wrapping)*/\r
+\r
+                               RecorderDataPtr->nextFreeIndex += noOfSlots;\r
+                               RecorderDataPtr->numEvents += noOfSlots;\r
+\r
+                               if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE)\r
+                               {\r
+                                       #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
+                                       /* We have reached the end, but this is a ring buffer. Start from the beginning again. */\r
+                                       RecorderDataPtr->bufferIsFull = 1;\r
+                                       RecorderDataPtr->nextFreeIndex = 0;\r
+                                       #else\r
+                                       /* We have reached the end so we stop. */\r
+                                       vTraceStop();\r
+                                       #endif\r
+                               }\r
+                               \r
+                               #if (STOP_AFTER_N_EVENTS > -1)\r
+                               /* Check if we have reached the desired number of events */\r
+                               if (RecorderDataPtr->numEvents >= STOP_AFTER_N_EVENTS)\r
+                               {\r
+                                       vTraceStop();\r
+                               }\r
+                               #endif        \r
+                       }\r
+                       \r
+                       #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
+                       /* Make sure the next entry is cleared correctly */\r
+                       prvCheckDataToBeOverwrittenForMultiEntryEvents(1);\r
+                       #endif\r
+       \r
                }\r
-#endif\r
-#endif\r
-\r
-        trcCRITICAL_SECTION_END();\r
-    }\r
+       }\r
+       trcCRITICAL_SECTION_END();\r
 \r
 #elif (USE_SEPARATE_USER_EVENT_BUFFER == 1)\r
        /* Use the separate user event buffer */\r
@@ -1195,13 +1296,13 @@ void vTraceUserEvent(traceLabel eventLabel)
 #if (USE_SEPARATE_USER_EVENT_BUFFER == 0)\r
     UserEvent* ue;\r
     uint8_t dts1;\r
+    TRACE_SR_ALLOC_CRITICAL_SECTION();\r
 \r
        TRACE_ASSERT(eventLabel > 0, "vTraceUserEvent: Invalid value for eventLabel", );\r
 \r
+       trcCRITICAL_SECTION_BEGIN();    \r
     if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task)\r
-    {\r
-        trcCRITICAL_SECTION_BEGIN();\r
-\r
+    {    \r
         dts1 = (uint8_t)prvTraceGetDTS(0xFF);\r
 \r
         if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
@@ -1214,14 +1315,14 @@ void vTraceUserEvent(traceLabel eventLabel)
                 ue->payload = eventLabel;\r
                 prvTraceUpdateCounters();\r
             }\r
-        }\r
-        trcCRITICAL_SECTION_END();\r
+        }        \r
     }\r
+       trcCRITICAL_SECTION_END();\r
+       \r
 #elif (USE_SEPARATE_USER_EVENT_BUFFER == 1)\r
        UserEventChannel channel;\r
        uint32_t noOfSlots = 1;\r
-       uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];\r
-\r
+       uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];        \r
        if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task)\r
        {\r
                channel = xTraceRegisterChannelFormat(0, eventLabel);\r
@@ -1235,7 +1336,7 @@ void vTraceUserEvent(traceLabel eventLabel)
                }\r
 \r
                prvTraceUserEventHelper2(channel, tempDataBuffer, noOfSlots);\r
-       }\r
+       }       \r
 #endif\r
 }\r
 \r