From 22fd3a12c007ad59bb834db605b24b2df3661b1f Mon Sep 17 00:00:00 2001 From: EunBong Song Date: Tue, 2 May 2017 16:57:57 +0900 Subject: [PATCH] pthread: Add logic to disable cancellation points within the OS This is useful when an internal OS function that is NOT a cancellation point calls an OS function which is a cancellation point. In that case, irrecoverable states may states may occur if the cancellation is within the OS. All credits should go to Juha Niskanen who wrote the original commit. Change-Id: Iaedfdcf921f4859f049d590e47ab136cb0a0b699 Signed-off-by: Juha Niskanen (Haltian) [Song: backported b4747286 from Nuttx] Signed-off-by: EunBong Song --- os/kernel/pthread/pthread.h | 8 ++++++++ os/kernel/pthread/pthread_condtimedwait.c | 5 +++++ os/kernel/pthread/pthread_condwait.c | 12 +++++++++++- 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/os/kernel/pthread/pthread.h b/os/kernel/pthread/pthread.h index bc0eda1..0cb7d38 100644 --- a/os/kernel/pthread/pthread.h +++ b/os/kernel/pthread/pthread.h @@ -135,6 +135,14 @@ void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb); #define pthread_mutex_give(m) pthread_givesemaphore(&(m)->sem) #endif +#if defined(CONFIG_CANCELLATION_POINTS) +uint16_t pthread_disable_cancel(void); +void pthread_enable_cancel(uint16_t oldstate); +#else +# define pthread_disable_cancel() (0) +# define pthread_enable_cancel(s) UNUSED(s) +#endif + #ifdef CONFIG_PTHREAD_MUTEX_TYPES int pthread_mutexattr_verifytype(int type); #endif diff --git a/os/kernel/pthread/pthread_condtimedwait.c b/os/kernel/pthread/pthread_condtimedwait.c index b951cee..e766b8e 100644 --- a/os/kernel/pthread/pthread_condtimedwait.c +++ b/os/kernel/pthread/pthread_condtimedwait.c @@ -198,6 +198,7 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex, int ticks; int mypid = (int)getpid(); irqstate_t int_state; + uint16_t oldstate; int ret = OK; int status; @@ -322,7 +323,11 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex, /* Reacquire the mutex (retaining the ret). */ svdbg("Re-locking...\n"); + + oldstate = pthread_disable_cancel(); status = pthread_mutex_take(mutex, false); + pthread_enable_cancel(oldstate); + if (status == OK) { mutex->pid = mypid; } else if (ret == 0) { diff --git a/os/kernel/pthread/pthread_condwait.c b/os/kernel/pthread/pthread_condwait.c index b6002c6..18a8062 100644 --- a/os/kernel/pthread/pthread_condwait.c +++ b/os/kernel/pthread/pthread_condwait.c @@ -126,6 +126,8 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex) else if (mutex->pid != (int)getpid()) { ret = EPERM; } else { + uint16_t oldstate; + /* Give up the mutex */ svdbg("Give up mutex / take cond\n"); @@ -145,10 +147,18 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex) sched_unlock(); - /* Reacquire the mutex */ + /* Reacquire the mutex + * When cancellation points are enabled, we need to + * hold the mutex when the pthread is canceled and + * cleanup handlers, if any, are entered. + */ svdbg("Reacquire mutex...\n"); + + oldstate = pthread_disable_cancel(); status = pthread_takesemaphore((FAR sem_t *)&mutex->sem, false); + pthread_enable_cancel(oldstate); + if (ret == OK) { /* Report the first failure that occurs */ -- 2.7.4