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