port.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. /*
  2. * FreeRTOS Kernel V10.4.3
  3. * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy of
  6. * this software and associated documentation files (the "Software"), to deal in
  7. * the Software without restriction, including without limitation the rights to
  8. * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
  9. * the Software, and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
  17. * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
  18. * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
  19. * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  20. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * https://www.FreeRTOS.org
  23. * https://github.com/FreeRTOS
  24. *
  25. */
  26. /*-----------------------------------------------------------
  27. * Implementation of functions defined in portable.h for the Posix port.
  28. *
  29. * Each task has a pthread which eases use of standard debuggers
  30. * (allowing backtraces of tasks etc). Threads for tasks that are not
  31. * running are blocked in sigwait().
  32. *
  33. * Task switch is done by resuming the thread for the next task by
  34. * signaling the condition variable and then waiting on a condition variable
  35. * with the current thread.
  36. *
  37. * The timer interrupt uses SIGALRM and care is taken to ensure that
  38. * the signal handler runs only on the thread for the current task.
  39. *
  40. * Use of part of the standard C library requires care as some
  41. * functions can take pthread mutexes internally which can result in
  42. * deadlocks as the FreeRTOS kernel can switch tasks while they're
  43. * holding a pthread mutex.
  44. *
  45. * stdio (printf() and friends) should be called from a single task
  46. * only or serialized with a FreeRTOS primitive such as a binary
  47. * semaphore or mutex.
  48. *----------------------------------------------------------*/
  49. #include <errno.h>
  50. #include <pthread.h>
  51. #include <signal.h>
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #include <sys/time.h>
  56. #include <sys/times.h>
  57. #include <time.h>
  58. /* Scheduler includes. */
  59. #include "FreeRTOS.h"
  60. #include "task.h"
  61. #include "timers.h"
  62. #include "utils/wait_for_event.h"
  63. /*-----------------------------------------------------------*/
  64. #define SIG_RESUME SIGUSR1
  65. typedef struct THREAD
  66. {
  67. pthread_t pthread;
  68. pdTASK_CODE pxCode;
  69. void *pvParams;
  70. BaseType_t xDying;
  71. struct event *ev;
  72. } Thread_t;
  73. /*
  74. * The additional per-thread data is stored at the beginning of the
  75. * task's stack.
  76. */
  77. static inline Thread_t *prvGetThreadFromTask(TaskHandle_t xTask)
  78. {
  79. StackType_t *pxTopOfStack = *(StackType_t **)xTask;
  80. return (Thread_t *)(pxTopOfStack + 1);
  81. }
  82. /*-----------------------------------------------------------*/
  83. static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT;
  84. static sigset_t xResumeSignals;
  85. static sigset_t xAllSignals;
  86. static sigset_t xSchedulerOriginalSignalMask;
  87. static pthread_t hMainThread = ( pthread_t )NULL;
  88. static volatile portBASE_TYPE uxCriticalNesting;
  89. /*-----------------------------------------------------------*/
  90. static portBASE_TYPE xSchedulerEnd = pdFALSE;
  91. /*-----------------------------------------------------------*/
  92. static void prvSetupSignalsAndSchedulerPolicy( void );
  93. static void prvSetupTimerInterrupt( void );
  94. static void *prvWaitForStart( void * pvParams );
  95. static void prvSwitchThread( Thread_t * xThreadToResume,
  96. Thread_t *xThreadToSuspend );
  97. static void prvSuspendSelf( Thread_t * thread);
  98. static void prvResumeThread( Thread_t * xThreadId );
  99. static void vPortSystemTickHandler( int sig );
  100. static void vPortStartFirstTask( void );
  101. /*-----------------------------------------------------------*/
  102. static void prvFatalError( const char *pcCall, int iErrno )
  103. {
  104. fprintf( stderr, "%s: %s\n", pcCall, strerror( iErrno ) );
  105. abort();
  106. }
  107. /*
  108. * See header file for description.
  109. */
  110. portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack,
  111. portSTACK_TYPE *pxEndOfStack,
  112. pdTASK_CODE pxCode, void *pvParameters )
  113. {
  114. Thread_t *thread;
  115. pthread_attr_t xThreadAttributes;
  116. size_t ulStackSize;
  117. int iRet;
  118. (void)pthread_once( &hSigSetupThread, prvSetupSignalsAndSchedulerPolicy );
  119. /*
  120. * Store the additional thread data at the start of the stack.
  121. */
  122. thread = (Thread_t *)(pxTopOfStack + 1) - 1;
  123. pxTopOfStack = (portSTACK_TYPE *)thread - 1;
  124. ulStackSize = (pxTopOfStack + 1 - pxEndOfStack) * sizeof(*pxTopOfStack);
  125. thread->pxCode = pxCode;
  126. thread->pvParams = pvParameters;
  127. thread->xDying = pdFALSE;
  128. pthread_attr_init( &xThreadAttributes );
  129. pthread_attr_setstack( &xThreadAttributes, pxEndOfStack, ulStackSize );
  130. thread->ev = event_create();
  131. vPortEnterCritical();
  132. iRet = pthread_create( &thread->pthread, &xThreadAttributes,
  133. prvWaitForStart, thread );
  134. if ( iRet )
  135. {
  136. prvFatalError( "pthread_create", iRet );
  137. }
  138. vPortExitCritical();
  139. return pxTopOfStack;
  140. }
  141. /*-----------------------------------------------------------*/
  142. void vPortStartFirstTask( void )
  143. {
  144. Thread_t *pxFirstThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  145. /* Start the first task. */
  146. prvResumeThread( pxFirstThread );
  147. }
  148. /*-----------------------------------------------------------*/
  149. /*
  150. * See header file for description.
  151. */
  152. portBASE_TYPE xPortStartScheduler( void )
  153. {
  154. int iSignal;
  155. sigset_t xSignals;
  156. hMainThread = pthread_self();
  157. /* Start the timer that generates the tick ISR(SIGALRM).
  158. Interrupts are disabled here already. */
  159. prvSetupTimerInterrupt();
  160. /* Start the first task. */
  161. vPortStartFirstTask();
  162. /* Wait until signaled by vPortEndScheduler(). */
  163. sigemptyset( &xSignals );
  164. sigaddset( &xSignals, SIG_RESUME );
  165. while ( !xSchedulerEnd )
  166. {
  167. sigwait( &xSignals, &iSignal );
  168. }
  169. /* Cancel the Idle task and free its resources */
  170. #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
  171. vPortCancelThread( xTaskGetIdleTaskHandle() );
  172. #endif
  173. #if ( configUSE_TIMERS == 1 )
  174. /* Cancel the Timer task and free its resources */
  175. vPortCancelThread( xTimerGetTimerDaemonTaskHandle() );
  176. #endif /* configUSE_TIMERS */
  177. /* Restore original signal mask. */
  178. (void)pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask, NULL );
  179. return 0;
  180. }
  181. /*-----------------------------------------------------------*/
  182. void vPortEndScheduler( void )
  183. {
  184. struct itimerval itimer;
  185. struct sigaction sigtick;
  186. Thread_t *xCurrentThread;
  187. /* Stop the timer and ignore any pending SIGALRMs that would end
  188. * up running on the main thread when it is resumed. */
  189. itimer.it_value.tv_sec = 0;
  190. itimer.it_value.tv_usec = 0;
  191. itimer.it_interval.tv_sec = 0;
  192. itimer.it_interval.tv_usec = 0;
  193. (void)setitimer( ITIMER_REAL, &itimer, NULL );
  194. sigtick.sa_flags = 0;
  195. sigtick.sa_handler = SIG_IGN;
  196. sigemptyset( &sigtick.sa_mask );
  197. sigaction( SIGALRM, &sigtick, NULL );
  198. /* Signal the scheduler to exit its loop. */
  199. xSchedulerEnd = pdTRUE;
  200. (void)pthread_kill( hMainThread, SIG_RESUME );
  201. xCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  202. prvSuspendSelf(xCurrentThread);
  203. }
  204. /*-----------------------------------------------------------*/
  205. void vPortEnterCritical( void )
  206. {
  207. if ( uxCriticalNesting == 0 )
  208. {
  209. vPortDisableInterrupts();
  210. }
  211. uxCriticalNesting++;
  212. }
  213. /*-----------------------------------------------------------*/
  214. void vPortExitCritical( void )
  215. {
  216. uxCriticalNesting--;
  217. /* If we have reached 0 then re-enable the interrupts. */
  218. if( uxCriticalNesting == 0 )
  219. {
  220. vPortEnableInterrupts();
  221. }
  222. }
  223. /*-----------------------------------------------------------*/
  224. void vPortYieldFromISR( void )
  225. {
  226. Thread_t *xThreadToSuspend;
  227. Thread_t *xThreadToResume;
  228. xThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  229. vTaskSwitchContext();
  230. xThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  231. prvSwitchThread( xThreadToResume, xThreadToSuspend );
  232. }
  233. /*-----------------------------------------------------------*/
  234. void vPortYield( void )
  235. {
  236. vPortEnterCritical();
  237. vPortYieldFromISR();
  238. vPortExitCritical();
  239. }
  240. /*-----------------------------------------------------------*/
  241. void vPortDisableInterrupts( void )
  242. {
  243. pthread_sigmask( SIG_BLOCK, &xAllSignals, NULL );
  244. }
  245. /*-----------------------------------------------------------*/
  246. void vPortEnableInterrupts( void )
  247. {
  248. pthread_sigmask( SIG_UNBLOCK, &xAllSignals, NULL );
  249. }
  250. /*-----------------------------------------------------------*/
  251. portBASE_TYPE xPortSetInterruptMask( void )
  252. {
  253. /* Interrupts are always disabled inside ISRs (signals
  254. handlers). */
  255. return pdTRUE;
  256. }
  257. /*-----------------------------------------------------------*/
  258. void vPortClearInterruptMask( portBASE_TYPE xMask )
  259. {
  260. }
  261. /*-----------------------------------------------------------*/
  262. static uint64_t prvGetTimeNs(void)
  263. {
  264. struct timespec t;
  265. clock_gettime(CLOCK_MONOTONIC, &t);
  266. return t.tv_sec * 1000000000ull + t.tv_nsec;
  267. }
  268. static uint64_t prvStartTimeNs;
  269. /* commented as part of the code below in vPortSystemTickHandler,
  270. * to adjust timing according to full demo requirements */
  271. /* static uint64_t prvTickCount; */
  272. /*
  273. * Setup the systick timer to generate the tick interrupts at the required
  274. * frequency.
  275. */
  276. void prvSetupTimerInterrupt( void )
  277. {
  278. struct itimerval itimer;
  279. int iRet;
  280. /* Initialise the structure with the current timer information. */
  281. iRet = getitimer( ITIMER_REAL, &itimer );
  282. if ( iRet )
  283. {
  284. prvFatalError( "getitimer", errno );
  285. }
  286. /* Set the interval between timer events. */
  287. itimer.it_interval.tv_sec = 0;
  288. itimer.it_interval.tv_usec = portTICK_RATE_MICROSECONDS;
  289. /* Set the current count-down. */
  290. itimer.it_value.tv_sec = 0;
  291. itimer.it_value.tv_usec = portTICK_RATE_MICROSECONDS;
  292. /* Set-up the timer interrupt. */
  293. iRet = setitimer( ITIMER_REAL, &itimer, NULL );
  294. if ( iRet )
  295. {
  296. prvFatalError( "setitimer", errno );
  297. }
  298. prvStartTimeNs = prvGetTimeNs();
  299. }
  300. /*-----------------------------------------------------------*/
  301. static void vPortSystemTickHandler( int sig )
  302. {
  303. Thread_t *pxThreadToSuspend;
  304. Thread_t *pxThreadToResume;
  305. /* uint64_t xExpectedTicks; */
  306. uxCriticalNesting++; /* Signals are blocked in this signal handler. */
  307. #if ( configUSE_PREEMPTION == 1 )
  308. pxThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  309. #endif
  310. /* Tick Increment, accounting for any lost signals or drift in
  311. * the timer. */
  312. /*
  313. * Comment code to adjust timing according to full demo requirements
  314. * xExpectedTicks = (prvGetTimeNs() - prvStartTimeNs)
  315. * / (portTICK_RATE_MICROSECONDS * 1000);
  316. * do { */
  317. xTaskIncrementTick();
  318. /* prvTickCount++;
  319. * } while (prvTickCount < xExpectedTicks);
  320. */
  321. #if ( configUSE_PREEMPTION == 1 )
  322. /* Select Next Task. */
  323. vTaskSwitchContext();
  324. pxThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  325. prvSwitchThread(pxThreadToResume, pxThreadToSuspend);
  326. #endif
  327. uxCriticalNesting--;
  328. }
  329. /*-----------------------------------------------------------*/
  330. void vPortThreadDying( void *pxTaskToDelete, volatile BaseType_t *pxPendYield )
  331. {
  332. Thread_t *pxThread = prvGetThreadFromTask( pxTaskToDelete );
  333. pxThread->xDying = pdTRUE;
  334. }
  335. void vPortCancelThread( void *pxTaskToDelete )
  336. {
  337. Thread_t *pxThreadToCancel = prvGetThreadFromTask( pxTaskToDelete );
  338. /*
  339. * The thread has already been suspended so it can be safely cancelled.
  340. */
  341. pthread_cancel( pxThreadToCancel->pthread );
  342. pthread_join( pxThreadToCancel->pthread, NULL );
  343. event_delete( pxThreadToCancel->ev );
  344. }
  345. /*-----------------------------------------------------------*/
  346. static void *prvWaitForStart( void * pvParams )
  347. {
  348. Thread_t *pxThread = pvParams;
  349. prvSuspendSelf(pxThread);
  350. /* Resumed for the first time, unblocks all signals. */
  351. uxCriticalNesting = 0;
  352. vPortEnableInterrupts();
  353. /* Call the task's entry point. */
  354. pxThread->pxCode( pxThread->pvParams );
  355. /* A function that implements a task must not exit or attempt to return to
  356. * its caller as there is nothing to return to. If a task wants to exit it
  357. * should instead call vTaskDelete( NULL ). Artificially force an assert()
  358. * to be triggered if configASSERT() is defined, so application writers can
  359. * catch the error. */
  360. configASSERT( pdFALSE );
  361. return NULL;
  362. }
  363. /*-----------------------------------------------------------*/
  364. static void prvSwitchThread( Thread_t *pxThreadToResume,
  365. Thread_t *pxThreadToSuspend )
  366. {
  367. BaseType_t uxSavedCriticalNesting;
  368. if ( pxThreadToSuspend != pxThreadToResume )
  369. {
  370. /*
  371. * Switch tasks.
  372. *
  373. * The critical section nesting is per-task, so save it on the
  374. * stack of the current (suspending thread), restoring it when
  375. * we switch back to this task.
  376. */
  377. uxSavedCriticalNesting = uxCriticalNesting;
  378. prvResumeThread( pxThreadToResume );
  379. if ( pxThreadToSuspend->xDying )
  380. {
  381. pthread_exit( NULL );
  382. }
  383. prvSuspendSelf( pxThreadToSuspend );
  384. uxCriticalNesting = uxSavedCriticalNesting;
  385. }
  386. }
  387. /*-----------------------------------------------------------*/
  388. static void prvSuspendSelf( Thread_t *thread )
  389. {
  390. /*
  391. * Suspend this thread by waiting for a pthread_cond_signal event.
  392. *
  393. * A suspended thread must not handle signals (interrupts) so
  394. * all signals must be blocked by calling this from:
  395. *
  396. * - Inside a critical section (vPortEnterCritical() /
  397. * vPortExitCritical()).
  398. *
  399. * - From a signal handler that has all signals masked.
  400. *
  401. * - A thread with all signals blocked with pthread_sigmask().
  402. */
  403. event_wait(thread->ev);
  404. }
  405. /*-----------------------------------------------------------*/
  406. static void prvResumeThread( Thread_t *xThreadId )
  407. {
  408. if ( pthread_self() != xThreadId->pthread )
  409. {
  410. event_signal(xThreadId->ev);
  411. }
  412. }
  413. /*-----------------------------------------------------------*/
  414. static void prvSetupSignalsAndSchedulerPolicy( void )
  415. {
  416. struct sigaction sigresume, sigtick;
  417. int iRet;
  418. hMainThread = pthread_self();
  419. /* Initialise common signal masks. */
  420. sigemptyset( &xResumeSignals );
  421. sigaddset( &xResumeSignals, SIG_RESUME );
  422. sigfillset( &xAllSignals );
  423. /* Don't block SIGINT so this can be used to break into GDB while
  424. * in a critical section. */
  425. sigdelset( &xAllSignals, SIGINT );
  426. /*
  427. * Block all signals in this thread so all new threads
  428. * inherits this mask.
  429. *
  430. * When a thread is resumed for the first time, all signals
  431. * will be unblocked.
  432. */
  433. //(void)pthread_sigmask( SIG_SETMASK, &xAllSignals,
  434. // *&xSchedulerOriginalSignalMask );
  435. /* SIG_RESUME is only used with sigwait() so doesn't need a
  436. handler. */
  437. sigresume.sa_flags = 0;
  438. sigresume.sa_handler = SIG_IGN;
  439. sigfillset( &sigresume.sa_mask );
  440. sigtick.sa_flags = 0;
  441. sigtick.sa_handler = vPortSystemTickHandler;
  442. sigfillset( &sigtick.sa_mask );
  443. iRet = sigaction( SIG_RESUME, &sigresume, NULL );
  444. if ( iRet )
  445. {
  446. prvFatalError( "sigaction", errno );
  447. }
  448. iRet = sigaction( SIGALRM, &sigtick, NULL );
  449. if ( iRet )
  450. {
  451. prvFatalError( "sigaction", errno );
  452. }
  453. }
  454. /*-----------------------------------------------------------*/
  455. unsigned long ulPortGetRunTime( void )
  456. {
  457. struct tms xTimes;
  458. times( &xTimes );
  459. return ( unsigned long ) xTimes.tms_utime;
  460. }
  461. /*-----------------------------------------------------------*/