| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824 |
- /*
- * SPDX-FileCopyrightText: 2020 Amazon.com, Inc. or its affiliates
- *
- * SPDX-License-Identifier: MIT
- */
- /*
- * FreeRTOS Kernel V10.4.3
- * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * https://www.FreeRTOS.org
- * https://github.com/FreeRTOS
- *
- */
- /*-----------------------------------------------------------
- * Implementation of functions defined in portable.h for the Posix port.
- *
- * Each task has a pthread which eases use of standard debuggers
- * (allowing backtraces of tasks etc). Threads for tasks that are not
- * running are blocked in sigwait().
- *
- * Task switch is done by resuming the thread for the next task by
- * signaling the condition variable and then waiting on a condition variable
- * with the current thread.
- *
- * The timer interrupt uses SIGALRM and care is taken to ensure that
- * the signal handler runs only on the thread for the current task.
- *
- * Use of part of the standard C library requires care as some
- * functions can take pthread mutexes internally which can result in
- * deadlocks as the FreeRTOS kernel can switch tasks while they're
- * holding a pthread mutex.
- *
- * stdio (printf() and friends) should be called from a single task
- * only or serialized with a FreeRTOS primitive such as a binary
- * semaphore or mutex.
- *----------------------------------------------------------*/
- #include <errno.h>
- #include <pthread.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/time.h>
- #include <sys/times.h>
- #include <time.h>
- #include <unistd.h>
- #include <assert.h>
- /* Scheduler includes. */
- #include "esp_heap_caps.h"
- #include "FreeRTOS.h"
- #include "task.h"
- #include "esp_task.h"
- #include "timers.h"
- #include "utils/wait_for_event.h"
- #include "esp_log.h"
- /*-----------------------------------------------------------*/
- #define SIG_RESUME SIGUSR1
- typedef struct THREAD
- {
- pthread_t pthread;
- TaskFunction_t pxCode;
- void *pvParams;
- BaseType_t xDying;
- struct event *ev;
- } Thread_t;
- /*
- * The additional per-thread data is stored at the beginning of the
- * task's stack.
- */
- static inline Thread_t *prvGetThreadFromTask(TaskHandle_t xTask)
- {
- StackType_t *pxTopOfStack = *(StackType_t **)xTask;
- return (Thread_t *)(pxTopOfStack + 1);
- }
- /*-----------------------------------------------------------*/
- static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT;
- static sigset_t xAllSignals;
- static sigset_t xSchedulerOriginalSignalMask;
- static pthread_t hMainThread = ( pthread_t )NULL;
- // These are saved as part of a thread's state in prvSwitchThread()
- static volatile BaseType_t uxCriticalNestingIDF = 0; /* Track nesting calls for IDF style critical sections. FreeRTOS critical section nesting is maintained in the TCB. */
- static volatile UBaseType_t uxInterruptNesting = 0; /* Tracks if we are currently in an interrupt. */
- static volatile BaseType_t uxInterruptLevel = 0; /* Tracks the current level (i.e., interrupt mask) */
- /*-----------------------------------------------------------*/
- static BaseType_t xSchedulerEnd = pdFALSE;
- /*-----------------------------------------------------------*/
- static void prvSetupSignalsAndSchedulerPolicy( void );
- static void prvSetupTimerInterrupt( void );
- static void *prvWaitForStart( void * pvParams );
- static void prvSwitchThread( Thread_t * xThreadToResume,
- Thread_t *xThreadToSuspend );
- static void prvSuspendSelf( Thread_t * thread);
- static void prvResumeThread( Thread_t * xThreadId );
- static void vPortSystemTickHandler( int sig );
- static void vPortStartFirstTask( void );
- /*-----------------------------------------------------------*/
- static void prvFatalError( const char *pcCall, int iErrno )
- {
- fprintf( stderr, "%s: %s\n", pcCall, strerror( iErrno ) );
- abort();
- }
- /*
- * See header file for description.
- */
- StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack,
- StackType_t *pxEndOfStack,
- TaskFunction_t pxCode,
- void *pvParameters )
- {
- Thread_t *thread;
- pthread_attr_t xThreadAttributes;
- size_t ulStackSize;
- int iRet;
- (void)pthread_once( &hSigSetupThread, prvSetupSignalsAndSchedulerPolicy );
- /*
- * Store the additional thread data at the start of the stack.
- */
- thread = (Thread_t *)(pxTopOfStack + 1) - 1;
- pxTopOfStack = (StackType_t *)thread - 1;
- ulStackSize = (pxTopOfStack + 1 - pxEndOfStack) * sizeof(*pxTopOfStack);
- thread->pxCode = pxCode;
- thread->pvParams = pvParameters;
- thread->xDying = pdFALSE;
- pthread_attr_init( &xThreadAttributes );
- pthread_attr_setstack( &xThreadAttributes, pxEndOfStack, ulStackSize );
- thread->ev = event_create();
- BaseType_t prev_intr_level = xPortSetInterruptMask();
- iRet = pthread_create( &thread->pthread, &xThreadAttributes,
- prvWaitForStart, thread );
- if ( iRet )
- {
- prvFatalError( "pthread_create", iRet );
- }
- vPortClearInterruptMask( prev_intr_level );
- return pxTopOfStack;
- }
- /*-----------------------------------------------------------*/
- void vPortStartFirstTask( void )
- {
- Thread_t *pxFirstThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
- /* Start the first task. */
- prvResumeThread( pxFirstThread );
- }
- /*-----------------------------------------------------------*/
- /*
- * See header file for description.
- */
- BaseType_t xPortStartScheduler( void )
- {
- int iSignal;
- sigset_t xSignals;
- hMainThread = pthread_self();
- /* Start the timer that generates the tick ISR(SIGALRM).
- Interrupts are disabled here already. */
- prvSetupTimerInterrupt();
- /* Start the first task. */
- vPortStartFirstTask();
- /* Wait until signaled by vPortEndScheduler(). */
- sigemptyset( &xSignals );
- sigaddset( &xSignals, SIG_RESUME );
- while ( !xSchedulerEnd )
- {
- sigwait( &xSignals, &iSignal );
- }
- /* Cancel the Idle task and free its resources */
- #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
- vPortCancelThread( xTaskGetIdleTaskHandle() );
- #endif
- #if ( configUSE_TIMERS == 1 )
- /* Cancel the Timer task and free its resources */
- vPortCancelThread( xTimerGetTimerDaemonTaskHandle() );
- #endif /* configUSE_TIMERS */
- /* Restore original signal mask. */
- (void)pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask, NULL );
- return 0;
- }
- /*-----------------------------------------------------------*/
- void vPortEndScheduler( void )
- {
- struct itimerval itimer;
- struct sigaction sigtick;
- Thread_t *xCurrentThread;
- /* Stop the timer and ignore any pending SIGALRMs that would end
- * up running on the main thread when it is resumed. */
- itimer.it_value.tv_sec = 0;
- itimer.it_value.tv_usec = 0;
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_usec = 0;
- (void)setitimer( ITIMER_REAL, &itimer, NULL );
- sigtick.sa_flags = 0;
- sigtick.sa_handler = SIG_IGN;
- sigemptyset( &sigtick.sa_mask );
- sigaction( SIGALRM, &sigtick, NULL );
- /* Signal the scheduler to exit its loop. */
- xSchedulerEnd = pdTRUE;
- (void)pthread_kill( hMainThread, SIG_RESUME );
- xCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
- prvSuspendSelf(xCurrentThread);
- }
- /*-----------------------------------------------------------*/
- static void vPortDisableInterrupts( void )
- {
- pthread_sigmask( SIG_BLOCK, &xAllSignals, NULL );
- }
- /*-----------------------------------------------------------*/
- static void vPortEnableInterrupts( void )
- {
- pthread_sigmask( SIG_UNBLOCK, &xAllSignals, NULL );
- }
- /*-----------------------------------------------------------*/
- void vPortEnterCriticalIDF( void )
- {
- if ( uxCriticalNestingIDF == 0 && uxInterruptLevel == 0)
- {
- vPortDisableInterrupts();
- }
- uxCriticalNestingIDF++;
- }
- /*-----------------------------------------------------------*/
- void vPortExitCriticalIDF( void )
- {
- uxCriticalNestingIDF--;
- /* If we have reached 0 then re-enable the interrupts. */
- if( uxCriticalNestingIDF == 0 && uxInterruptLevel == 0)
- {
- vPortEnableInterrupts();
- }
- }
- /*-----------------------------------------------------------*/
- void vPortYieldFromISR( void )
- {
- Thread_t *xThreadToSuspend;
- Thread_t *xThreadToResume;
- xThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
- vTaskSwitchContext(xPortGetCoreID());
- xThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
- prvSwitchThread( xThreadToResume, xThreadToSuspend );
- }
- /*-----------------------------------------------------------*/
- void vPortYield( void )
- {
- BaseType_t prev_intr_level = xPortSetInterruptMask();
- vPortYieldFromISR();
- vPortClearInterruptMask( prev_intr_level );
- }
- /*-----------------------------------------------------------*/
- /* In SMP code, the disable/enable interrupt macros are calling the set/get interrupt mask functions below.
- Hence, we need to call vPortDisableInterrupts() and vPortEnableInterrupts(), otherwise interrupts
- are never disabled/enabled. */
- BaseType_t xPortSetInterruptMask( void )
- {
- if (uxInterruptLevel == 0 && uxCriticalNestingIDF == 0) {
- vPortDisableInterrupts();
- }
- BaseType_t prev_intr_level = uxInterruptLevel;
- uxInterruptLevel++;
- return prev_intr_level;
- }
- /*-----------------------------------------------------------*/
- void vPortClearInterruptMask( BaseType_t xMask )
- {
- // Only reenable interrupts if xMask is 0
- uxInterruptLevel = xMask;
- if (uxInterruptLevel == 0 && uxCriticalNestingIDF == 0) {
- vPortEnableInterrupts();
- }
- }
- /*-----------------------------------------------------------*/
- static uint64_t prvGetTimeNs(void)
- {
- struct timespec t;
- clock_gettime(CLOCK_MONOTONIC, &t);
- return t.tv_sec * 1000000000ull + t.tv_nsec;
- }
- static uint64_t prvStartTimeNs;
- /* commented as part of the code below in vPortSystemTickHandler,
- * to adjust timing according to full demo requirements */
- /* static uint64_t prvTickCount; */
- /*
- * Setup the systick timer to generate the tick interrupts at the required
- * frequency.
- */
- void prvSetupTimerInterrupt( void )
- {
- struct itimerval itimer;
- int iRet;
- /* Initialise the structure with the current timer information. */
- iRet = getitimer( ITIMER_REAL, &itimer );
- if ( iRet )
- {
- prvFatalError( "getitimer", errno );
- }
- /* Set the interval between timer events. */
- itimer.it_interval.tv_sec = 0;
- itimer.it_interval.tv_usec = portTICK_RATE_MICROSECONDS;
- /* Set the current count-down. */
- itimer.it_value.tv_sec = 0;
- itimer.it_value.tv_usec = portTICK_RATE_MICROSECONDS;
- /* Set-up the timer interrupt. */
- iRet = setitimer( ITIMER_REAL, &itimer, NULL );
- if ( iRet )
- {
- prvFatalError( "setitimer", errno );
- }
- prvStartTimeNs = prvGetTimeNs();
- }
- /*-----------------------------------------------------------*/
- static void vPortSystemTickHandler( int sig )
- {
- Thread_t *pxThreadToSuspend;
- Thread_t *pxThreadToResume;
- BaseType_t xSwitchRequired;
- /* uint64_t xExpectedTicks; */
- // Handling a timer signal, so we are currently in an interrupt.
- uxInterruptNesting++;
- #if ( configUSE_PREEMPTION == 1 )
- pxThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
- #endif
- /* Tick Increment, accounting for any lost signals or drift in
- * the timer. */
- /*
- * Comment code to adjust timing according to full demo requirements
- * xExpectedTicks = (prvGetTimeNs() - prvStartTimeNs)
- * / (portTICK_RATE_MICROSECONDS * 1000);
- * do { */
- xSwitchRequired = xTaskIncrementTick();
- /* prvTickCount++;
- * } while (prvTickCount < xExpectedTicks);
- */
- #if ( configUSE_PREEMPTION == 1 )
- if (xSwitchRequired == pdTRUE) {
- /* Select Next Task. */
- vTaskSwitchContext(xPortGetCoreID());
- pxThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
- prvSwitchThread(pxThreadToResume, pxThreadToSuspend);
- }
- #else
- (void)xSwitchRequired;
- #endif
- // Returning from the timer signal handler, so we are exiting the interrupt.
- uxInterruptNesting--;
- }
- /*-----------------------------------------------------------*/
- void vPortThreadDying( void *pxTaskToDelete, volatile BaseType_t *pxPendYield )
- {
- Thread_t *pxThread = prvGetThreadFromTask( pxTaskToDelete );
- pxThread->xDying = pdTRUE;
- }
- void vPortCancelThread( void *pxTaskToDelete )
- {
- Thread_t *pxThreadToCancel = prvGetThreadFromTask( pxTaskToDelete );
- /*
- * The thread has already been suspended so it can be safely cancelled.
- */
- pthread_cancel( pxThreadToCancel->pthread );
- pthread_join( pxThreadToCancel->pthread, NULL );
- event_delete( pxThreadToCancel->ev );
- }
- /*-----------------------------------------------------------*/
- static void *prvWaitForStart( void * pvParams )
- {
- Thread_t *pxThread = pvParams;
- prvSuspendSelf(pxThread);
- /* Resumed for the first time, thus this thread didn't previously call
- * prvSwitchThread(). So we need to initialise the state variables for this
- * thread. */
- uxCriticalNestingIDF = 0;
- uxInterruptNesting = 0;
- uxInterruptLevel = 0;
- vPortEnableInterrupts();
- /* Call the task's entry point. */
- pxThread->pxCode( pxThread->pvParams );
- /* A function that implements a task must not exit or attempt to return to
- * its caller as there is nothing to return to. If a task wants to exit it
- * should instead call vTaskDelete( NULL ). Artificially force an assert()
- * to be triggered if configASSERT() is defined, so application writers can
- * catch the error. */
- configASSERT( pdFALSE );
- return NULL;
- }
- /*-----------------------------------------------------------*/
- static void prvSwitchThread( Thread_t *pxThreadToResume,
- Thread_t *pxThreadToSuspend )
- {
- BaseType_t uxSavedCriticalNestingIDF;
- BaseType_t uxSavedInterruptNesting;
- BaseType_t uxSavedInterruptLevel;
- if ( pxThreadToSuspend != pxThreadToResume )
- {
- /* It is possible for prvSwitchThread() to be called...
- * - while inside an ISR (i.e., via vPortSystemTickHandler() or vPortYieldFromISR())
- * - while interrupts are disabled or in a critical section (i.e., via vPortYield())
- *
- * So we need to save the various count variables as part of the thread's context.
- * They are restored when the pthread switches back. */
- uxSavedCriticalNestingIDF = uxCriticalNestingIDF;
- uxSavedInterruptNesting = uxInterruptNesting;
- uxSavedInterruptLevel = uxInterruptLevel;
- prvResumeThread( pxThreadToResume );
- if ( pxThreadToSuspend->xDying )
- {
- pthread_exit( NULL );
- }
- prvSuspendSelf( pxThreadToSuspend );
- uxCriticalNestingIDF = uxSavedCriticalNestingIDF;
- uxInterruptNesting = uxSavedInterruptNesting;
- uxInterruptLevel = uxSavedInterruptLevel;
- }
- }
- /*-----------------------------------------------------------*/
- static void prvSuspendSelf( Thread_t *thread )
- {
- /*
- * Suspend this thread by waiting for a pthread_cond_signal event.
- *
- * A suspended thread must not handle signals (interrupts) so
- * all signals must be blocked by calling this from:
- *
- * - Inside a critical section (vPortEnterCritical() /
- * vPortExitCritical()).
- *
- * - From a signal handler that has all signals masked.
- *
- * - A thread with all signals blocked with pthread_sigmask().
- */
- event_wait(thread->ev);
- }
- /*-----------------------------------------------------------*/
- static void prvResumeThread( Thread_t *xThreadId )
- {
- if ( pthread_self() != xThreadId->pthread )
- {
- event_signal(xThreadId->ev);
- }
- }
- /*-----------------------------------------------------------*/
- static void prvSetupSignalsAndSchedulerPolicy( void )
- {
- struct sigaction sigresume, sigtick;
- int iRet;
- hMainThread = pthread_self();
- /* Initialise common signal masks. */
- sigfillset( &xAllSignals );
- /* Don't block SIGINT so this can be used to break into GDB while
- * in a critical section. */
- sigdelset( &xAllSignals, SIGINT );
- /*
- * Block all signals in this thread so all new threads
- * inherits this mask.
- *
- * When a thread is resumed for the first time, all signals
- * will be unblocked.
- */
- (void)pthread_sigmask( SIG_SETMASK, &xAllSignals,
- &xSchedulerOriginalSignalMask );
- /* SIG_RESUME is only used with sigwait() so doesn't need a
- handler. */
- sigresume.sa_flags = 0;
- sigresume.sa_handler = SIG_IGN;
- sigfillset( &sigresume.sa_mask );
- sigtick.sa_flags = 0;
- sigtick.sa_handler = vPortSystemTickHandler;
- sigfillset( &sigtick.sa_mask );
- iRet = sigaction( SIG_RESUME, &sigresume, NULL );
- if ( iRet )
- {
- prvFatalError( "sigaction", errno );
- }
- iRet = sigaction( SIGALRM, &sigtick, NULL );
- if ( iRet )
- {
- prvFatalError( "sigaction", errno );
- }
- }
- /*-----------------------------------------------------------*/
- unsigned long ulPortGetRunTime( void )
- {
- struct tms xTimes;
- times( &xTimes );
- return ( unsigned long ) xTimes.tms_utime;
- }
- /*-----------------------------------------------------------*/
- bool portVALID_TCB_MEM(const void *ptr)
- {
- return true;
- }
- bool portVALID_STACK_MEM(const void *ptr)
- {
- return true;
- }
- /*-----------------------------------------------------------*/
- portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED;
- portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED;
- static const char *TAG = "port";
- /* When configSUPPORT_STATIC_ALLOCATION is set to 1 the application writer can
- * use a callback function to optionally provide the memory required by the idle
- * and timer tasks. This is the stack that will be used by the timer task. It is
- * declared here, as a global, so it can be checked by a test that is implemented
- * in a different file. */
- StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
- BaseType_t xPortCheckIfInISR(void)
- {
- return (uxInterruptNesting == 0) ? pdFALSE : pdTRUE;
- }
- void app_main(void);
- static void main_task(void* args)
- {
- app_main();
- vTaskDelete(NULL);
- }
- int main(int argc, const char **argv)
- {
- // This makes sure that stdio is flushed after each '\n' so that idf.py monitor
- // reads the program output on time.
- setvbuf(stdout, NULL, _IOLBF, 0);
- usleep(1000);
- BaseType_t res;
- #if ( configNUM_CORES > 1 )
- res = xTaskCreateAffinitySet(&main_task, "main",
- ESP_TASK_MAIN_STACK, NULL,
- ESP_TASK_MAIN_PRIO, ESP_TASK_MAIN_CORE, NULL);
- #else
- res = xTaskCreate(&main_task, "main",
- ESP_TASK_MAIN_STACK, NULL,
- ESP_TASK_MAIN_PRIO, NULL);
- #endif
- assert(res == pdTRUE);
- (void)res;
- ESP_LOGI(TAG, "Starting SMP scheduler.");
- vTaskStartScheduler();
- // This line should never be reached
- assert(false);
- }
- void esp_vApplicationIdleHook(void)
- {
- /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
- * to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
- * task. It is essential that code added to this hook function never attempts
- * to block in any way (for example, call xQueueReceive() with a block time
- * specified, or call vTaskDelay()). If application tasks make use of the
- * vTaskDelete() API function to delete themselves then it is also important
- * that vApplicationIdleHook() is permitted to return to its calling function,
- * because it is the responsibility of the idle task to clean up memory
- * allocated by the kernel to any task that has since deleted itself. */
- usleep( 15000 );
- }
- void esp_vApplicationTickHook( void ) { }
- #if ( configUSE_TICK_HOOK > 0 )
- void vApplicationTickHook( void )
- {
- esp_vApplicationTickHook();
- }
- #endif
- #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
- /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
- * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
- * used by the Idle task. */
- void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
- StackType_t ** ppxIdleTaskStackBuffer,
- uint32_t * pulIdleTaskStackSize )
- {
- /* If the buffers to be provided to the Idle task are declared inside this
- * function then they must be declared static - otherwise they will be allocated on
- * the stack and so not exists after this function exits. */
- static StaticTask_t xIdleTaskTCB;
- static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
- /* Pass out a pointer to the StaticTask_t structure in which the Idle task's
- * state will be stored. */
- *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
- /* Pass out the array that will be used as the Idle task's stack. */
- *ppxIdleTaskStackBuffer = uxIdleTaskStack;
- /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
- * Note that, as the array is necessarily of type StackType_t,
- * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
- *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
- }
- #endif // configSUPPORT_STATIC_ALLOCATION == 1
- /*-----------------------------------------------------------*/
- #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
- /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
- * application must provide an implementation of vApplicationGetTimerTaskMemory()
- * to provide the memory that is used by the Timer service task. */
- void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
- StackType_t ** ppxTimerTaskStackBuffer,
- uint32_t * pulTimerTaskStackSize )
- {
- /* If the buffers to be provided to the Timer task are declared inside this
- * function then they must be declared static - otherwise they will be allocated on
- * the stack and so not exists after this function exits. */
- static StaticTask_t xTimerTaskTCB;
- /* Pass out a pointer to the StaticTask_t structure in which the Timer
- * task's state will be stored. */
- *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
- /* Pass out the array that will be used as the Timer task's stack. */
- *ppxTimerTaskStackBuffer = uxTimerTaskStack;
- /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
- * Note that, as the array is necessarily of type StackType_t,
- * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
- *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
- }
- #endif // configSUPPORT_STATIC_ALLOCATION == 1
- void vPortTakeLock( portMUX_TYPE *lock )
- {
- spinlock_acquire( lock, portMUX_NO_TIMEOUT);
- }
- void vPortReleaseLock( portMUX_TYPE *lock )
- {
- spinlock_release( lock );
- }
- #define FREERTOS_SMP_MALLOC_CAPS (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
- void *pvPortMalloc( size_t xSize )
- {
- return heap_caps_malloc(xSize, FREERTOS_SMP_MALLOC_CAPS);
- }
- void vPortFree( void *pv )
- {
- heap_caps_free(pv);
- }
- void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
- {
- #define ERR_STR1 "***ERROR*** A stack overflow in task "
- #define ERR_STR2 " has been detected."
- const char *str[] = {ERR_STR1, pcTaskName, ERR_STR2};
- char buf[sizeof(ERR_STR1) + CONFIG_FREERTOS_MAX_TASK_NAME_LEN + sizeof(ERR_STR2) + 1 /* null char */] = {0};
- char *dest = buf;
- for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
- dest = strcat(dest, str[i]);
- }
- printf("%s\n", buf);
- abort();
- }
- // ------- Thread Local Storage Pointers Deletion Callbacks -------
- #if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
- void vPortTLSPointersDelCb( void *pxTCB )
- {
- /* Typecast pxTCB to StaticTask_t type to access TCB struct members.
- * pvDummy15 corresponds to pvThreadLocalStoragePointers member of the TCB.
- */
- StaticTask_t *tcb = ( StaticTask_t * )pxTCB;
- /* The TLSP deletion callbacks are stored at an offset of (configNUM_THREAD_LOCAL_STORAGE_POINTERS/2) */
- TlsDeleteCallbackFunction_t *pvThreadLocalStoragePointersDelCallback = ( TlsDeleteCallbackFunction_t * )( &( tcb->pvDummy15[ ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ] ) );
- /* We need to iterate over half the depth of the pvThreadLocalStoragePointers area
- * to access all TLS pointers and their respective TLS deletion callbacks.
- */
- for ( int x = 0; x < ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ); x++ ) {
- if ( pvThreadLocalStoragePointersDelCallback[ x ] != NULL ) { //If del cb is set
- // We skip the check if the callback is executable as that is difficult to determine for different
- // platforms (compare xtensa and riscv code).
- pvThreadLocalStoragePointersDelCallback[ x ]( x, tcb->pvDummy15[ x ] ); //Call del cb
- }
- }
- }
- #endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS
- void vPortCleanUpTCB ( void *pxTCB )
- {
- #if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
- /* Call TLS pointers deletion callbacks */
- vPortTLSPointersDelCb( pxTCB );
- #endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */
- vPortCancelThread(pxTCB);
- }
|