port.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. /*
  2. * FreeRTOS Kernel <DEVELOPMENT BRANCH>
  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. * Note: When using LLDB (the default debugger on macOS) with this port,
  52. * suppress SIGUSR1 to prevent debugger interference. This can be
  53. * done by adding the following line to ~/.lldbinit:
  54. * `process handle SIGUSR1 -n true -p false -s false`
  55. *----------------------------------------------------------*/
  56. #ifdef __linux__
  57. #define _GNU_SOURCE
  58. #endif
  59. #include "portmacro.h"
  60. #include <errno.h>
  61. #include <pthread.h>
  62. #include <limits.h>
  63. #include <signal.h>
  64. #include <stdio.h>
  65. #include <stdlib.h>
  66. #include <string.h>
  67. #include <sys/time.h>
  68. #include <sys/times.h>
  69. #include <time.h>
  70. #include <unistd.h>
  71. /* Scheduler includes. */
  72. #include "FreeRTOS.h"
  73. #include "task.h"
  74. #include "timers.h"
  75. #include "utils/wait_for_event.h"
  76. /*-----------------------------------------------------------*/
  77. #define SIG_RESUME SIGUSR1
  78. typedef struct THREAD
  79. {
  80. pthread_t pthread;
  81. TaskFunction_t pxCode;
  82. void * pvParams;
  83. BaseType_t xDying;
  84. struct event * ev;
  85. } Thread_t;
  86. /*
  87. * The additional per-thread data is stored at the beginning of the
  88. * task's stack.
  89. */
  90. static inline Thread_t * prvGetThreadFromTask( TaskHandle_t xTask )
  91. {
  92. StackType_t * pxTopOfStack = *( StackType_t ** ) xTask;
  93. return ( Thread_t * ) ( pxTopOfStack + 1 );
  94. }
  95. /*-----------------------------------------------------------*/
  96. static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT;
  97. static pthread_once_t hThreadKeyOnce = PTHREAD_ONCE_INIT;
  98. static sigset_t xAllSignals;
  99. static sigset_t xSchedulerOriginalSignalMask;
  100. static pthread_t hMainThread = ( pthread_t ) NULL;
  101. static volatile BaseType_t uxCriticalNesting;
  102. static BaseType_t xSchedulerEnd = pdFALSE;
  103. static pthread_t hTimerTickThread;
  104. static bool xTimerTickThreadShouldRun;
  105. static uint64_t prvStartTimeNs;
  106. static pthread_key_t xThreadKey = 0;
  107. /*-----------------------------------------------------------*/
  108. static void prvSetupSignalsAndSchedulerPolicy( void );
  109. static void prvSetupTimerInterrupt( void );
  110. static void * prvWaitForStart( void * pvParams );
  111. static void prvSwitchThread( Thread_t * xThreadToResume,
  112. Thread_t * xThreadToSuspend );
  113. static void prvSuspendSelf( Thread_t * thread );
  114. static void prvResumeThread( Thread_t * xThreadId );
  115. static void vPortSystemTickHandler( int sig );
  116. static void vPortStartFirstTask( void );
  117. static void prvPortYieldFromISR( void );
  118. static void prvThreadKeyDestructor( void * pvData );
  119. static void prvInitThreadKey( void );
  120. static void prvMarkAsFreeRTOSThread( void );
  121. static BaseType_t prvIsFreeRTOSThread( void );
  122. static void prvDestroyThreadKey( void );
  123. /*-----------------------------------------------------------*/
  124. static void prvThreadKeyDestructor( void * pvData )
  125. {
  126. free( pvData );
  127. }
  128. /*-----------------------------------------------------------*/
  129. static void prvInitThreadKey( void )
  130. {
  131. pthread_key_create( &xThreadKey, prvThreadKeyDestructor );
  132. /* Destroy xThreadKey when the process exits. */
  133. atexit( prvDestroyThreadKey );
  134. }
  135. /*-----------------------------------------------------------*/
  136. static void prvMarkAsFreeRTOSThread( void )
  137. {
  138. uint8_t * pucThreadData = NULL;
  139. ( void ) pthread_once( &hThreadKeyOnce, prvInitThreadKey );
  140. pucThreadData = malloc( 1 );
  141. configASSERT( pucThreadData != NULL );
  142. *pucThreadData = 1;
  143. pthread_setspecific( xThreadKey, pucThreadData );
  144. }
  145. /*-----------------------------------------------------------*/
  146. static BaseType_t prvIsFreeRTOSThread( void )
  147. {
  148. uint8_t * pucThreadData = NULL;
  149. BaseType_t xRet = pdFALSE;
  150. ( void ) pthread_once( &hThreadKeyOnce, prvInitThreadKey );
  151. pucThreadData = ( uint8_t * ) pthread_getspecific( xThreadKey );
  152. if( ( pucThreadData != NULL ) && ( *pucThreadData == 1 ) )
  153. {
  154. xRet = pdTRUE;
  155. }
  156. return xRet;
  157. }
  158. /*-----------------------------------------------------------*/
  159. static void prvDestroyThreadKey( void )
  160. {
  161. pthread_key_delete( xThreadKey );
  162. }
  163. /*-----------------------------------------------------------*/
  164. static void prvFatalError( const char * pcCall,
  165. int iErrno ) __attribute__( ( __noreturn__ ) );
  166. void prvFatalError( const char * pcCall,
  167. int iErrno )
  168. {
  169. fprintf( stderr, "%s: %s\n", pcCall, strerror( iErrno ) );
  170. abort();
  171. }
  172. /*-----------------------------------------------------------*/
  173. static void prvPortSetCurrentThreadName( const char * pxThreadName )
  174. {
  175. #ifdef __APPLE__
  176. pthread_setname_np( pxThreadName );
  177. #else
  178. pthread_setname_np( pthread_self(), pxThreadName );
  179. #endif
  180. }
  181. /*-----------------------------------------------------------*/
  182. /*
  183. * See header file for description.
  184. */
  185. StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
  186. StackType_t * pxEndOfStack,
  187. TaskFunction_t pxCode,
  188. void * pvParameters )
  189. {
  190. Thread_t * thread;
  191. pthread_attr_t xThreadAttributes;
  192. size_t ulStackSize;
  193. int iRet;
  194. ( void ) pthread_once( &hSigSetupThread, prvSetupSignalsAndSchedulerPolicy );
  195. /*
  196. * Store the additional thread data at the start of the stack.
  197. */
  198. thread = ( Thread_t * ) ( pxTopOfStack + 1 ) - 1;
  199. pxTopOfStack = ( StackType_t * ) thread - 1;
  200. /* Ensure that there is enough space to store Thread_t on the stack. */
  201. ulStackSize = ( size_t ) ( pxTopOfStack + 1 - pxEndOfStack ) * sizeof( *pxTopOfStack );
  202. configASSERT( ulStackSize > sizeof( Thread_t ) );
  203. ( void ) ulStackSize; /* suppress set but not used warning */
  204. thread->pxCode = pxCode;
  205. thread->pvParams = pvParameters;
  206. thread->xDying = pdFALSE;
  207. pthread_attr_init( &xThreadAttributes );
  208. thread->ev = event_create();
  209. vPortEnterCritical();
  210. iRet = pthread_create( &thread->pthread, &xThreadAttributes,
  211. prvWaitForStart, thread );
  212. if( iRet != 0 )
  213. {
  214. prvFatalError( "pthread_create", iRet );
  215. }
  216. vPortExitCritical();
  217. return pxTopOfStack;
  218. }
  219. /*-----------------------------------------------------------*/
  220. void vPortStartFirstTask( void )
  221. {
  222. Thread_t * pxFirstThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  223. /* Start the first task. */
  224. prvResumeThread( pxFirstThread );
  225. }
  226. /*-----------------------------------------------------------*/
  227. /*
  228. * See header file for description.
  229. */
  230. BaseType_t xPortStartScheduler( void )
  231. {
  232. int iSignal;
  233. sigset_t xSignals;
  234. hMainThread = pthread_self();
  235. prvPortSetCurrentThreadName( "Scheduler" );
  236. /* Start the timer that generates the tick ISR(SIGALRM).
  237. * Interrupts are disabled here already. */
  238. prvSetupTimerInterrupt();
  239. /*
  240. * Block SIG_RESUME before starting any tasks so the main thread can sigwait on it.
  241. * To sigwait on an unblocked signal is undefined.
  242. * https://pubs.opengroup.org/onlinepubs/009604499/functions/sigwait.html
  243. */
  244. sigemptyset( &xSignals );
  245. sigaddset( &xSignals, SIG_RESUME );
  246. ( void ) pthread_sigmask( SIG_BLOCK, &xSignals, NULL );
  247. /* Start the first task. */
  248. vPortStartFirstTask();
  249. /* Wait until signaled by vPortEndScheduler(). */
  250. while( xSchedulerEnd != pdTRUE )
  251. {
  252. sigwait( &xSignals, &iSignal );
  253. }
  254. /*
  255. * clear out the variable that is used to end the scheduler, otherwise
  256. * subsequent scheduler restarts will end immediately.
  257. */
  258. xSchedulerEnd = pdFALSE;
  259. /* Reset pthread_once_t, needed to restart the scheduler again.
  260. * memset the internal struct members for MacOS/Linux Compatibility */
  261. #if __APPLE__
  262. hSigSetupThread.__sig = _PTHREAD_ONCE_SIG_init;
  263. hThreadKeyOnce.__sig = _PTHREAD_ONCE_SIG_init;
  264. memset( ( void * ) &hSigSetupThread.__opaque, 0, sizeof( hSigSetupThread.__opaque ) );
  265. memset( ( void * ) &hThreadKeyOnce.__opaque, 0, sizeof( hThreadKeyOnce.__opaque ) );
  266. #else /* Linux PTHREAD library*/
  267. hSigSetupThread = ( pthread_once_t ) PTHREAD_ONCE_INIT;
  268. hThreadKeyOnce = ( pthread_once_t ) PTHREAD_ONCE_INIT;
  269. #endif /* __APPLE__*/
  270. /* Restore original signal mask. */
  271. ( void ) pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask, NULL );
  272. return 0;
  273. }
  274. /*-----------------------------------------------------------*/
  275. void vPortEndScheduler( void )
  276. {
  277. Thread_t * pxCurrentThread;
  278. BaseType_t xIsFreeRTOSThread;
  279. /* Stop the timer tick thread. */
  280. xTimerTickThreadShouldRun = false;
  281. pthread_join( hTimerTickThread, NULL );
  282. /* Check whether the current thread is a FreeRTOS thread.
  283. * This has to happen before the scheduler is signaled to exit
  284. * its loop to prevent data races on the thread key. */
  285. xIsFreeRTOSThread = prvIsFreeRTOSThread();
  286. /* Signal the scheduler to exit its loop. */
  287. xSchedulerEnd = pdTRUE;
  288. ( void ) pthread_kill( hMainThread, SIG_RESUME );
  289. /* Waiting to be deleted here. */
  290. if( xIsFreeRTOSThread == pdTRUE )
  291. {
  292. pxCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  293. event_wait( pxCurrentThread->ev );
  294. }
  295. pthread_testcancel();
  296. }
  297. /*-----------------------------------------------------------*/
  298. void vPortEnterCritical( void )
  299. {
  300. if( uxCriticalNesting == 0 )
  301. {
  302. vPortDisableInterrupts();
  303. }
  304. uxCriticalNesting++;
  305. }
  306. /*-----------------------------------------------------------*/
  307. void vPortExitCritical( void )
  308. {
  309. uxCriticalNesting--;
  310. /* If we have reached 0 then re-enable the interrupts. */
  311. if( uxCriticalNesting == 0 )
  312. {
  313. vPortEnableInterrupts();
  314. }
  315. }
  316. /*-----------------------------------------------------------*/
  317. static void prvPortYieldFromISR( void )
  318. {
  319. Thread_t * xThreadToSuspend;
  320. Thread_t * xThreadToResume;
  321. xThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  322. vTaskSwitchContext();
  323. xThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  324. prvSwitchThread( xThreadToResume, xThreadToSuspend );
  325. }
  326. /*-----------------------------------------------------------*/
  327. void vPortYield( void )
  328. {
  329. /* This must never be called from outside of a FreeRTOS-owned thread, or
  330. * the thread could get stuck in a suspended state. */
  331. configASSERT( prvIsFreeRTOSThread() == pdTRUE );
  332. vPortEnterCritical();
  333. prvPortYieldFromISR();
  334. vPortExitCritical();
  335. }
  336. /*-----------------------------------------------------------*/
  337. void vPortDisableInterrupts( void )
  338. {
  339. if( prvIsFreeRTOSThread() == pdTRUE )
  340. {
  341. pthread_sigmask( SIG_BLOCK, &xAllSignals, NULL );
  342. }
  343. }
  344. /*-----------------------------------------------------------*/
  345. void vPortEnableInterrupts( void )
  346. {
  347. if( prvIsFreeRTOSThread() == pdTRUE )
  348. {
  349. pthread_sigmask( SIG_UNBLOCK, &xAllSignals, NULL );
  350. }
  351. }
  352. /*-----------------------------------------------------------*/
  353. UBaseType_t xPortSetInterruptMask( void )
  354. {
  355. /* Interrupts are always disabled inside ISRs (signals
  356. * handlers). */
  357. return ( UBaseType_t ) 0;
  358. }
  359. /*-----------------------------------------------------------*/
  360. void vPortClearInterruptMask( UBaseType_t uxMask )
  361. {
  362. ( void ) uxMask;
  363. }
  364. /*-----------------------------------------------------------*/
  365. static uint64_t prvGetTimeNs( void )
  366. {
  367. struct timespec t;
  368. clock_gettime( CLOCK_MONOTONIC, &t );
  369. return ( uint64_t ) t.tv_sec * ( uint64_t ) 1000000000UL + ( uint64_t ) t.tv_nsec;
  370. }
  371. /*-----------------------------------------------------------*/
  372. /* commented as part of the code below in vPortSystemTickHandler,
  373. * to adjust timing according to full demo requirements */
  374. /* static uint64_t prvTickCount; */
  375. static void * prvTimerTickHandler( void * arg )
  376. {
  377. ( void ) arg;
  378. prvMarkAsFreeRTOSThread();
  379. prvPortSetCurrentThreadName( "Scheduler timer" );
  380. while( xTimerTickThreadShouldRun )
  381. {
  382. /*
  383. * signal to the active task to cause tick handling or
  384. * preemption (if enabled)
  385. */
  386. Thread_t * thread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  387. pthread_kill( thread->pthread, SIGALRM );
  388. usleep( portTICK_RATE_MICROSECONDS );
  389. }
  390. return NULL;
  391. }
  392. /*-----------------------------------------------------------*/
  393. /*
  394. * Setup the systick timer to generate the tick interrupts at the required
  395. * frequency.
  396. */
  397. void prvSetupTimerInterrupt( void )
  398. {
  399. xTimerTickThreadShouldRun = true;
  400. pthread_create( &hTimerTickThread, NULL, prvTimerTickHandler, NULL );
  401. prvStartTimeNs = prvGetTimeNs();
  402. }
  403. /*-----------------------------------------------------------*/
  404. static void vPortSystemTickHandler( int sig )
  405. {
  406. if( prvIsFreeRTOSThread() == pdTRUE )
  407. {
  408. Thread_t * pxThreadToSuspend;
  409. Thread_t * pxThreadToResume;
  410. ( void ) sig;
  411. uxCriticalNesting++; /* Signals are blocked in this signal handler. */
  412. pxThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  413. if( xTaskIncrementTick() != pdFALSE )
  414. {
  415. /* Select Next Task. */
  416. vTaskSwitchContext();
  417. pxThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
  418. prvSwitchThread( pxThreadToResume, pxThreadToSuspend );
  419. }
  420. uxCriticalNesting--;
  421. }
  422. else
  423. {
  424. fprintf( stderr, "vPortSystemTickHandler called from non-FreeRTOS thread\n" );
  425. }
  426. }
  427. /*-----------------------------------------------------------*/
  428. void vPortThreadDying( void * pxTaskToDelete,
  429. volatile BaseType_t * pxPendYield )
  430. {
  431. Thread_t * pxThread = prvGetThreadFromTask( pxTaskToDelete );
  432. ( void ) pxPendYield;
  433. pxThread->xDying = pdTRUE;
  434. }
  435. /*-----------------------------------------------------------*/
  436. void vPortCancelThread( void * pxTaskToDelete )
  437. {
  438. Thread_t * pxThreadToCancel = prvGetThreadFromTask( pxTaskToDelete );
  439. /*
  440. * The thread has already been suspended so it can be safely cancelled.
  441. */
  442. pthread_cancel( pxThreadToCancel->pthread );
  443. event_signal( pxThreadToCancel->ev );
  444. pthread_join( pxThreadToCancel->pthread, NULL );
  445. event_delete( pxThreadToCancel->ev );
  446. }
  447. /*-----------------------------------------------------------*/
  448. static void * prvWaitForStart( void * pvParams )
  449. {
  450. Thread_t * pxThread = pvParams;
  451. prvMarkAsFreeRTOSThread();
  452. prvSuspendSelf( pxThread );
  453. /* Resumed for the first time, unblocks all signals. */
  454. uxCriticalNesting = 0;
  455. vPortEnableInterrupts();
  456. /* Set thread name */
  457. prvPortSetCurrentThreadName( pcTaskGetName( xTaskGetCurrentTaskHandle() ) );
  458. /* Call the task's entry point. */
  459. pxThread->pxCode( pxThread->pvParams );
  460. /* A function that implements a task must not exit or attempt to return to
  461. * its caller as there is nothing to return to. If a task wants to exit it
  462. * should instead call vTaskDelete( NULL ). Artificially force an assert()
  463. * to be triggered if configASSERT() is defined, so application writers can
  464. * catch the error. */
  465. configASSERT( pdFALSE );
  466. return NULL;
  467. }
  468. /*-----------------------------------------------------------*/
  469. static void prvSwitchThread( Thread_t * pxThreadToResume,
  470. Thread_t * pxThreadToSuspend )
  471. {
  472. BaseType_t uxSavedCriticalNesting;
  473. if( pxThreadToSuspend != pxThreadToResume )
  474. {
  475. /*
  476. * Switch tasks.
  477. *
  478. * The critical section nesting is per-task, so save it on the
  479. * stack of the current (suspending thread), restoring it when
  480. * we switch back to this task.
  481. */
  482. uxSavedCriticalNesting = uxCriticalNesting;
  483. prvResumeThread( pxThreadToResume );
  484. if( pxThreadToSuspend->xDying == pdTRUE )
  485. {
  486. pthread_exit( NULL );
  487. }
  488. prvSuspendSelf( pxThreadToSuspend );
  489. uxCriticalNesting = uxSavedCriticalNesting;
  490. }
  491. }
  492. /*-----------------------------------------------------------*/
  493. static void prvSuspendSelf( Thread_t * thread )
  494. {
  495. /*
  496. * Suspend this thread by waiting for a pthread_cond_signal event.
  497. *
  498. * A suspended thread must not handle signals (interrupts) so
  499. * all signals must be blocked by calling this from:
  500. *
  501. * - Inside a critical section (vPortEnterCritical() /
  502. * vPortExitCritical()).
  503. *
  504. * - From a signal handler that has all signals masked.
  505. *
  506. * - A thread with all signals blocked with pthread_sigmask().
  507. */
  508. event_wait( thread->ev );
  509. pthread_testcancel();
  510. }
  511. /*-----------------------------------------------------------*/
  512. static void prvResumeThread( Thread_t * xThreadId )
  513. {
  514. if( pthread_self() != xThreadId->pthread )
  515. {
  516. event_signal( xThreadId->ev );
  517. }
  518. }
  519. /*-----------------------------------------------------------*/
  520. static void prvSetupSignalsAndSchedulerPolicy( void )
  521. {
  522. struct sigaction sigtick;
  523. int iRet;
  524. hMainThread = pthread_self();
  525. /* Initialise common signal masks. */
  526. sigfillset( &xAllSignals );
  527. /* Don't block SIGINT so this can be used to break into GDB while
  528. * in a critical section. */
  529. sigdelset( &xAllSignals, SIGINT );
  530. /*
  531. * Block all signals in this thread so all new threads
  532. * inherits this mask.
  533. *
  534. * When a thread is resumed for the first time, all signals
  535. * will be unblocked.
  536. */
  537. ( void ) pthread_sigmask( SIG_SETMASK,
  538. &xAllSignals,
  539. &xSchedulerOriginalSignalMask );
  540. sigtick.sa_flags = 0;
  541. sigtick.sa_handler = vPortSystemTickHandler;
  542. sigfillset( &sigtick.sa_mask );
  543. iRet = sigaction( SIGALRM, &sigtick, NULL );
  544. if( iRet == -1 )
  545. {
  546. prvFatalError( "sigaction", errno );
  547. }
  548. }
  549. /*-----------------------------------------------------------*/
  550. uint32_t ulPortGetRunTime( void )
  551. {
  552. struct tms xTimes;
  553. times( &xTimes );
  554. return ( uint32_t ) xTimes.tms_utime;
  555. }
  556. /*-----------------------------------------------------------*/