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