]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c
Add FreeRTOS-Plus directory with new directory structure so it matches the FreeRTOS...
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-Trace / trcKernel.c
diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c
new file mode 100644 (file)
index 0000000..98b84a8
--- /dev/null
@@ -0,0 +1,491 @@
+/*******************************************************************************\r
+ * FreeRTOS+Trace v2.3.0 Recorder Library\r
+ * Percepio AB, www.percepio.com\r
+ *\r
+ * trcKernel.c\r
+ *\r
+ * Functions for integration of the trace recorder library in the FreeRTOS \r
+ * kernel (requires FreeRTOS v7.1.0 or later).\r
+ * \r
+ * Terms of Use\r
+ * This software is copyright Percepio AB. The recorder library is free for\r
+ * use together with Percepio products. You may distribute the recorder library\r
+ * in its original form, including modifications in trcPort.c and trcPort.h\r
+ * given that these modification are clearly marked as your own modifications\r
+ * and documented in the initial comment section of these source files. \r
+ * This software is the intellectual property of Percepio AB and may not be \r
+ * sold or in other ways commercially redistributed without explicit written \r
+ * permission by Percepio AB.\r
+ *\r
+ * Disclaimer \r
+ * The trace tool and recorder library is being delivered to you AS IS and \r
+ * Percepio AB makes no warranty as to its use or performance. Percepio AB does \r
+ * not and cannot warrant the performance or results you may obtain by using the \r
+ * software or documentation. Percepio AB make no warranties, express or \r
+ * implied, as to noninfringement of third party rights, merchantability, or \r
+ * fitness for any particular purpose. In no event will Percepio AB, its \r
+ * technology partners, or distributors be liable to you for any consequential, \r
+ * incidental or special damages, including any lost profits or lost savings, \r
+ * even if a representative of Percepio AB has been advised of the possibility \r
+ * of such damages, or for any claim by any third party. Some jurisdictions do \r
+ * not allow the exclusion or limitation of incidental, consequential or special \r
+ * damages, or the exclusion of implied warranties or limitations on how long an \r
+ * implied warranty may last, so the above limitations may not apply to you.\r
+ *\r
+ * FreeRTOS+Trace is available as Free Edition and in two premium editions.\r
+ * You may use the premium features during 30 days for evaluation.\r
+ * Download FreeRTOS+Trace at http://www.percepio.com/products/downloads/\r
+ *\r
+ * Copyright Percepio AB, 2012.\r
+ * www.percepio.com\r
+ ******************************************************************************/\r
+\r
+#include "trcUser.h"\r
+#include "task.h"\r
+\r
+#if (configUSE_TRACE_FACILITY == 1)\r
+\r
+\r
+\r
+/******************************************************************************\r
+ * TraceObjectClassTable\r
+ * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_).\r
+ * This was added since we want to map both types of Mutex and both types of \r
+ * Semaphores on common classes for all Mutexes and all Semaphores respectively. \r
+ * \r
+ * FreeRTOS Queue types\r
+ * #define queueQUEUE_TYPE_BASE                  ( 0U ) => TRACE_CLASS_QUEUE\r
+ * #define queueQUEUE_TYPE_MUTEX                 ( 1U ) => TRACE_CLASS_MUTEX\r
+ * #define queueQUEUE_TYPE_COUNTING_SEMAPHORE    ( 2U ) => TRACE_CLASS_SEMAPHORE\r
+ * #define queueQUEUE_TYPE_BINARY_SEMAPHORE      ( 3U ) => TRACE_CLASS_SEMAPHORE\r
+ * #define queueQUEUE_TYPE_RECURSIVE_MUTEX       ( 4U ) => TRACE_CLASS_MUTEX \r
+ ******************************************************************************/\r
+traceObjectClass TraceObjectClassTable[5]        =  {TRACE_CLASS_QUEUE,     \r
+                                                     TRACE_CLASS_MUTEX,      \r
+                                                     TRACE_CLASS_SEMAPHORE,  \r
+                                                     TRACE_CLASS_SEMAPHORE,\r
+                                                     TRACE_CLASS_MUTEX };\r
+\r
+/* This is defined in FreeRTOS! */\r
+extern volatile void * volatile pxCurrentTCB; \r
+\r
+/* Internal variables */\r
+uint8_t nISRactive = 0;\r
+objectHandleType handle_of_last_logged_task = 0;\r
+uint8_t inExcludedTask = 0;\r
+\r
+static uint8_t prvTraceIsObjectExcluded(traceObjectClass, uint32_t);\r
+\r
+/*******************************************************************************\r
+ * prvTraceIsObjectExcluded\r
+ *\r
+ * Private function that accepts an object class and an object number and uses\r
+ * that to determine if the object has been flagged as excluded.\r
+ ******************************************************************************/\r
+static uint8_t prvTraceIsObjectExcluded(traceObjectClass objectClass, uint32_t objectNumber)\r
+{\r
+    switch(objectClass)\r
+    {\r
+    case TRACE_CLASS_QUEUE:\r
+        return GET_QUEUE_FLAG_ISEXCLUDED(objectNumber);\r
+        break;\r
+    case TRACE_CLASS_SEMAPHORE:\r
+        return GET_SEMAPHORE_FLAG_ISEXCLUDED(objectNumber);\r
+        break;\r
+    case TRACE_CLASS_MUTEX:\r
+        return GET_MUTEX_FLAG_ISEXCLUDED(objectNumber);\r
+        break;\r
+    case TRACE_CLASS_TASK:\r
+        return GET_TASK_FLAG_ISEXCLUDED(objectNumber);\r
+        break;\r
+    }\r
+    return 0;\r
+}\r
+\r
+#if !defined INCLUDE_READY_EVENTS || INCLUDE_READY_EVENTS == 1\r
+/*******************************************************************************\r
+ * vTraceStoreTaskReady\r
+ *\r
+ * This function stores a ready state for the task handle sent in as parameter.\r
+ ******************************************************************************/\r
+void vTraceStoreTaskReady(objectHandleType handle)\r
+{\r
+    uint16_t dts3;\r
+    TREvent* tr;\r
+\r
+    if (!GET_TASK_FLAG_ISEXCLUDED(handle))\r
+    {\r
+        dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
+        if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+        {\r
+            tr = (TREvent*)xTraceNextFreeEventBufferSlot();\r
+\r
+            if (tr != NULL)\r
+            {\r
+                tr->type = TR_TASK_READY;\r
+                tr->dts = dts3;\r
+                tr->objHandle = handle;\r
+\r
+                prvTraceUpdateCounters();    \r
+            }\r
+        }\r
+    }\r
+}\r
+#endif\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreKernelCall\r
+ *\r
+ * This is the main integration point for storing FreeRTOS kernel calls, and\r
+ * is called by the hooks in FreeRTOS.h (see trcKernel.h for event codes).\r
+ ******************************************************************************/\r
+void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber)\r
+{\r
+    KernelCall * kse;\r
+    uint16_t dts1;\r
+\r
+    if (handle_of_last_logged_task == 0)\r
+    {\r
+        return;\r
+    }\r
+    \r
+    if (RecorderDataPtr->recorderActive)\r
+    {\r
+        \r
+        /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */\r
+        if (nISRactive || !inExcludedTask)\r
+        {\r
+            /* Make sure ISRs never change the IFE flags of tasks */\r
+            if (!nISRactive)\r
+            {\r
+                /* This checks if this is the first kernel call after a call to\r
+                vTraceTaskInstanceIsFinished. In that case, calls to this kernel service \r
+                with this specific kernel object become the "instance finish event"\r
+                (IFE) of the calling task.*/\r
+                if (GET_TASK_FLAG_MARKIFE(handle_of_last_logged_task))\r
+                {\r
+                    /* Reset the flag - this has been handled now */\r
+                    CLEAR_TASK_FLAG_MARKIFE(handle_of_last_logged_task);\r
+\r
+                    /* Store the kernel service tagged as instance finished event */\r
+                    PROPERTY_TASK_IFE_SERVICECODE(handle_of_last_logged_task) = \r
+                      (uint8_t)ecode;                \r
+\r
+                    /* Store the handle of the specific kernel object */\r
+                    PROPERTY_TASK_IFE_OBJHANDLE(handle_of_last_logged_task) =\r
+                      (objectHandleType)objectNumber;    \r
+                }\r
+            }\r
+            \r
+            /* Check if the referenced object or the event code is excluded */\r
+            if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode))\r
+            {\r
+                trcCRITICAL_SECTION_BEGIN();\r
+                dts1 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
+\r
+                if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+                {           \r
+                    kse = (KernelCall*) xTraceNextFreeEventBufferSlot();\r
+                    if (kse != NULL)\r
+                    {\r
+                        kse->dts = dts1;\r
+                        kse->type = (uint8_t)ecode;\r
+                        kse->objHandle = (uint8_t)objectNumber;\r
+                        prvTraceUpdateCounters();\r
+                    }\r
+                }\r
+                trcCRITICAL_SECTION_END();\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreKernelCallWithParam\r
+ *\r
+ * Used for storing kernel calls with a handle and a numeric parameter. This is\r
+ * only used for traceTASK_PRIORITY_SET at the moment.\r
+ ******************************************************************************/\r
+void vTraceStoreKernelCallWithParam(uint32_t evtcode,\r
+                                    traceObjectClass objectClass,\r
+                                    uint32_t objectNumber,\r
+                                    uint8_t param)\r
+{\r
+    KernelCallWithParamAndHandle * kse;\r
+    uint8_t dts2;\r
+\r
+    if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && \r
+        (! inExcludedTask || nISRactive))\r
+    {\r
+        /* Check if the referenced object or the event code is excluded */\r
+        if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))\r
+        {\r
+            trcCRITICAL_SECTION_BEGIN();\r
+            dts2 = (uint8_t)prvTraceGetDTS(0xFF);\r
+\r
+            if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+            {                \r
+                kse = (KernelCallWithParamAndHandle*) xTraceNextFreeEventBufferSlot();\r
+                if (kse != NULL)\r
+                {\r
+                    kse->dts = dts2;\r
+                    kse->type = (uint8_t)evtcode;\r
+                    kse->objHandle = (uint8_t)objectNumber;\r
+                    kse->param = param;\r
+                    prvTraceUpdateCounters();    \r
+                }\r
+            }\r
+            trcCRITICAL_SECTION_END();\r
+        }\r
+    }\r
+}\r
+\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreKernelCallWithNumericParamOnly\r
+ *\r
+ * Used for storing kernel calls with numeric parameters only. This is\r
+ * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment.\r
+ ******************************************************************************/\r
+void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint16_t param)\r
+{\r
+    KernelCallWithParam16 * kse;\r
+    uint8_t dts6;\r
+\r
+    if (RecorderDataPtr->recorderActive && handle_of_last_logged_task \r
+        && (! inExcludedTask || nISRactive))\r
+    {\r
+        /* Check if the event code is excluded */\r
+        if (!GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))\r
+        {\r
+            trcCRITICAL_SECTION_BEGIN();\r
+            dts6 = (uint8_t)prvTraceGetDTS(0xFF);\r
+\r
+            if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+            {                \r
+                kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot();\r
+                if (kse != NULL)\r
+                {\r
+                    kse->dts = dts6;\r
+                    kse->type = (uint8_t)evtcode;\r
+                    kse->param = param;\r
+                    prvTraceUpdateCounters();    \r
+                }\r
+            }\r
+            trcCRITICAL_SECTION_END();\r
+        }\r
+    }\r
+}\r
+\r
+objectHandleType handle_of_running_task = 0;\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreTaskswitch\r
+ * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart.\r
+ * At this point interrupts are assumed to be disabled!\r
+ ******************************************************************************/\r
+void vTraceStoreTaskswitch(void)\r
+{\r
+    uint16_t dts3;\r
+    TSEvent* ts;        \r
+    int8_t skipEvent = 0;\r
+    uint32_t schedulerState = 0;\r
+    \r
+    /*************************************************************************** \r
+    This is used to detect if a high-priority ISRs is illegally using the \r
+    recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the \r
+    recorder is busy with a task-level event or lower priority ISR event.\r
+    \r
+    If this is detected, it triggers a call to vTraceError with the error \r
+    "Illegal call to vTraceStoreISRBegin/End". If you get this error, it means\r
+    that the macro taskENTER_CRITICAL does not disable this ISR, as required.\r
+    You can solve this by adjusting the value of the FreeRTOS constant\r
+    configMAX_SYSCALL_INTERRUPT_PRIORITY, which is defined in FreeRTOSConfig.h\r
+\r
+    Note: Setting recorder_busy is normally handled in our macros\r
+    trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this \r
+    function since critical sections should not be used in the context switch \r
+    event...)    \r
+    ***************************************************************************/\r
+    recorder_busy++; \r
+    \r
+    schedulerState = xTaskGetSchedulerState();\r
+\r
+    if (schedulerState == 0)\r
+    {\r
+        /* This occurs on the very first taskswitch event, generated by \r
+        vTraceStart and uiTraceStart if the scheduler is not yet started.\r
+        This creates a dummy "(startup)" task entry internally in the\r
+        recorder */\r
+        if (handle_of_running_task == 0)\r
+        {\r
+            handle_of_running_task = xTraceGetObjectHandle(TRACE_CLASS_TASK);\r
+\r
+            vTraceSetObjectName(TRACE_CLASS_TASK, \r
+                handle_of_running_task,\r
+                "(startup)");\r
+\r
+            vTraceSetPriorityProperty(TRACE_CLASS_TASK,\r
+                handle_of_running_task,\r
+                0);\r
+        }        \r
+    }\r
+    else\r
+    {    \r
+        handle_of_running_task = \r
+        (objectHandleType)uxTaskGetTaskNumber(xTaskGetCurrentTaskHandle());\r
+    }\r
+    \r
+    /* Skip the event if the task has been excluded, using vTraceExcludeTask */\r
+    if (GET_TASK_FLAG_ISEXCLUDED(handle_of_running_task))\r
+    {    \r
+        skipEvent = 1;\r
+        inExcludedTask = 1;            \r
+    }\r
+    else\r
+        inExcludedTask = 0;\r
+        \r
+\r
+    /* Skip the event if the same task is scheduled */\r
+    if (handle_of_running_task == handle_of_last_logged_task)\r
+    {\r
+        skipEvent = 1;\r
+    }\r
+  \r
+    if (! RecorderDataPtr->recorderActive)\r
+    {\r
+        skipEvent = 1;\r
+    }\r
+\r
+    /* If this event should be logged, log it! */\r
+    if (skipEvent == 0)    \r
+    {    \r
+        dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
+        \r
+        if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+        {\r
+            handle_of_last_logged_task = handle_of_running_task;            \r
+            ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
+\r
+            if (ts != NULL)\r
+            {\r
+                if (uiTraceGetObjectState(TRACE_CLASS_TASK,\r
+                    handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE)\r
+                {\r
+                    ts->type = TS_TASK_RESUME;\r
+                }\r
+                else\r
+                {\r
+                    ts->type = TS_TASK_BEGIN;\r
+                }\r
+\r
+                ts->dts = dts3;\r
+                ts->objHandle = handle_of_last_logged_task;\r
+\r
+                vTraceSetObjectState(TRACE_CLASS_TASK, \r
+                                     handle_of_last_logged_task, \r
+                                     TASK_STATE_INSTANCE_ACTIVE);\r
+\r
+                prvTraceUpdateCounters();    \r
+            }\r
+        }\r
+    }    \r
+\r
+    /* See comment on recorder_busy++ above. */\r
+    recorder_busy--; \r
+}\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreNameCloseEvent\r
+ *\r
+ * Updates the symbol table with the name of this object from the dynamic\r
+ * objects table and stores a "close" event, holding the mapping between handle\r
+ * and name (a symbol table handle). The stored name-handle mapping is thus the\r
+ * "old" one, valid up until this point.\r
+ ******************************************************************************/\r
+#if (INCLUDE_OBJECT_DELETE == 1)\r
+void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, \r
+                                       traceObjectClass objectclass)\r
+{    \r
+    ObjCloseNameEvent * ce;\r
+    const char * name;\r
+    traceLabel idx;\r
+\r
+    name = PROPERTY_NAME_GET(objectclass, handle);\r
+\r
+    idx = prvTraceOpenSymbol(name, 0);\r
+    \r
+    // Interrupt disable not necessary, already done in trcHooks.h macro\r
+    ce = (ObjCloseNameEvent*) xTraceNextFreeEventBufferSlot(); \r
+    if (ce != NULL)\r
+    {\r
+        ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass;\r
+        ce->objHandle = handle;\r
+        ce->symbolIndex = idx;\r
+        prvTraceUpdateCounters();\r
+    }\r
+    \r
+}\r
+\r
+void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, \r
+                                             traceObjectClass objectclass)\r
+{\r
+    ObjClosePropEvent * pe;\r
+\r
+    if (objectclass == TRACE_CLASS_ISR)\r
+    {        \r
+        /* ISR handles should not be closed - never called for ISR */\r
+        return;\r
+    }\r
+\r
+    // Interrupt disable not necessary, already done in trcHooks.h macro\r
+    pe = (ObjClosePropEvent*) xTraceNextFreeEventBufferSlot();\r
+    if (pe != NULL)\r
+    {\r
+        if (objectclass == TRACE_CLASS_TASK)\r
+        {\r
+            pe->arg1 = PROPERTY_ACTOR_PRIORITY(objectclass, handle);\r
+            pe->arg2 = PROPERTY_TASK_IFE_SERVICECODE(handle);\r
+            pe->arg3 = PROPERTY_TASK_IFE_OBJHANDLE(handle);\r
+            PROPERTY_TASK_IFE_SERVICECODE(handle) = 0;\r
+            PROPERTY_TASK_IFE_OBJHANDLE(handle) = 0;\r
+        }else{\r
+            pe->arg1 = PROPERTY_OBJECT_STATE(objectclass, handle);\r
+        }\r
+        pe->type = EVENTGROUP_OBJCLOSE_PROP + objectclass;    \r
+        prvTraceUpdateCounters();\r
+    }\r
+}\r
+#endif\r
+\r
+void vTraceSetPriorityProperty(uint8_t objectclass, uint8_t id, uint8_t value)\r
+{\r
+    PROPERTY_ACTOR_PRIORITY(objectclass, id) = value;\r
+}\r
+\r
+uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, uint8_t id)\r
+{\r
+    return PROPERTY_ACTOR_PRIORITY(objectclass, id);\r
+}\r
+\r
+void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value)\r
+{\r
+    PROPERTY_OBJECT_STATE(objectclass, id) = value;\r
+}\r
+\r
+void vTraceSetTaskInstanceFinished(objectHandleType handle)\r
+{\r
+#if (USE_IMPLICIT_IFE_RULES == 1)\r
+    if (PROPERTY_TASK_IFE_SERVICECODE(handle) == 0)\r
+    {\r
+        PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0;\r
+    }\r
+#endif\r
+}\r
+\r
+uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id)\r
+{\r
+    return PROPERTY_OBJECT_STATE(objectclass, id);\r
+}\r
+\r
+#endif\r