port.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. /*
  2. * SPDX-FileCopyrightText: 2020 Amazon.com, Inc. or its affiliates
  3. *
  4. * SPDX-License-Identifier: MIT
  5. */
  6. /*
  7. * FreeRTOS Kernel V10.4.3
  8. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  9. *
  10. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  11. * this software and associated documentation files (the "Software"), to deal in
  12. * the Software without restriction, including without limitation the rights to
  13. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  14. * the Software, and to permit persons to whom the Software is furnished to do so,
  15. * subject to the following conditions:
  16. *
  17. * The above copyright notice and this permission notice shall be included in all
  18. * copies or substantial portions of the Software.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  22. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  23. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  24. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  25. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26. *
  27. * https://www.FreeRTOS.org
  28. * https://github.com/FreeRTOS
  29. *
  30. */
  31. /*-----------------------------------------------------------
  32. * Implementation of functions defined in portable.h for the Posix port.
  33. *
  34. * Each task has a pthread which eases use of standard debuggers
  35. * (allowing backtraces of tasks etc). Threads for tasks that are not
  36. * running are blocked in sigwait().
  37. *
  38. * Task switch is done by resuming the thread for the next task by
  39. * signaling the condition variable and then waiting on a condition variable
  40. * with the current thread.
  41. *
  42. * The timer interrupt uses SIGALRM and care is taken to ensure that
  43. * the signal handler runs only on the thread for the current task.
  44. *
  45. * Use of part of the standard C library requires care as some
  46. * functions can take pthread mutexes internally which can result in
  47. * deadlocks as the FreeRTOS kernel can switch tasks while they're
  48. * holding a pthread mutex.
  49. *
  50. * stdio (printf() and friends) should be called from a single task
  51. * only or serialized with a FreeRTOS primitive such as a binary
  52. * semaphore or mutex.
  53. *----------------------------------------------------------*/
  54. #include <errno.h>
  55. #include <pthread.h>
  56. #include <signal.h>
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include <sys/time.h>
  61. #include <sys/times.h>
  62. #include <time.h>
  63. #include <unistd.h>
  64. #include <assert.h>
  65. /* Scheduler includes. */
  66. #include "esp_heap_caps.h"
  67. #include "FreeRTOS.h"
  68. #include "task.h"
  69. #include "esp_task.h"
  70. #include "timers.h"
  71. #include "utils/wait_for_event.h"
  72. #include "esp_log.h"
  73. /*-----------------------------------------------------------*/
  74. #define SIG_RESUME SIGUSR1
  75. typedef struct THREAD
  76. {
  77. pthread_t pthread;
  78. TaskFunction_t pxCode;
  79. void *pvParams;
  80. BaseType_t xDying;
  81. struct event *ev;
  82. } Thread_t;
  83. /*
  84. * The additional per-thread data is stored at the beginning of the
  85. * task's stack.
  86. */
  87. static inline Thread_t *prvGetThreadFromTask(TaskHandle_t xTask)
  88. {
  89. StackType_t *pxTopOfStack = *(StackType_t **)xTask;
  90. return (Thread_t *)(pxTopOfStack + 1);
  91. }
  92. /*-----------------------------------------------------------*/
  93. static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT;
  94. static sigset_t xAllSignals;
  95. static sigset_t xSchedulerOriginalSignalMask;
  96. static pthread_t hMainThread = ( pthread_t )NULL;
  97. // These are saved as part of a thread's state in prvSwitchThread()
  98. static volatile BaseType_t uxCriticalNestingIDF = 0; /* Track nesting calls for IDF style critical sections. FreeRTOS critical section nesting is maintained in the TCB. */
  99. static volatile UBaseType_t uxInterruptNesting = 0; /* Tracks if we are currently in an interrupt. */
  100. static volatile BaseType_t uxInterruptLevel = 0; /* Tracks the current level (i.e., interrupt mask) */
  101. /*-----------------------------------------------------------*/
  102. static BaseType_t xSchedulerEnd = pdFALSE;
  103. /*-----------------------------------------------------------*/
  104. static void prvSetupSignalsAndSchedulerPolicy( void );
  105. static void prvSetupTimerInterrupt( void );
  106. static void *prvWaitForStart( void * pvParams );
  107. static void prvSwitchThread( Thread_t * xThreadToResume,
  108. Thread_t *xThreadToSuspend );
  109. static void prvSuspendSelf( Thread_t * thread);
  110. static void prvResumeThread( Thread_t * xThreadId );
  111. static void vPortSystemTickHandler( int sig );
  112. static void vPortStartFirstTask( void );
  113. /*-----------------------------------------------------------*/
  114. static void prvFatalError( const char *pcCall, int iErrno )
  115. {
  116. fprintf( stderr, "%s: %s\n", pcCall, strerror( iErrno ) );
  117. abort();
  118. }
  119. /*
  120. * See header file for description.
  121. */
  122. StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack,
  123. StackType_t *pxEndOfStack,
  124. TaskFunction_t pxCode,
  125. void *pvParameters )
  126. {
  127. Thread_t *thread;
  128. pthread_attr_t xThreadAttributes;
  129. size_t ulStackSize;
  130. int iRet;
  131. (void)pthread_once( &hSigSetupThread, prvSetupSignalsAndSchedulerPolicy );
  132. /*
  133. * Store the additional thread data at the start of the stack.
  134. */
  135. thread = (Thread_t *)(pxTopOfStack + 1) - 1;
  136. pxTopOfStack = (StackType_t *)thread - 1;
  137. ulStackSize = (pxTopOfStack + 1 - pxEndOfStack) * sizeof(*pxTopOfStack);
  138. thread->pxCode = pxCode;
  139. thread->pvParams = pvParameters;
  140. thread->xDying = pdFALSE;
  141. pthread_attr_init( &xThreadAttributes );
  142. pthread_attr_setstack( &xThreadAttributes, pxEndOfStack, ulStackSize );
  143. thread->ev = event_create();
  144. BaseType_t prev_intr_level = xPortSetInterruptMask();
  145. iRet = pthread_create( &thread->pthread, &xThreadAttributes,
  146. prvWaitForStart, thread );
  147. if ( iRet )
  148. {
  149. prvFatalError( "pthread_create", iRet );
  150. }
  151. vPortClearInterruptMask( prev_intr_level );
  152. return pxTopOfStack;
  153. }
  154. /*-----------------------------------------------------------*/
  155. void vPortStartFirstTask( void )
  156. {
  157. Thread_t *pxFirstThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  158. /* Start the first task. */
  159. prvResumeThread( pxFirstThread );
  160. }
  161. /*-----------------------------------------------------------*/
  162. /*
  163. * See header file for description.
  164. */
  165. BaseType_t xPortStartScheduler( void )
  166. {
  167. int iSignal;
  168. sigset_t xSignals;
  169. hMainThread = pthread_self();
  170. /* Start the timer that generates the tick ISR(SIGALRM).
  171. Interrupts are disabled here already. */
  172. prvSetupTimerInterrupt();
  173. /* Start the first task. */
  174. vPortStartFirstTask();
  175. /* Wait until signaled by vPortEndScheduler(). */
  176. sigemptyset( &xSignals );
  177. sigaddset( &xSignals, SIG_RESUME );
  178. while ( !xSchedulerEnd )
  179. {
  180. sigwait( &xSignals, &iSignal );
  181. }
  182. /* Cancel the Idle task and free its resources */
  183. #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
  184. vPortCancelThread( xTaskGetIdleTaskHandle() );
  185. #endif
  186. #if ( configUSE_TIMERS == 1 )
  187. /* Cancel the Timer task and free its resources */
  188. vPortCancelThread( xTimerGetTimerDaemonTaskHandle() );
  189. #endif /* configUSE_TIMERS */
  190. /* Restore original signal mask. */
  191. (void)pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask, NULL );
  192. return 0;
  193. }
  194. /*-----------------------------------------------------------*/
  195. void vPortEndScheduler( void )
  196. {
  197. struct itimerval itimer;
  198. struct sigaction sigtick;
  199. Thread_t *xCurrentThread;
  200. /* Stop the timer and ignore any pending SIGALRMs that would end
  201. * up running on the main thread when it is resumed. */
  202. itimer.it_value.tv_sec = 0;
  203. itimer.it_value.tv_usec = 0;
  204. itimer.it_interval.tv_sec = 0;
  205. itimer.it_interval.tv_usec = 0;
  206. (void)setitimer( ITIMER_REAL, &itimer, NULL );
  207. sigtick.sa_flags = 0;
  208. sigtick.sa_handler = SIG_IGN;
  209. sigemptyset( &sigtick.sa_mask );
  210. sigaction( SIGALRM, &sigtick, NULL );
  211. /* Signal the scheduler to exit its loop. */
  212. xSchedulerEnd = pdTRUE;
  213. (void)pthread_kill( hMainThread, SIG_RESUME );
  214. xCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  215. prvSuspendSelf(xCurrentThread);
  216. }
  217. /*-----------------------------------------------------------*/
  218. static void vPortDisableInterrupts( void )
  219. {
  220. pthread_sigmask( SIG_BLOCK, &xAllSignals, NULL );
  221. }
  222. /*-----------------------------------------------------------*/
  223. static void vPortEnableInterrupts( void )
  224. {
  225. pthread_sigmask( SIG_UNBLOCK, &xAllSignals, NULL );
  226. }
  227. /*-----------------------------------------------------------*/
  228. void vPortEnterCriticalIDF( void )
  229. {
  230. if ( uxCriticalNestingIDF == 0 && uxInterruptLevel == 0)
  231. {
  232. vPortDisableInterrupts();
  233. }
  234. uxCriticalNestingIDF++;
  235. }
  236. /*-----------------------------------------------------------*/
  237. void vPortExitCriticalIDF( void )
  238. {
  239. uxCriticalNestingIDF--;
  240. /* If we have reached 0 then re-enable the interrupts. */
  241. if( uxCriticalNestingIDF == 0 && uxInterruptLevel == 0)
  242. {
  243. vPortEnableInterrupts();
  244. }
  245. }
  246. /*-----------------------------------------------------------*/
  247. void vPortYieldFromISR( void )
  248. {
  249. Thread_t *xThreadToSuspend;
  250. Thread_t *xThreadToResume;
  251. xThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  252. vTaskSwitchContext(xPortGetCoreID());
  253. xThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  254. prvSwitchThread( xThreadToResume, xThreadToSuspend );
  255. }
  256. /*-----------------------------------------------------------*/
  257. void vPortYield( void )
  258. {
  259. BaseType_t prev_intr_level = xPortSetInterruptMask();
  260. vPortYieldFromISR();
  261. vPortClearInterruptMask( prev_intr_level );
  262. }
  263. /*-----------------------------------------------------------*/
  264. /* In SMP code, the disable/enable interrupt macros are calling the set/get interrupt mask functions below.
  265. Hence, we need to call vPortDisableInterrupts() and vPortEnableInterrupts(), otherwise interrupts
  266. are never disabled/enabled. */
  267. BaseType_t xPortSetInterruptMask( void )
  268. {
  269. if (uxInterruptLevel == 0 && uxCriticalNestingIDF == 0) {
  270. vPortDisableInterrupts();
  271. }
  272. BaseType_t prev_intr_level = uxInterruptLevel;
  273. uxInterruptLevel++;
  274. return prev_intr_level;
  275. }
  276. /*-----------------------------------------------------------*/
  277. void vPortClearInterruptMask( BaseType_t xMask )
  278. {
  279. // Only reenable interrupts if xMask is 0
  280. uxInterruptLevel = xMask;
  281. if (uxInterruptLevel == 0 && uxCriticalNestingIDF == 0) {
  282. vPortEnableInterrupts();
  283. }
  284. }
  285. /*-----------------------------------------------------------*/
  286. static uint64_t prvGetTimeNs(void)
  287. {
  288. struct timespec t;
  289. clock_gettime(CLOCK_MONOTONIC, &t);
  290. return t.tv_sec * 1000000000ull + t.tv_nsec;
  291. }
  292. static uint64_t prvStartTimeNs;
  293. /* commented as part of the code below in vPortSystemTickHandler,
  294. * to adjust timing according to full demo requirements */
  295. /* static uint64_t prvTickCount; */
  296. /*
  297. * Setup the systick timer to generate the tick interrupts at the required
  298. * frequency.
  299. */
  300. void prvSetupTimerInterrupt( void )
  301. {
  302. struct itimerval itimer;
  303. int iRet;
  304. /* Initialise the structure with the current timer information. */
  305. iRet = getitimer( ITIMER_REAL, &itimer );
  306. if ( iRet )
  307. {
  308. prvFatalError( "getitimer", errno );
  309. }
  310. /* Set the interval between timer events. */
  311. itimer.it_interval.tv_sec = 0;
  312. itimer.it_interval.tv_usec = portTICK_RATE_MICROSECONDS;
  313. /* Set the current count-down. */
  314. itimer.it_value.tv_sec = 0;
  315. itimer.it_value.tv_usec = portTICK_RATE_MICROSECONDS;
  316. /* Set-up the timer interrupt. */
  317. iRet = setitimer( ITIMER_REAL, &itimer, NULL );
  318. if ( iRet )
  319. {
  320. prvFatalError( "setitimer", errno );
  321. }
  322. prvStartTimeNs = prvGetTimeNs();
  323. }
  324. /*-----------------------------------------------------------*/
  325. static void vPortSystemTickHandler( int sig )
  326. {
  327. Thread_t *pxThreadToSuspend;
  328. Thread_t *pxThreadToResume;
  329. BaseType_t xSwitchRequired;
  330. /* uint64_t xExpectedTicks; */
  331. // Handling a timer signal, so we are currently in an interrupt.
  332. uxInterruptNesting++;
  333. #if ( configUSE_PREEMPTION == 1 )
  334. pxThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  335. #endif
  336. /* Tick Increment, accounting for any lost signals or drift in
  337. * the timer. */
  338. /*
  339. * Comment code to adjust timing according to full demo requirements
  340. * xExpectedTicks = (prvGetTimeNs() - prvStartTimeNs)
  341. * / (portTICK_RATE_MICROSECONDS * 1000);
  342. * do { */
  343. xSwitchRequired = xTaskIncrementTick();
  344. /* prvTickCount++;
  345. * } while (prvTickCount < xExpectedTicks);
  346. */
  347. #if ( configUSE_PREEMPTION == 1 )
  348. if (xSwitchRequired == pdTRUE) {
  349. /* Select Next Task. */
  350. vTaskSwitchContext(xPortGetCoreID());
  351. pxThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  352. prvSwitchThread(pxThreadToResume, pxThreadToSuspend);
  353. }
  354. #else
  355. (void)xSwitchRequired;
  356. #endif
  357. // Returning from the timer signal handler, so we are exiting the interrupt.
  358. uxInterruptNesting--;
  359. }
  360. /*-----------------------------------------------------------*/
  361. void vPortThreadDying( void *pxTaskToDelete, volatile BaseType_t *pxPendYield )
  362. {
  363. Thread_t *pxThread = prvGetThreadFromTask( pxTaskToDelete );
  364. pxThread->xDying = pdTRUE;
  365. }
  366. void vPortCancelThread( void *pxTaskToDelete )
  367. {
  368. Thread_t *pxThreadToCancel = prvGetThreadFromTask( pxTaskToDelete );
  369. /*
  370. * The thread has already been suspended so it can be safely cancelled.
  371. */
  372. pthread_cancel( pxThreadToCancel->pthread );
  373. pthread_join( pxThreadToCancel->pthread, NULL );
  374. event_delete( pxThreadToCancel->ev );
  375. }
  376. /*-----------------------------------------------------------*/
  377. static void *prvWaitForStart( void * pvParams )
  378. {
  379. Thread_t *pxThread = pvParams;
  380. prvSuspendSelf(pxThread);
  381. /* Resumed for the first time, thus this thread didn't previously call
  382. * prvSwitchThread(). So we need to initialise the state variables for this
  383. * thread. */
  384. uxCriticalNestingIDF = 0;
  385. uxInterruptNesting = 0;
  386. uxInterruptLevel = 0;
  387. vPortEnableInterrupts();
  388. /* Call the task's entry point. */
  389. pxThread->pxCode( pxThread->pvParams );
  390. /* A function that implements a task must not exit or attempt to return to
  391. * its caller as there is nothing to return to. If a task wants to exit it
  392. * should instead call vTaskDelete( NULL ). Artificially force an assert()
  393. * to be triggered if configASSERT() is defined, so application writers can
  394. * catch the error. */
  395. configASSERT( pdFALSE );
  396. return NULL;
  397. }
  398. /*-----------------------------------------------------------*/
  399. static void prvSwitchThread( Thread_t *pxThreadToResume,
  400. Thread_t *pxThreadToSuspend )
  401. {
  402. BaseType_t uxSavedCriticalNestingIDF;
  403. BaseType_t uxSavedInterruptNesting;
  404. BaseType_t uxSavedInterruptLevel;
  405. if ( pxThreadToSuspend != pxThreadToResume )
  406. {
  407. /* It is possible for prvSwitchThread() to be called...
  408. * - while inside an ISR (i.e., via vPortSystemTickHandler() or vPortYieldFromISR())
  409. * - while interrupts are disabled or in a critical section (i.e., via vPortYield())
  410. *
  411. * So we need to save the various count variables as part of the thread's context.
  412. * They are restored when the pthread switches back. */
  413. uxSavedCriticalNestingIDF = uxCriticalNestingIDF;
  414. uxSavedInterruptNesting = uxInterruptNesting;
  415. uxSavedInterruptLevel = uxInterruptLevel;
  416. prvResumeThread( pxThreadToResume );
  417. if ( pxThreadToSuspend->xDying )
  418. {
  419. pthread_exit( NULL );
  420. }
  421. prvSuspendSelf( pxThreadToSuspend );
  422. uxCriticalNestingIDF = uxSavedCriticalNestingIDF;
  423. uxInterruptNesting = uxSavedInterruptNesting;
  424. uxInterruptLevel = uxSavedInterruptLevel;
  425. }
  426. }
  427. /*-----------------------------------------------------------*/
  428. static void prvSuspendSelf( Thread_t *thread )
  429. {
  430. /*
  431. * Suspend this thread by waiting for a pthread_cond_signal event.
  432. *
  433. * A suspended thread must not handle signals (interrupts) so
  434. * all signals must be blocked by calling this from:
  435. *
  436. * - Inside a critical section (vPortEnterCritical() /
  437. * vPortExitCritical()).
  438. *
  439. * - From a signal handler that has all signals masked.
  440. *
  441. * - A thread with all signals blocked with pthread_sigmask().
  442. */
  443. event_wait(thread->ev);
  444. }
  445. /*-----------------------------------------------------------*/
  446. static void prvResumeThread( Thread_t *xThreadId )
  447. {
  448. if ( pthread_self() != xThreadId->pthread )
  449. {
  450. event_signal(xThreadId->ev);
  451. }
  452. }
  453. /*-----------------------------------------------------------*/
  454. static void prvSetupSignalsAndSchedulerPolicy( void )
  455. {
  456. struct sigaction sigresume, sigtick;
  457. int iRet;
  458. hMainThread = pthread_self();
  459. /* Initialise common signal masks. */
  460. sigfillset( &xAllSignals );
  461. /* Don't block SIGINT so this can be used to break into GDB while
  462. * in a critical section. */
  463. sigdelset( &xAllSignals, SIGINT );
  464. /*
  465. * Block all signals in this thread so all new threads
  466. * inherits this mask.
  467. *
  468. * When a thread is resumed for the first time, all signals
  469. * will be unblocked.
  470. */
  471. (void)pthread_sigmask( SIG_SETMASK, &xAllSignals,
  472. &xSchedulerOriginalSignalMask );
  473. /* SIG_RESUME is only used with sigwait() so doesn't need a
  474. handler. */
  475. sigresume.sa_flags = 0;
  476. sigresume.sa_handler = SIG_IGN;
  477. sigfillset( &sigresume.sa_mask );
  478. sigtick.sa_flags = 0;
  479. sigtick.sa_handler = vPortSystemTickHandler;
  480. sigfillset( &sigtick.sa_mask );
  481. iRet = sigaction( SIG_RESUME, &sigresume, NULL );
  482. if ( iRet )
  483. {
  484. prvFatalError( "sigaction", errno );
  485. }
  486. iRet = sigaction( SIGALRM, &sigtick, NULL );
  487. if ( iRet )
  488. {
  489. prvFatalError( "sigaction", errno );
  490. }
  491. }
  492. /*-----------------------------------------------------------*/
  493. unsigned long ulPortGetRunTime( void )
  494. {
  495. struct tms xTimes;
  496. times( &xTimes );
  497. return ( unsigned long ) xTimes.tms_utime;
  498. }
  499. /*-----------------------------------------------------------*/
  500. bool portVALID_TCB_MEM(const void *ptr)
  501. {
  502. return true;
  503. }
  504. bool portVALID_STACK_MEM(const void *ptr)
  505. {
  506. return true;
  507. }
  508. /*-----------------------------------------------------------*/
  509. portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED;
  510. portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED;
  511. static const char *TAG = "port";
  512. /* When configSUPPORT_STATIC_ALLOCATION is set to 1 the application writer can
  513. * use a callback function to optionally provide the memory required by the idle
  514. * and timer tasks. This is the stack that will be used by the timer task. It is
  515. * declared here, as a global, so it can be checked by a test that is implemented
  516. * in a different file. */
  517. StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ];
  518. BaseType_t xPortCheckIfInISR(void)
  519. {
  520. return (uxInterruptNesting == 0) ? pdFALSE : pdTRUE;
  521. }
  522. void app_main(void);
  523. static void main_task(void* args)
  524. {
  525. app_main();
  526. vTaskDelete(NULL);
  527. }
  528. int main(int argc, const char **argv)
  529. {
  530. // This makes sure that stdio is flushed after each '\n' so that idf.py monitor
  531. // reads the program output on time.
  532. setvbuf(stdout, NULL, _IOLBF, 0);
  533. usleep(1000);
  534. BaseType_t res;
  535. #if ( configNUM_CORES > 1 )
  536. res = xTaskCreateAffinitySet(&main_task, "main",
  537. ESP_TASK_MAIN_STACK, NULL,
  538. ESP_TASK_MAIN_PRIO, ESP_TASK_MAIN_CORE, NULL);
  539. #else
  540. res = xTaskCreate(&main_task, "main",
  541. ESP_TASK_MAIN_STACK, NULL,
  542. ESP_TASK_MAIN_PRIO, NULL);
  543. #endif
  544. assert(res == pdTRUE);
  545. (void)res;
  546. ESP_LOGI(TAG, "Starting SMP scheduler.");
  547. vTaskStartScheduler();
  548. // This line should never be reached
  549. assert(false);
  550. }
  551. void esp_vApplicationIdleHook(void)
  552. {
  553. /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
  554. * to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle
  555. * task. It is essential that code added to this hook function never attempts
  556. * to block in any way (for example, call xQueueReceive() with a block time
  557. * specified, or call vTaskDelay()). If application tasks make use of the
  558. * vTaskDelete() API function to delete themselves then it is also important
  559. * that vApplicationIdleHook() is permitted to return to its calling function,
  560. * because it is the responsibility of the idle task to clean up memory
  561. * allocated by the kernel to any task that has since deleted itself. */
  562. usleep( 15000 );
  563. }
  564. void esp_vApplicationTickHook( void ) { }
  565. #if ( configUSE_TICK_HOOK > 0 )
  566. void vApplicationTickHook( void )
  567. {
  568. esp_vApplicationTickHook();
  569. }
  570. #endif
  571. #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
  572. /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an
  573. * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is
  574. * used by the Idle task. */
  575. void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
  576. StackType_t ** ppxIdleTaskStackBuffer,
  577. uint32_t * pulIdleTaskStackSize )
  578. {
  579. /* If the buffers to be provided to the Idle task are declared inside this
  580. * function then they must be declared static - otherwise they will be allocated on
  581. * the stack and so not exists after this function exits. */
  582. static StaticTask_t xIdleTaskTCB;
  583. static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ];
  584. /* Pass out a pointer to the StaticTask_t structure in which the Idle task's
  585. * state will be stored. */
  586. *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
  587. /* Pass out the array that will be used as the Idle task's stack. */
  588. *ppxIdleTaskStackBuffer = uxIdleTaskStack;
  589. /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer.
  590. * Note that, as the array is necessarily of type StackType_t,
  591. * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
  592. *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  593. }
  594. #endif // configSUPPORT_STATIC_ALLOCATION == 1
  595. /*-----------------------------------------------------------*/
  596. #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
  597. /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the
  598. * application must provide an implementation of vApplicationGetTimerTaskMemory()
  599. * to provide the memory that is used by the Timer service task. */
  600. void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
  601. StackType_t ** ppxTimerTaskStackBuffer,
  602. uint32_t * pulTimerTaskStackSize )
  603. {
  604. /* If the buffers to be provided to the Timer task are declared inside this
  605. * function then they must be declared static - otherwise they will be allocated on
  606. * the stack and so not exists after this function exits. */
  607. static StaticTask_t xTimerTaskTCB;
  608. /* Pass out a pointer to the StaticTask_t structure in which the Timer
  609. * task's state will be stored. */
  610. *ppxTimerTaskTCBBuffer = &xTimerTaskTCB;
  611. /* Pass out the array that will be used as the Timer task's stack. */
  612. *ppxTimerTaskStackBuffer = uxTimerTaskStack;
  613. /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer.
  614. * Note that, as the array is necessarily of type StackType_t,
  615. * configMINIMAL_STACK_SIZE is specified in words, not bytes. */
  616. *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
  617. }
  618. #endif // configSUPPORT_STATIC_ALLOCATION == 1
  619. void vPortTakeLock( portMUX_TYPE *lock )
  620. {
  621. spinlock_acquire( lock, portMUX_NO_TIMEOUT);
  622. }
  623. void vPortReleaseLock( portMUX_TYPE *lock )
  624. {
  625. spinlock_release( lock );
  626. }
  627. #define FREERTOS_SMP_MALLOC_CAPS (MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT)
  628. void *pvPortMalloc( size_t xSize )
  629. {
  630. return heap_caps_malloc(xSize, FREERTOS_SMP_MALLOC_CAPS);
  631. }
  632. void vPortFree( void *pv )
  633. {
  634. heap_caps_free(pv);
  635. }
  636. void __attribute__((weak)) vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName)
  637. {
  638. #define ERR_STR1 "***ERROR*** A stack overflow in task "
  639. #define ERR_STR2 " has been detected."
  640. const char *str[] = {ERR_STR1, pcTaskName, ERR_STR2};
  641. char buf[sizeof(ERR_STR1) + CONFIG_FREERTOS_MAX_TASK_NAME_LEN + sizeof(ERR_STR2) + 1 /* null char */] = {0};
  642. char *dest = buf;
  643. for (int i = 0; i < sizeof(str) / sizeof(str[0]); i++) {
  644. dest = strcat(dest, str[i]);
  645. }
  646. printf("%s\n", buf);
  647. abort();
  648. }
  649. // ------- Thread Local Storage Pointers Deletion Callbacks -------
  650. #if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
  651. void vPortTLSPointersDelCb( void *pxTCB )
  652. {
  653. /* Typecast pxTCB to StaticTask_t type to access TCB struct members.
  654. * pvDummy15 corresponds to pvThreadLocalStoragePointers member of the TCB.
  655. */
  656. StaticTask_t *tcb = ( StaticTask_t * )pxTCB;
  657. /* The TLSP deletion callbacks are stored at an offset of (configNUM_THREAD_LOCAL_STORAGE_POINTERS/2) */
  658. TlsDeleteCallbackFunction_t *pvThreadLocalStoragePointersDelCallback = ( TlsDeleteCallbackFunction_t * )( &( tcb->pvDummy15[ ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ] ) );
  659. /* We need to iterate over half the depth of the pvThreadLocalStoragePointers area
  660. * to access all TLS pointers and their respective TLS deletion callbacks.
  661. */
  662. for ( int x = 0; x < ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ); x++ ) {
  663. if ( pvThreadLocalStoragePointersDelCallback[ x ] != NULL ) { //If del cb is set
  664. // We skip the check if the callback is executable as that is difficult to determine for different
  665. // platforms (compare xtensa and riscv code).
  666. pvThreadLocalStoragePointersDelCallback[ x ]( x, tcb->pvDummy15[ x ] ); //Call del cb
  667. }
  668. }
  669. }
  670. #endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS
  671. void vPortCleanUpTCB ( void *pxTCB )
  672. {
  673. #if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
  674. /* Call TLS pointers deletion callbacks */
  675. vPortTLSPointersDelCb( pxTCB );
  676. #endif /* CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS */
  677. vPortCancelThread(pxTCB);
  678. }