Skip to content

Commit ad4e723

Browse files
authored
Mark mutex as robust to prevent deadlocks (FreeRTOS#1233)
Mark mutex as robust to prevent deadlocks Prevent application hangs that occur when a thread dies while holding a mutex, particularly during vTaskEndScheduler or exit calls. This is achieved by setting the PTHREAD_MUTEX_ROBUST attribute on the mutex. Fixes: - GitHub issue: FreeRTOS#1217 - Forum thread: freertos.org/t/22287 Signed-off-by: Gaurav Aggarwal <[email protected]>
1 parent f94bc89 commit ad4e723

File tree

2 files changed

+79
-25
lines changed

2 files changed

+79
-25
lines changed

portable/ThirdParty/GCC/Posix/port.c

+44-21
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,20 @@ static void prvResumeThread( Thread_t * xThreadId );
119119
static void vPortSystemTickHandler( int sig );
120120
static void vPortStartFirstTask( void );
121121
static void prvPortYieldFromISR( void );
122+
static void prvThreadKeyDestructor( void * pvData );
123+
static void prvInitThreadKey( void );
124+
static void prvMarkAsFreeRTOSThread( void );
125+
static BaseType_t prvIsFreeRTOSThread( void );
126+
static void prvDestroyThreadKey( void );
122127
/*-----------------------------------------------------------*/
123128

124-
void prvThreadKeyDestructor( void * data )
129+
static void prvThreadKeyDestructor( void * pvData )
125130
{
126-
free( data );
131+
free( pvData );
127132
}
133+
/*-----------------------------------------------------------*/
128134

129-
static void prvInitThreadKey()
135+
static void prvInitThreadKey( void )
130136
{
131137
pthread_mutex_lock( &xThreadMutex );
132138

@@ -137,24 +143,39 @@ static void prvInitThreadKey()
137143

138144
pthread_mutex_unlock( &xThreadMutex );
139145
}
146+
/*-----------------------------------------------------------*/
140147

141-
static void prvMarkAsFreeRTOSThread( pthread_t thread )
148+
static void prvMarkAsFreeRTOSThread( void )
142149
{
150+
uint8_t * pucThreadData = NULL;
151+
143152
prvInitThreadKey();
144-
uint8_t * thread_data = malloc( 1 );
145-
configASSERT( thread_data != NULL );
146-
*thread_data = 1;
147-
pthread_setspecific( xThreadKey, thread_data );
153+
154+
pucThreadData = malloc( 1 );
155+
configASSERT( pucThreadData != NULL );
156+
157+
*pucThreadData = 1;
158+
159+
pthread_setspecific( xThreadKey, pucThreadData );
148160
}
161+
/*-----------------------------------------------------------*/
149162

150-
static BaseType_t prvIsFreeRTOSThread( pthread_t thread )
163+
static BaseType_t prvIsFreeRTOSThread( void )
151164
{
152-
uint8_t * thread_data = ( uint8_t * ) pthread_getspecific( xThreadKey );
165+
uint8_t * pucThreadData = NULL;
166+
BaseType_t xRet = pdFALSE;
153167

154-
return thread_data != NULL && *thread_data == 1;
168+
pucThreadData = ( uint8_t * ) pthread_getspecific( xThreadKey );
169+
if( ( pucThreadData != NULL ) && ( *pucThreadData == 1 ) )
170+
{
171+
xRet = pdTRUE;
172+
}
173+
174+
return xRet;
155175
}
176+
/*-----------------------------------------------------------*/
156177

157-
static void prvDestroyThreadKey()
178+
static void prvDestroyThreadKey( void )
158179
{
159180
pthread_key_delete( xThreadKey );
160181
}
@@ -309,7 +330,7 @@ void vPortEndScheduler( void )
309330
( void ) pthread_kill( hMainThread, SIG_RESUME );
310331

311332
/* Waiting to be deleted here. */
312-
if( prvIsFreeRTOSThread( pthread_self() ) == pdTRUE )
333+
if( prvIsFreeRTOSThread() == pdTRUE )
313334
{
314335
pxCurrentThread = prvGetThreadFromTask( xTaskGetCurrentTaskHandle() );
315336
event_wait( pxCurrentThread->ev );
@@ -369,7 +390,7 @@ void vPortYield( void )
369390

370391
void vPortDisableInterrupts( void )
371392
{
372-
if( prvIsFreeRTOSThread( pthread_self() ) == pdTRUE )
393+
if( prvIsFreeRTOSThread() == pdTRUE )
373394
{
374395
pthread_sigmask(SIG_BLOCK, &xAllSignals, NULL);
375396
}
@@ -378,9 +399,9 @@ void vPortDisableInterrupts( void )
378399

379400
void vPortEnableInterrupts( void )
380401
{
381-
if( prvIsFreeRTOSThread( pthread_self() ) == pdTRUE )
402+
if( prvIsFreeRTOSThread() == pdTRUE )
382403
{
383-
pthread_sigmask(SIG_UNBLOCK, &xAllSignals, NULL);
404+
pthread_sigmask( SIG_UNBLOCK, &xAllSignals, NULL );
384405
}
385406
}
386407
/*-----------------------------------------------------------*/
@@ -417,9 +438,9 @@ static void * prvTimerTickHandler( void * arg )
417438
{
418439
( void ) arg;
419440

420-
prvMarkAsFreeRTOSThread( pthread_self() );
441+
prvMarkAsFreeRTOSThread();
421442

422-
prvPortSetCurrentThreadName("Scheduler timer");
443+
prvPortSetCurrentThreadName( "Scheduler timer" );
423444

424445
while( xTimerTickThreadShouldRun )
425446
{
@@ -451,7 +472,7 @@ void prvSetupTimerInterrupt( void )
451472

452473
static void vPortSystemTickHandler( int sig )
453474
{
454-
if( prvIsFreeRTOSThread( pthread_self() ) == pdTRUE )
475+
if( prvIsFreeRTOSThread() == pdTRUE )
455476
{
456477
Thread_t * pxThreadToSuspend;
457478
Thread_t * pxThreadToResume;
@@ -473,7 +494,9 @@ static void vPortSystemTickHandler( int sig )
473494
}
474495

475496
uxCriticalNesting--;
476-
} else {
497+
}
498+
else
499+
{
477500
fprintf( stderr, "vPortSystemTickHandler called from non-FreeRTOS thread\n" );
478501
}
479502
}
@@ -508,7 +531,7 @@ static void * prvWaitForStart( void * pvParams )
508531
{
509532
Thread_t * pxThread = pvParams;
510533

511-
prvMarkAsFreeRTOSThread( pthread_self() );
534+
prvMarkAsFreeRTOSThread();
512535

513536
prvSuspendSelf( pxThread );
514537

portable/ThirdParty/GCC/Posix/utils/wait_for_event.c

+35-4
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@
3535
struct event
3636
{
3737
pthread_mutex_t mutex;
38+
pthread_mutexattr_t mutexattr;
3839
pthread_cond_t cond;
3940
bool event_triggered;
4041
};
42+
/*-----------------------------------------------------------*/
4143

4244
struct event * event_create( void )
4345
{
@@ -46,23 +48,36 @@ struct event * event_create( void )
4648
if( ev != NULL )
4749
{
4850
ev->event_triggered = false;
49-
pthread_mutex_init( &ev->mutex, NULL );
51+
pthread_mutexattr_init( &ev->mutexattr );
52+
#ifndef __APPLE__
53+
pthread_mutexattr_setrobust( &ev->mutexattr, PTHREAD_MUTEX_ROBUST );
54+
#endif
55+
pthread_mutex_init( &ev->mutex, &ev->mutexattr );
5056
pthread_cond_init( &ev->cond, NULL );
5157
}
5258

5359
return ev;
5460
}
61+
/*-----------------------------------------------------------*/
5562

5663
void event_delete( struct event * ev )
5764
{
5865
pthread_mutex_destroy( &ev->mutex );
66+
pthread_mutexattr_destroy( &ev->mutexattr );
5967
pthread_cond_destroy( &ev->cond );
6068
free( ev );
6169
}
70+
/*-----------------------------------------------------------*/
6271

6372
bool event_wait( struct event * ev )
6473
{
65-
pthread_mutex_lock( &ev->mutex );
74+
if( pthread_mutex_lock( &ev->mutex ) == EOWNERDEAD )
75+
{
76+
#ifndef __APPLE__
77+
/* If the thread owning the mutex died, make the mutex consistent. */
78+
pthread_mutex_consistent( &ev->mutex );
79+
#endif
80+
}
6681

6782
while( ev->event_triggered == false )
6883
{
@@ -73,6 +88,8 @@ bool event_wait( struct event * ev )
7388
pthread_mutex_unlock( &ev->mutex );
7489
return true;
7590
}
91+
/*-----------------------------------------------------------*/
92+
7693
bool event_wait_timed( struct event * ev,
7794
time_t ms )
7895
{
@@ -82,7 +99,13 @@ bool event_wait_timed( struct event * ev,
8299
clock_gettime( CLOCK_REALTIME, &ts );
83100
ts.tv_sec += ms / 1000;
84101
ts.tv_nsec += ( ( ms % 1000 ) * 1000000 );
85-
pthread_mutex_lock( &ev->mutex );
102+
if( pthread_mutex_lock( &ev->mutex ) == EOWNERDEAD )
103+
{
104+
#ifndef __APPLE__
105+
/* If the thread owning the mutex died, make the mutex consistent. */
106+
pthread_mutex_consistent( &ev->mutex );
107+
#endif
108+
}
86109

87110
while( ( ev->event_triggered == false ) && ( ret == 0 ) )
88111
{
@@ -98,11 +121,19 @@ bool event_wait_timed( struct event * ev,
98121
pthread_mutex_unlock( &ev->mutex );
99122
return true;
100123
}
124+
/*-----------------------------------------------------------*/
101125

102126
void event_signal( struct event * ev )
103127
{
104-
pthread_mutex_lock( &ev->mutex );
128+
if( pthread_mutex_lock( &ev->mutex ) == EOWNERDEAD )
129+
{
130+
#ifndef __APPLE__
131+
/* If the thread owning the mutex died, make the mutex consistent. */
132+
pthread_mutex_consistent( &ev->mutex );
133+
#endif
134+
}
105135
ev->event_triggered = true;
106136
pthread_cond_signal( &ev->cond );
107137
pthread_mutex_unlock( &ev->mutex );
108138
}
139+
/*-----------------------------------------------------------*/

0 commit comments

Comments
 (0)