port.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  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. /* Scheduler includes. */
  64. #include "FreeRTOS.h"
  65. #include "task.h"
  66. #include "timers.h"
  67. #include "utils/wait_for_event.h"
  68. /*-----------------------------------------------------------*/
  69. #define SIG_RESUME SIGUSR1
  70. typedef struct THREAD
  71. {
  72. pthread_t pthread;
  73. TaskFunction_t pxCode;
  74. void *pvParams;
  75. BaseType_t xDying;
  76. struct event *ev;
  77. } Thread_t;
  78. /*
  79. * The additional per-thread data is stored at the beginning of the
  80. * task's stack.
  81. */
  82. static inline Thread_t *prvGetThreadFromTask(TaskHandle_t xTask)
  83. {
  84. StackType_t *pxTopOfStack = *(StackType_t **)xTask;
  85. return (Thread_t *)(pxTopOfStack + 1);
  86. }
  87. /*-----------------------------------------------------------*/
  88. static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT;
  89. static sigset_t xAllSignals;
  90. static sigset_t xSchedulerOriginalSignalMask;
  91. static pthread_t hMainThread = ( pthread_t )NULL;
  92. static volatile BaseType_t uxCriticalNesting;
  93. /*-----------------------------------------------------------*/
  94. static BaseType_t xSchedulerEnd = pdFALSE;
  95. /*-----------------------------------------------------------*/
  96. static void prvSetupSignalsAndSchedulerPolicy( void );
  97. static void prvSetupTimerInterrupt( void );
  98. static void *prvWaitForStart( void * pvParams );
  99. static void prvSwitchThread( Thread_t * xThreadToResume,
  100. Thread_t *xThreadToSuspend );
  101. static void prvSuspendSelf( Thread_t * thread);
  102. static void prvResumeThread( Thread_t * xThreadId );
  103. static void vPortSystemTickHandler( int sig );
  104. static void vPortStartFirstTask( void );
  105. /*-----------------------------------------------------------*/
  106. static void prvFatalError( const char *pcCall, int iErrno )
  107. {
  108. fprintf( stderr, "%s: %s\n", pcCall, strerror( iErrno ) );
  109. abort();
  110. }
  111. /*
  112. * See header file for description.
  113. */
  114. StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack,
  115. StackType_t *pxEndOfStack,
  116. TaskFunction_t pxCode,
  117. void *pvParameters )
  118. {
  119. Thread_t *thread;
  120. pthread_attr_t xThreadAttributes;
  121. size_t ulStackSize;
  122. int iRet;
  123. (void)pthread_once( &hSigSetupThread, prvSetupSignalsAndSchedulerPolicy );
  124. /*
  125. * Store the additional thread data at the start of the stack.
  126. */
  127. thread = (Thread_t *)(pxTopOfStack + 1) - 1;
  128. pxTopOfStack = (StackType_t *)thread - 1;
  129. ulStackSize = (pxTopOfStack + 1 - pxEndOfStack) * sizeof(*pxTopOfStack);
  130. thread->pxCode = pxCode;
  131. thread->pvParams = pvParameters;
  132. thread->xDying = pdFALSE;
  133. pthread_attr_init( &xThreadAttributes );
  134. pthread_attr_setstack( &xThreadAttributes, pxEndOfStack, ulStackSize );
  135. thread->ev = event_create();
  136. vPortEnterCritical();
  137. iRet = pthread_create( &thread->pthread, &xThreadAttributes,
  138. prvWaitForStart, thread );
  139. if ( iRet )
  140. {
  141. prvFatalError( "pthread_create", iRet );
  142. }
  143. vPortExitCritical();
  144. return pxTopOfStack;
  145. }
  146. /*-----------------------------------------------------------*/
  147. void vPortStartFirstTask( void )
  148. {
  149. Thread_t *pxFirstThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  150. /* Start the first task. */
  151. prvResumeThread( pxFirstThread );
  152. }
  153. /*-----------------------------------------------------------*/
  154. /*
  155. * See header file for description.
  156. */
  157. BaseType_t xPortStartScheduler( void )
  158. {
  159. int iSignal;
  160. sigset_t xSignals;
  161. hMainThread = pthread_self();
  162. /* Start the timer that generates the tick ISR(SIGALRM).
  163. Interrupts are disabled here already. */
  164. prvSetupTimerInterrupt();
  165. /* Start the first task. */
  166. vPortStartFirstTask();
  167. /* Wait until signaled by vPortEndScheduler(). */
  168. sigemptyset( &xSignals );
  169. sigaddset( &xSignals, SIG_RESUME );
  170. while ( !xSchedulerEnd )
  171. {
  172. sigwait( &xSignals, &iSignal );
  173. }
  174. /* Cancel the Idle task and free its resources */
  175. #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
  176. vPortCancelThread( xTaskGetIdleTaskHandle() );
  177. #endif
  178. #if ( configUSE_TIMERS == 1 )
  179. /* Cancel the Timer task and free its resources */
  180. vPortCancelThread( xTimerGetTimerDaemonTaskHandle() );
  181. #endif /* configUSE_TIMERS */
  182. /* Restore original signal mask. */
  183. (void)pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask, NULL );
  184. return 0;
  185. }
  186. /*-----------------------------------------------------------*/
  187. void vPortEndScheduler( void )
  188. {
  189. struct itimerval itimer;
  190. struct sigaction sigtick;
  191. Thread_t *xCurrentThread;
  192. /* Stop the timer and ignore any pending SIGALRMs that would end
  193. * up running on the main thread when it is resumed. */
  194. itimer.it_value.tv_sec = 0;
  195. itimer.it_value.tv_usec = 0;
  196. itimer.it_interval.tv_sec = 0;
  197. itimer.it_interval.tv_usec = 0;
  198. (void)setitimer( ITIMER_REAL, &itimer, NULL );
  199. sigtick.sa_flags = 0;
  200. sigtick.sa_handler = SIG_IGN;
  201. sigemptyset( &sigtick.sa_mask );
  202. sigaction( SIGALRM, &sigtick, NULL );
  203. /* Signal the scheduler to exit its loop. */
  204. xSchedulerEnd = pdTRUE;
  205. (void)pthread_kill( hMainThread, SIG_RESUME );
  206. xCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  207. prvSuspendSelf(xCurrentThread);
  208. }
  209. /*-----------------------------------------------------------*/
  210. void vPortEnterCritical( void )
  211. {
  212. if ( uxCriticalNesting == 0 )
  213. {
  214. vPortDisableInterrupts();
  215. }
  216. uxCriticalNesting++;
  217. }
  218. /*-----------------------------------------------------------*/
  219. void vPortExitCritical( void )
  220. {
  221. uxCriticalNesting--;
  222. /* If we have reached 0 then re-enable the interrupts. */
  223. if( uxCriticalNesting == 0 )
  224. {
  225. vPortEnableInterrupts();
  226. }
  227. }
  228. /*-----------------------------------------------------------*/
  229. void vPortYieldFromISR( void )
  230. {
  231. Thread_t *xThreadToSuspend;
  232. Thread_t *xThreadToResume;
  233. xThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  234. vTaskSwitchContext();
  235. xThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  236. prvSwitchThread( xThreadToResume, xThreadToSuspend );
  237. }
  238. /*-----------------------------------------------------------*/
  239. void vPortYield( void )
  240. {
  241. vPortEnterCritical();
  242. vPortYieldFromISR();
  243. vPortExitCritical();
  244. }
  245. /*-----------------------------------------------------------*/
  246. void vPortDisableInterrupts( void )
  247. {
  248. pthread_sigmask( SIG_BLOCK, &xAllSignals, NULL );
  249. }
  250. /*-----------------------------------------------------------*/
  251. void vPortEnableInterrupts( void )
  252. {
  253. pthread_sigmask( SIG_UNBLOCK, &xAllSignals, NULL );
  254. }
  255. /*-----------------------------------------------------------*/
  256. BaseType_t xPortSetInterruptMask( void )
  257. {
  258. /* Interrupts are always disabled inside ISRs (signals
  259. handlers). */
  260. return pdTRUE;
  261. }
  262. /*-----------------------------------------------------------*/
  263. void vPortClearInterruptMask( BaseType_t xMask )
  264. {
  265. }
  266. /*-----------------------------------------------------------*/
  267. static uint64_t prvGetTimeNs(void)
  268. {
  269. struct timespec t;
  270. clock_gettime(CLOCK_MONOTONIC, &t);
  271. return t.tv_sec * 1000000000ull + t.tv_nsec;
  272. }
  273. static uint64_t prvStartTimeNs;
  274. /* commented as part of the code below in vPortSystemTickHandler,
  275. * to adjust timing according to full demo requirements */
  276. /* static uint64_t prvTickCount; */
  277. /*
  278. * Setup the systick timer to generate the tick interrupts at the required
  279. * frequency.
  280. */
  281. void prvSetupTimerInterrupt( void )
  282. {
  283. struct itimerval itimer;
  284. int iRet;
  285. /* Initialise the structure with the current timer information. */
  286. iRet = getitimer( ITIMER_REAL, &itimer );
  287. if ( iRet )
  288. {
  289. prvFatalError( "getitimer", errno );
  290. }
  291. /* Set the interval between timer events. */
  292. itimer.it_interval.tv_sec = 0;
  293. itimer.it_interval.tv_usec = portTICK_RATE_MICROSECONDS;
  294. /* Set the current count-down. */
  295. itimer.it_value.tv_sec = 0;
  296. itimer.it_value.tv_usec = portTICK_RATE_MICROSECONDS;
  297. /* Set-up the timer interrupt. */
  298. iRet = setitimer( ITIMER_REAL, &itimer, NULL );
  299. if ( iRet )
  300. {
  301. prvFatalError( "setitimer", errno );
  302. }
  303. prvStartTimeNs = prvGetTimeNs();
  304. }
  305. /*-----------------------------------------------------------*/
  306. static void vPortSystemTickHandler( int sig )
  307. {
  308. Thread_t *pxThreadToSuspend;
  309. Thread_t *pxThreadToResume;
  310. /* uint64_t xExpectedTicks; */
  311. uxCriticalNesting++; /* Signals are blocked in this signal handler. */
  312. #if ( configUSE_PREEMPTION == 1 )
  313. pxThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  314. #endif
  315. /* Tick Increment, accounting for any lost signals or drift in
  316. * the timer. */
  317. /*
  318. * Comment code to adjust timing according to full demo requirements
  319. * xExpectedTicks = (prvGetTimeNs() - prvStartTimeNs)
  320. * / (portTICK_RATE_MICROSECONDS * 1000);
  321. * do { */
  322. xTaskIncrementTick();
  323. /* prvTickCount++;
  324. * } while (prvTickCount < xExpectedTicks);
  325. */
  326. #if ( configUSE_PREEMPTION == 1 )
  327. /* Select Next Task. */
  328. vTaskSwitchContext();
  329. pxThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  330. prvSwitchThread(pxThreadToResume, pxThreadToSuspend);
  331. #endif
  332. uxCriticalNesting--;
  333. }
  334. /*-----------------------------------------------------------*/
  335. void vPortThreadDying( void *pxTaskToDelete, volatile BaseType_t *pxPendYield )
  336. {
  337. Thread_t *pxThread = prvGetThreadFromTask( pxTaskToDelete );
  338. pxThread->xDying = pdTRUE;
  339. }
  340. void vPortCancelThread( void *pxTaskToDelete )
  341. {
  342. Thread_t *pxThreadToCancel = prvGetThreadFromTask( pxTaskToDelete );
  343. /*
  344. * The thread has already been suspended so it can be safely cancelled.
  345. */
  346. pthread_cancel( pxThreadToCancel->pthread );
  347. pthread_join( pxThreadToCancel->pthread, NULL );
  348. event_delete( pxThreadToCancel->ev );
  349. }
  350. /*-----------------------------------------------------------*/
  351. static void *prvWaitForStart( void * pvParams )
  352. {
  353. Thread_t *pxThread = pvParams;
  354. prvSuspendSelf(pxThread);
  355. /* Resumed for the first time, unblocks all signals. */
  356. uxCriticalNesting = 0;
  357. vPortEnableInterrupts();
  358. /* Call the task's entry point. */
  359. pxThread->pxCode( pxThread->pvParams );
  360. /* A function that implements a task must not exit or attempt to return to
  361. * its caller as there is nothing to return to. If a task wants to exit it
  362. * should instead call vTaskDelete( NULL ). Artificially force an assert()
  363. * to be triggered if configASSERT() is defined, so application writers can
  364. * catch the error. */
  365. configASSERT( pdFALSE );
  366. return NULL;
  367. }
  368. /*-----------------------------------------------------------*/
  369. static void prvSwitchThread( Thread_t *pxThreadToResume,
  370. Thread_t *pxThreadToSuspend )
  371. {
  372. BaseType_t uxSavedCriticalNesting;
  373. if ( pxThreadToSuspend != pxThreadToResume )
  374. {
  375. /*
  376. * Switch tasks.
  377. *
  378. * The critical section nesting is per-task, so save it on the
  379. * stack of the current (suspending thread), restoring it when
  380. * we switch back to this task.
  381. */
  382. uxSavedCriticalNesting = uxCriticalNesting;
  383. prvResumeThread( pxThreadToResume );
  384. if ( pxThreadToSuspend->xDying )
  385. {
  386. pthread_exit( NULL );
  387. }
  388. prvSuspendSelf( pxThreadToSuspend );
  389. uxCriticalNesting = uxSavedCriticalNesting;
  390. }
  391. }
  392. /*-----------------------------------------------------------*/
  393. static void prvSuspendSelf( Thread_t *thread )
  394. {
  395. /*
  396. * Suspend this thread by waiting for a pthread_cond_signal event.
  397. *
  398. * A suspended thread must not handle signals (interrupts) so
  399. * all signals must be blocked by calling this from:
  400. *
  401. * - Inside a critical section (vPortEnterCritical() /
  402. * vPortExitCritical()).
  403. *
  404. * - From a signal handler that has all signals masked.
  405. *
  406. * - A thread with all signals blocked with pthread_sigmask().
  407. */
  408. event_wait(thread->ev);
  409. }
  410. /*-----------------------------------------------------------*/
  411. static void prvResumeThread( Thread_t *xThreadId )
  412. {
  413. if ( pthread_self() != xThreadId->pthread )
  414. {
  415. event_signal(xThreadId->ev);
  416. }
  417. }
  418. /*-----------------------------------------------------------*/
  419. static void prvSetupSignalsAndSchedulerPolicy( void )
  420. {
  421. struct sigaction sigresume, sigtick;
  422. int iRet;
  423. hMainThread = pthread_self();
  424. /* Initialise common signal masks. */
  425. sigfillset( &xAllSignals );
  426. /* Don't block SIGINT so this can be used to break into GDB while
  427. * in a critical section. */
  428. sigdelset( &xAllSignals, SIGINT );
  429. /*
  430. * Block all signals in this thread so all new threads
  431. * inherits this mask.
  432. *
  433. * When a thread is resumed for the first time, all signals
  434. * will be unblocked.
  435. */
  436. (void)pthread_sigmask( SIG_SETMASK, &xAllSignals,
  437. &xSchedulerOriginalSignalMask );
  438. /* SIG_RESUME is only used with sigwait() so doesn't need a
  439. handler. */
  440. sigresume.sa_flags = 0;
  441. sigresume.sa_handler = SIG_IGN;
  442. sigfillset( &sigresume.sa_mask );
  443. sigtick.sa_flags = 0;
  444. sigtick.sa_handler = vPortSystemTickHandler;
  445. sigfillset( &sigtick.sa_mask );
  446. iRet = sigaction( SIG_RESUME, &sigresume, NULL );
  447. if ( iRet )
  448. {
  449. prvFatalError( "sigaction", errno );
  450. }
  451. iRet = sigaction( SIGALRM, &sigtick, NULL );
  452. if ( iRet )
  453. {
  454. prvFatalError( "sigaction", errno );
  455. }
  456. }
  457. /*-----------------------------------------------------------*/
  458. unsigned long ulPortGetRunTime( void )
  459. {
  460. struct tms xTimes;
  461. times( &xTimes );
  462. return ( unsigned long ) xTimes.tms_utime;
  463. }
  464. /*-----------------------------------------------------------*/