port.c 16 KB

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