| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2023-10-09 03:30:04 +08:00
										 |  |  |  * FreeRTOS Kernel V10.5.1 (ESP-IDF SMP modified) | 
					
						
							|  |  |  |  * Copyright (C) 2020 Cambridge Consultants Ltd. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * SPDX-FileCopyrightText: 2020 Cambridge Consultants Ltd | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-License-Identifier: MIT | 
					
						
							| 
									
										
										
										
											2023-10-09 03:30:04 +08:00
										 |  |  |  * | 
					
						
							|  |  |  |  * SPDX-FileContributor: 2023 Espressif Systems (Shanghai) CO LTD | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Permission is hereby granted, free of charge, to any person obtaining a copy of | 
					
						
							|  |  |  |  * this software and associated documentation files (the "Software"), to deal in | 
					
						
							|  |  |  |  * the Software without restriction, including without limitation the rights to | 
					
						
							|  |  |  |  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | 
					
						
							|  |  |  |  * the Software, and to permit persons to whom the Software is furnished to do so, | 
					
						
							|  |  |  |  * subject to the following conditions: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The above copyright notice and this permission notice shall be included in all | 
					
						
							|  |  |  |  * copies or substantial portions of the Software. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | 
					
						
							|  |  |  |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | 
					
						
							|  |  |  |  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | 
					
						
							|  |  |  |  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | 
					
						
							|  |  |  |  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | 
					
						
							|  |  |  |  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * https://www.FreeRTOS.org
 | 
					
						
							|  |  |  |  * https://github.com/FreeRTOS
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*-----------------------------------------------------------
 | 
					
						
							|  |  |  |  * Implementation of functions defined in portable.h for the Posix port. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Each task has a pthread which eases use of standard debuggers | 
					
						
							|  |  |  |  * (allowing backtraces of tasks etc). Threads for tasks that are not | 
					
						
							|  |  |  |  * running are blocked in sigwait(). | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Task switch is done by resuming the thread for the next task by | 
					
						
							|  |  |  |  * signaling the condition variable and then waiting on a condition variable | 
					
						
							|  |  |  |  * with the current thread. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The timer interrupt uses SIGALRM and care is taken to ensure that | 
					
						
							|  |  |  |  * the signal handler runs only on the thread for the current task. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of part of the standard C library requires care as some | 
					
						
							|  |  |  |  * functions can take pthread mutexes internally which can result in | 
					
						
							|  |  |  |  * deadlocks as the FreeRTOS kernel can switch tasks while they're | 
					
						
							|  |  |  |  * holding a pthread mutex. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * stdio (printf() and friends) should be called from a single task | 
					
						
							|  |  |  |  * only or serialized with a FreeRTOS primitive such as a binary | 
					
						
							|  |  |  |  * semaphore or mutex. | 
					
						
							|  |  |  |  *----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <pthread.h>
 | 
					
						
							|  |  |  | #include <signal.h>
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <sys/time.h>
 | 
					
						
							|  |  |  | #include <sys/times.h>
 | 
					
						
							|  |  |  | #include <time.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Scheduler includes. */ | 
					
						
							|  |  |  | #include "FreeRTOS.h"
 | 
					
						
							|  |  |  | #include "task.h"
 | 
					
						
							|  |  |  | #include "timers.h"
 | 
					
						
							|  |  |  | #include "utils/wait_for_event.h"
 | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SIG_RESUME SIGUSR1
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct THREAD | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     pthread_t pthread; | 
					
						
							|  |  |  |     TaskFunction_t pxCode; | 
					
						
							|  |  |  |     void *pvParams; | 
					
						
							|  |  |  |     BaseType_t xDying; | 
					
						
							|  |  |  |     struct event *ev; | 
					
						
							|  |  |  | } Thread_t; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The additional per-thread data is stored at the beginning of the | 
					
						
							|  |  |  |  * task's stack. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static inline Thread_t *prvGetThreadFromTask(TaskHandle_t xTask) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     StackType_t *pxTopOfStack = *(StackType_t **)xTask; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return (Thread_t *)(pxTopOfStack + 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT; | 
					
						
							|  |  |  | static sigset_t xAllSignals; | 
					
						
							|  |  |  | static sigset_t xSchedulerOriginalSignalMask; | 
					
						
							|  |  |  | static pthread_t hMainThread = ( pthread_t )NULL; | 
					
						
							| 
									
										
										
										
											2023-07-31 17:10:34 +02:00
										 |  |  | static volatile BaseType_t uxCriticalNesting; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-31 17:10:34 +02:00
										 |  |  | static BaseType_t xSchedulerEnd = pdFALSE; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void prvSetupSignalsAndSchedulerPolicy( void ); | 
					
						
							|  |  |  | static void prvSetupTimerInterrupt( void ); | 
					
						
							|  |  |  | static void *prvWaitForStart( void * pvParams ); | 
					
						
							|  |  |  | static void prvSwitchThread( Thread_t * xThreadToResume, | 
					
						
							|  |  |  |                              Thread_t *xThreadToSuspend ); | 
					
						
							|  |  |  | static void prvSuspendSelf( Thread_t * thread); | 
					
						
							|  |  |  | static void prvResumeThread( Thread_t * xThreadId ); | 
					
						
							|  |  |  | static void vPortSystemTickHandler( int sig ); | 
					
						
							|  |  |  | static void vPortStartFirstTask( void ); | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void prvFatalError( const char *pcCall, int iErrno ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     fprintf( stderr, "%s: %s\n", pcCall, strerror( iErrno ) ); | 
					
						
							|  |  |  |     abort(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * See header file for description. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2023-07-31 16:59:41 +02:00
										 |  |  | StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, | 
					
						
							|  |  |  |                                     StackType_t *pxEndOfStack, | 
					
						
							|  |  |  |                                     TaskFunction_t pxCode, | 
					
						
							|  |  |  |                                     void *pvParameters ) | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     Thread_t *thread; | 
					
						
							|  |  |  |     pthread_attr_t xThreadAttributes; | 
					
						
							|  |  |  |     size_t ulStackSize; | 
					
						
							|  |  |  |     int iRet; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     (void)pthread_once( &hSigSetupThread, prvSetupSignalsAndSchedulerPolicy ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Store the additional thread data at the start of the stack. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     thread = (Thread_t *)(pxTopOfStack + 1) - 1; | 
					
						
							| 
									
										
										
										
											2023-07-31 16:59:41 +02:00
										 |  |  |     pxTopOfStack = (StackType_t *)thread - 1; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  |     ulStackSize = (pxTopOfStack + 1 - pxEndOfStack) * sizeof(*pxTopOfStack); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     thread->pxCode = pxCode; | 
					
						
							|  |  |  |     thread->pvParams = pvParameters; | 
					
						
							|  |  |  |     thread->xDying = pdFALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pthread_attr_init( &xThreadAttributes ); | 
					
						
							|  |  |  |     pthread_attr_setstack( &xThreadAttributes, pxEndOfStack, ulStackSize ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     thread->ev = event_create(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vPortEnterCritical(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     iRet = pthread_create( &thread->pthread, &xThreadAttributes, | 
					
						
							|  |  |  |                            prvWaitForStart, thread ); | 
					
						
							|  |  |  |     if ( iRet ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         prvFatalError( "pthread_create", iRet ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vPortExitCritical(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return pxTopOfStack; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortStartFirstTask( void ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     Thread_t *pxFirstThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() ); | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Start the first task. */ | 
					
						
							|  |  |  |     prvResumeThread( pxFirstThread ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * See header file for description. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2023-07-31 17:10:34 +02:00
										 |  |  | BaseType_t xPortStartScheduler( void ) | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     int iSignal; | 
					
						
							|  |  |  |     sigset_t xSignals; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     hMainThread = pthread_self(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Start the timer that generates the tick ISR(SIGALRM).
 | 
					
						
							|  |  |  |        Interrupts are disabled here already. */ | 
					
						
							|  |  |  |     prvSetupTimerInterrupt(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Start the first task. */ | 
					
						
							|  |  |  |     vPortStartFirstTask(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Wait until signaled by vPortEndScheduler(). */ | 
					
						
							|  |  |  |     sigemptyset( &xSignals ); | 
					
						
							|  |  |  |     sigaddset( &xSignals, SIG_RESUME ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     while ( !xSchedulerEnd ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         sigwait( &xSignals, &iSignal ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Cancel the Idle task and free its resources */ | 
					
						
							|  |  |  | #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
 | 
					
						
							|  |  |  |     vPortCancelThread( xTaskGetIdleTaskHandle() ); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if ( configUSE_TIMERS == 1 )
 | 
					
						
							|  |  |  |     /* Cancel the Timer task and free its resources */ | 
					
						
							|  |  |  |     vPortCancelThread( xTimerGetTimerDaemonTaskHandle() ); | 
					
						
							|  |  |  | #endif /* configUSE_TIMERS */
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Restore original signal mask. */ | 
					
						
							|  |  |  |     (void)pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask,  NULL ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortEndScheduler( void ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     struct itimerval itimer; | 
					
						
							|  |  |  |     struct sigaction sigtick; | 
					
						
							|  |  |  |     Thread_t *xCurrentThread; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Stop the timer and ignore any pending SIGALRMs that would end
 | 
					
						
							|  |  |  |      * up running on the main thread when it is resumed. */ | 
					
						
							|  |  |  |     itimer.it_value.tv_sec = 0; | 
					
						
							|  |  |  |     itimer.it_value.tv_usec = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     itimer.it_interval.tv_sec = 0; | 
					
						
							|  |  |  |     itimer.it_interval.tv_usec = 0; | 
					
						
							|  |  |  |     (void)setitimer( ITIMER_REAL, &itimer, NULL ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sigtick.sa_flags = 0; | 
					
						
							|  |  |  |     sigtick.sa_handler = SIG_IGN; | 
					
						
							|  |  |  |     sigemptyset( &sigtick.sa_mask ); | 
					
						
							|  |  |  |     sigaction( SIGALRM, &sigtick, NULL ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Signal the scheduler to exit its loop. */ | 
					
						
							|  |  |  |     xSchedulerEnd = pdTRUE; | 
					
						
							|  |  |  |     (void)pthread_kill( hMainThread, SIG_RESUME ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     xCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() ); | 
					
						
							|  |  |  |     prvSuspendSelf(xCurrentThread); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortEnterCritical( void ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if ( uxCriticalNesting == 0 ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         vPortDisableInterrupts(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     uxCriticalNesting++; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortExitCritical( void ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uxCriticalNesting--; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* If we have reached 0 then re-enable the interrupts. */ | 
					
						
							|  |  |  |     if( uxCriticalNesting == 0 ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         vPortEnableInterrupts(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortYieldFromISR( void ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     Thread_t *xThreadToSuspend; | 
					
						
							|  |  |  |     Thread_t *xThreadToResume; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     xThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vTaskSwitchContext(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     xThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     prvSwitchThread( xThreadToResume, xThreadToSuspend ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortYield( void ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     vPortEnterCritical(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vPortYieldFromISR(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     vPortExitCritical(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortDisableInterrupts( void ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     pthread_sigmask( SIG_BLOCK, &xAllSignals, NULL ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortEnableInterrupts( void ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     pthread_sigmask( SIG_UNBLOCK, &xAllSignals, NULL ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-31 17:10:34 +02:00
										 |  |  | BaseType_t xPortSetInterruptMask( void ) | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     /* Interrupts are always disabled inside ISRs (signals
 | 
					
						
							|  |  |  |        handlers). */ | 
					
						
							|  |  |  |     return pdTRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-31 17:10:34 +02:00
										 |  |  | void vPortClearInterruptMask( BaseType_t xMask ) | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t prvGetTimeNs(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     struct timespec t; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     clock_gettime(CLOCK_MONOTONIC, &t); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return t.tv_sec * 1000000000ull + t.tv_nsec; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t prvStartTimeNs; | 
					
						
							|  |  |  | /* commented as part of the code below in vPortSystemTickHandler,
 | 
					
						
							|  |  |  |  * to adjust timing according to full demo requirements */ | 
					
						
							|  |  |  | /* static uint64_t prvTickCount; */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Setup the systick timer to generate the tick interrupts at the required | 
					
						
							|  |  |  |  * frequency. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void prvSetupTimerInterrupt( void ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     struct itimerval itimer; | 
					
						
							|  |  |  |     int iRet; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Initialise the structure with the current timer information. */ | 
					
						
							|  |  |  |     iRet = getitimer( ITIMER_REAL, &itimer ); | 
					
						
							|  |  |  |     if ( iRet ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         prvFatalError( "getitimer", errno ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Set the interval between timer events. */ | 
					
						
							|  |  |  |     itimer.it_interval.tv_sec = 0; | 
					
						
							|  |  |  |     itimer.it_interval.tv_usec = portTICK_RATE_MICROSECONDS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Set the current count-down. */ | 
					
						
							|  |  |  |     itimer.it_value.tv_sec = 0; | 
					
						
							|  |  |  |     itimer.it_value.tv_usec = portTICK_RATE_MICROSECONDS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Set-up the timer interrupt. */ | 
					
						
							|  |  |  |     iRet = setitimer( ITIMER_REAL, &itimer, NULL ); | 
					
						
							|  |  |  |     if ( iRet ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         prvFatalError( "setitimer", errno ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     prvStartTimeNs = prvGetTimeNs(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void vPortSystemTickHandler( int sig ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     Thread_t *pxThreadToSuspend; | 
					
						
							|  |  |  |     Thread_t *pxThreadToResume; | 
					
						
							|  |  |  |     /* uint64_t xExpectedTicks; */ | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     uxCriticalNesting++; /* Signals are blocked in this signal handler. */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if ( configUSE_PREEMPTION == 1 )
 | 
					
						
							|  |  |  |     pxThreadToSuspend = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() ); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Tick Increment, accounting for any lost signals or drift in
 | 
					
						
							|  |  |  |      * the timer. */ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  *      Comment code to adjust timing according to full demo requirements | 
					
						
							|  |  |  |  *      xExpectedTicks = (prvGetTimeNs() - prvStartTimeNs) | 
					
						
							|  |  |  |  *        / (portTICK_RATE_MICROSECONDS * 1000); | 
					
						
							|  |  |  |  * do { */ | 
					
						
							|  |  |  |         xTaskIncrementTick(); | 
					
						
							|  |  |  | /*        prvTickCount++;
 | 
					
						
							|  |  |  |  *    } while (prvTickCount < xExpectedTicks); | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if ( configUSE_PREEMPTION == 1 )
 | 
					
						
							|  |  |  |     /* Select Next Task. */ | 
					
						
							|  |  |  |     vTaskSwitchContext(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     pxThreadToResume = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     prvSwitchThread(pxThreadToResume, pxThreadToSuspend); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     uxCriticalNesting--; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortThreadDying( void *pxTaskToDelete, volatile BaseType_t *pxPendYield ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     Thread_t *pxThread = prvGetThreadFromTask( pxTaskToDelete ); | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     pxThread->xDying = pdTRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void vPortCancelThread( void *pxTaskToDelete ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     Thread_t *pxThreadToCancel = prvGetThreadFromTask( pxTaskToDelete ); | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * The thread has already been suspended so it can be safely cancelled. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     pthread_cancel( pxThreadToCancel->pthread ); | 
					
						
							|  |  |  |     pthread_join( pxThreadToCancel->pthread, NULL ); | 
					
						
							|  |  |  |     event_delete( pxThreadToCancel->ev ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void *prvWaitForStart( void * pvParams ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     Thread_t *pxThread = pvParams; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     prvSuspendSelf(pxThread); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Resumed for the first time, unblocks all signals. */ | 
					
						
							|  |  |  |     uxCriticalNesting = 0; | 
					
						
							|  |  |  |     vPortEnableInterrupts(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Call the task's entry point. */ | 
					
						
							|  |  |  |     pxThread->pxCode( pxThread->pvParams ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* A function that implements a task must not exit or attempt to return to
 | 
					
						
							|  |  |  |     * its caller as there is nothing to return to. If a task wants to exit it | 
					
						
							|  |  |  |     * should instead call vTaskDelete( NULL ). Artificially force an assert() | 
					
						
							|  |  |  |     * to be triggered if configASSERT() is defined, so application writers can | 
					
						
							|  |  |  |         * catch the error. */ | 
					
						
							|  |  |  |     configASSERT( pdFALSE ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void prvSwitchThread( Thread_t *pxThreadToResume, | 
					
						
							|  |  |  |                              Thread_t *pxThreadToSuspend ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     BaseType_t uxSavedCriticalNesting; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if ( pxThreadToSuspend != pxThreadToResume ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * Switch tasks. | 
					
						
							|  |  |  |          * | 
					
						
							|  |  |  |          * The critical section nesting is per-task, so save it on the | 
					
						
							|  |  |  |          * stack of the current (suspending thread), restoring it when | 
					
						
							|  |  |  |          * we switch back to this task. | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  |         uxSavedCriticalNesting = uxCriticalNesting; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         prvResumeThread( pxThreadToResume ); | 
					
						
							|  |  |  |         if ( pxThreadToSuspend->xDying ) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             pthread_exit( NULL ); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         prvSuspendSelf( pxThreadToSuspend ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         uxCriticalNesting = uxSavedCriticalNesting; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void prvSuspendSelf( Thread_t *thread ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Suspend this thread by waiting for a pthread_cond_signal event. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * A suspended thread must not handle signals (interrupts) so | 
					
						
							|  |  |  |      * all signals must be blocked by calling this from: | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * - Inside a critical section (vPortEnterCritical() / | 
					
						
							|  |  |  |      *   vPortExitCritical()). | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * - From a signal handler that has all signals masked. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * - A thread with all signals blocked with pthread_sigmask(). | 
					
						
							|  |  |  |         */ | 
					
						
							|  |  |  |     event_wait(thread->ev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void prvResumeThread( Thread_t *xThreadId ) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if ( pthread_self() != xThreadId->pthread ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         event_signal(xThreadId->ev); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void prvSetupSignalsAndSchedulerPolicy( void ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     struct sigaction sigresume, sigtick; | 
					
						
							|  |  |  |     int iRet; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     hMainThread = pthread_self(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Initialise common signal masks. */ | 
					
						
							|  |  |  |     sigfillset( &xAllSignals ); | 
					
						
							|  |  |  |     /* Don't block SIGINT so this can be used to break into GDB while
 | 
					
						
							|  |  |  |      * in a critical section. */ | 
					
						
							|  |  |  |     sigdelset( &xAllSignals, SIGINT ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Block all signals in this thread so all new threads | 
					
						
							|  |  |  |      * inherits this mask. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * When a thread is resumed for the first time, all signals | 
					
						
							|  |  |  |      * will be unblocked. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     (void)pthread_sigmask( SIG_SETMASK, &xAllSignals, | 
					
						
							|  |  |  |                            &xSchedulerOriginalSignalMask ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* SIG_RESUME is only used with sigwait() so doesn't need a
 | 
					
						
							|  |  |  |        handler. */ | 
					
						
							|  |  |  |     sigresume.sa_flags = 0; | 
					
						
							|  |  |  |     sigresume.sa_handler = SIG_IGN; | 
					
						
							|  |  |  |     sigfillset( &sigresume.sa_mask ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     sigtick.sa_flags = 0; | 
					
						
							|  |  |  |     sigtick.sa_handler = vPortSystemTickHandler; | 
					
						
							|  |  |  |     sigfillset( &sigtick.sa_mask ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     iRet = sigaction( SIG_RESUME, &sigresume, NULL ); | 
					
						
							|  |  |  |     if ( iRet ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         prvFatalError( "sigaction", errno ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     iRet = sigaction( SIGALRM, &sigtick, NULL ); | 
					
						
							|  |  |  |     if ( iRet ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         prvFatalError( "sigaction", errno ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned long ulPortGetRunTime( void ) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2022-12-29 12:03:08 +08:00
										 |  |  |     struct tms xTimes; | 
					
						
							| 
									
										
										
										
											2022-09-06 16:09:23 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     times( &xTimes ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return ( unsigned long ) xTimes.tms_utime; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*-----------------------------------------------------------*/ |