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