Skip to content

Commit ad0ea34

Browse files
authored
FreeRTOS threads improvement (#1092)
1 parent 5a342d6 commit ad0ea34

File tree

7 files changed

+746
-49
lines changed

7 files changed

+746
-49
lines changed

lib/Simulator/native.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -312,16 +312,6 @@ auto main(int argc, char *argv[]) -> int {
312312
// Pre-initialize PreferencesStore to point to simprefs.ini
313313
prefs.begin("simprefs.ini");
314314

315-
// The FreeRTOS tick handler happens via SIGALRM, and it also kicks off preemptive task
316-
// switching, which is not what we want on the main thread, since it's not a real FreeRTOS task.
317-
// Just disable SIGALRM on this thread so that it only happens on FreeRTOS tasks.
318-
sigset_t mask;
319-
sigemptyset(&mask);
320-
sigaddset(&mask, SIGALRM);
321-
pthread_sigmask(SIG_BLOCK, &mask, NULL);
322-
323-
vPortSetExternalThread(pthread_self());
324-
325315
// Start the FreeRTOS scheduler
326316
std::thread schedulerThread([]() {
327317
// ESP-IDF does `app_main` in a task as well. We need to do this so we can use

lib/Simulator/stubs/freertos-posix/freertos/portmacro.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ extern void vPortYield( void );
8686
/*-----------------------------------------------------------*/
8787

8888
/* Critical section management. */
89-
extern void vPortSetExternalThread( pthread_t externalThread );
9089
extern void vPortDisableInterrupts( void );
9190
extern void vPortEnableInterrupts( void );
9291
#define portSET_INTERRUPT_MASK() ( vPortDisableInterrupts() )

lib/Simulator/stubs/freertos-posix/src/Source/portable/ThirdParty/GCC/Posix/port.c

Lines changed: 72 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,15 @@ static inline Thread_t * prvGetThreadFromTask( TaskHandle_t xTask )
102102

103103
static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT;
104104
static sigset_t xAllSignals;
105-
pthread_t xExternalThread;
106105
static sigset_t xSchedulerOriginalSignalMask;
107106
static pthread_t hMainThread = ( pthread_t ) NULL;
108107
static volatile BaseType_t uxCriticalNesting;
109108
static BaseType_t xSchedulerEnd = pdFALSE;
110109
static pthread_t hTimerTickThread;
111110
static bool xTimerTickThreadShouldRun;
112111
static uint64_t prvStartTimeNs;
112+
static pthread_mutex_t xThreadMutex = PTHREAD_MUTEX_INITIALIZER;
113+
static pthread_key_t xThreadKey = 0;
113114
/*-----------------------------------------------------------*/
114115

115116
static void prvSetupSignalsAndSchedulerPolicy( void );
@@ -124,6 +125,44 @@ static void vPortStartFirstTask( void );
124125
static void prvPortYieldFromISR( void );
125126
/*-----------------------------------------------------------*/
126127

128+
void prvThreadKeyDestructor( void * data )
129+
{
130+
free( data );
131+
}
132+
133+
static void prvInitThreadKey()
134+
{
135+
pthread_mutex_lock( &xThreadMutex );
136+
137+
if( xThreadKey == 0 )
138+
{
139+
pthread_key_create( &xThreadKey, prvThreadKeyDestructor );
140+
}
141+
142+
pthread_mutex_unlock( &xThreadMutex );
143+
}
144+
145+
static void prvMarkAsFreeRTOSThread( pthread_t thread )
146+
{
147+
prvInitThreadKey();
148+
uint8_t * thread_data = malloc( 1 );
149+
*thread_data = 1;
150+
pthread_setspecific( xThreadKey, thread_data );
151+
}
152+
153+
static BaseType_t prvIsFreeRTOSThread( pthread_t thread )
154+
{
155+
uint8_t * thread_data = ( uint8_t * ) pthread_getspecific( xThreadKey );
156+
157+
return thread_data != NULL && *thread_data == 1;
158+
}
159+
160+
static void prvDestroyThreadKey()
161+
{
162+
pthread_key_delete( xThreadKey );
163+
}
164+
/*-----------------------------------------------------------*/
165+
127166
static void prvFatalError( const char * pcCall,
128167
int iErrno ) __attribute__( ( __noreturn__ ) );
129168

@@ -206,24 +245,27 @@ void vPortStartFirstTask( void )
206245
/*
207246
* Clear a signal that is pending for the calling thread.
208247
*/
209-
void prvClearPendingSignal( int sig ) {
248+
void prvClearPendingSignal( int sig )
249+
{
210250
sigset_t set, oldset;
211251

212252
/* Block the signal */
213-
sigemptyset(&set);
214-
sigaddset(&set, sig);
215-
pthread_sigmask(SIG_BLOCK, &set, &oldset);
253+
sigemptyset( &set );
254+
sigaddset( &set, sig );
255+
pthread_sigmask( SIG_BLOCK, &set, &oldset );
216256

217257
/* Check if signal is pending */
218-
sigpending(&set);
219-
if (sigismember(&set, sig)) {
258+
sigpending( &set );
259+
260+
if( sigismember( &set, sig ) )
261+
{
220262
int signum;
221263
/* Wait for and remove signal */
222-
sigwait(&set, &signum);
264+
sigwait( &set, &signum );
223265
}
224266

225267
/* Restore the original signal mask */
226-
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
268+
pthread_sigmask( SIG_SETMASK, &oldset, NULL );
227269
}
228270
/*-----------------------------------------------------------*/
229271

@@ -267,7 +309,7 @@ BaseType_t xPortStartScheduler( void )
267309
xSchedulerEnd = pdFALSE;
268310

269311
/* Reset pthread_once_t, needed to restart the scheduler again.
270-
* memset the internal struct members for MacOS/Linux Compatability */
312+
* memset the internal struct members for MacOS/Linux Compatibility */
271313
#if __APPLE__
272314
hSigSetupThread.__sig = _PTHREAD_ONCE_SIG_init;
273315
memset( ( void * ) &hSigSetupThread.__opaque, 0, sizeof(hSigSetupThread.__opaque));
@@ -281,6 +323,8 @@ BaseType_t xPortStartScheduler( void )
281323
/* Restore original signal mask. */
282324
( void ) pthread_sigmask( SIG_SETMASK, &xSchedulerOriginalSignalMask, NULL );
283325

326+
prvDestroyThreadKey();
327+
284328
return 0;
285329
}
286330
/*-----------------------------------------------------------*/
@@ -298,10 +342,12 @@ void vPortEndScheduler( void )
298342
( void ) pthread_kill( hMainThread, SIG_RESUME );
299343

300344
/* Waiting to be deleted here. */
301-
if ( xExternalThread != pthread_self() ) {
345+
if( prvIsFreeRTOSThread( pthread_self() ) == pdTRUE )
346+
{
302347
pxCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
303348
event_wait( pxCurrentThread->ev );
304349
}
350+
305351
pthread_testcancel();
306352
}
307353
/*-----------------------------------------------------------*/
@@ -354,21 +400,20 @@ void vPortYield( void )
354400
}
355401
/*-----------------------------------------------------------*/
356402

357-
void vPortSetExternalThread(pthread_t externalThread) {
358-
xExternalThread = externalThread;
359-
}
360-
/*-----------------------------------------------------------*/
361-
362-
void vPortDisableInterrupts(void) {
363-
if (pthread_self() == xExternalThread) {
403+
void vPortDisableInterrupts( void )
404+
{
405+
if( prvIsFreeRTOSThread( pthread_self() ) == pdFALSE )
406+
{
364407
return;
365408
}
366409
pthread_sigmask(SIG_BLOCK, &xAllSignals, NULL);
367410
}
368411
/*-----------------------------------------------------------*/
369412

370-
void vPortEnableInterrupts(void) {
371-
if (pthread_self() == xExternalThread) {
413+
void vPortEnableInterrupts( void )
414+
{
415+
if( prvIsFreeRTOSThread( pthread_self() ) == pdFALSE )
416+
{
372417
return;
373418
}
374419
pthread_sigmask(SIG_UNBLOCK, &xAllSignals, NULL);
@@ -407,6 +452,8 @@ static void * prvTimerTickHandler( void * arg )
407452
{
408453
( void ) arg;
409454

455+
prvMarkAsFreeRTOSThread( pthread_self() );
456+
410457
prvPortSetCurrentThreadName("Scheduler timer");
411458

412459
while( xTimerTickThreadShouldRun )
@@ -439,8 +486,9 @@ void prvSetupTimerInterrupt( void )
439486

440487
static void vPortSystemTickHandler( int sig )
441488
{
442-
if (pthread_self() == xExternalThread) {
443-
fprintf(stderr, "vPortSystemTickHandler called from non-FreeRTOS thread\n");
489+
if( prvIsFreeRTOSThread( pthread_self() ) == pdFALSE )
490+
{
491+
fprintf( stderr, "vPortSystemTickHandler called from non-FreeRTOS thread\n" );
444492
return;
445493
}
446494

@@ -496,6 +544,8 @@ static void * prvWaitForStart( void * pvParams )
496544
{
497545
Thread_t * pxThread = pvParams;
498546

547+
prvMarkAsFreeRTOSThread( pthread_self() );
548+
499549
prvSuspendSelf( pxThread );
500550

501551
/* Resumed for the first time, unblocks all signals. */

lib/Simulator/stubs/freertos-posix/src/Source/portable/ThirdParty/GCC/Posix/portmacro.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ extern void vPortCancelThread( void * pxTaskToDelete );
135135
* are always a full memory barrier. ISRs are emulated as signals
136136
* which also imply a full memory barrier.
137137
*
138-
* Thus, only a compilier barrier is needed to prevent the compiler
138+
* Thus, only a compiler barrier is needed to prevent the compiler
139139
* reordering.
140140
*/
141141
#define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )

0 commit comments

Comments
 (0)