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