Skip to content
Snippets Groups Projects
Commit b4747286 authored by Juha Niskanen (Haltian)'s avatar Juha Niskanen (Haltian) Committed by Gregory Nutt
Browse files

Add logic to disable cancellation points within the OS. This is useful when...

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 occur if the cancellation is within the OS.
parent 3fb73004
No related branches found
No related tags found
No related merge requests found
......@@ -121,6 +121,14 @@ void pthread_mutex_inconsistent(FAR struct pthread_tcb_s *tcb);
# define pthread_mutex_give(m) pthread_givesemaphore(&(m)->sem)
#endif
#ifdef 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
......
......@@ -167,9 +167,10 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
FAR const struct timespec *abstime)
{
FAR struct tcb_s *rtcb = this_task();
irqstate_t flags;
uint16_t oldstate;
int ticks;
int mypid = (int)getpid();
irqstate_t flags;
int ret = OK;
int status;
......@@ -316,7 +317,11 @@ int pthread_cond_timedwait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex,
/* Reacquire the mutex (retaining the ret). */
sinfo("Re-locking...\n");
oldstate = pthread_disable_cancel();
status = pthread_mutex_take(mutex, false);
pthread_enable_cancel(oldstate);
if (status == OK)
{
mutex->pid = mypid;
......
......@@ -95,6 +95,8 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex)
}
else
{
uint16_t oldstate;
/* Give up the mutex */
sinfo("Give up mutex / take cond\n");
......@@ -117,12 +119,17 @@ int pthread_cond_wait(FAR pthread_cond_t *cond, FAR pthread_mutex_t *mutex)
/* Reacquire the mutex.
*
* REVISIT: When cancellation points are enabled, we will almost
* certainly hold the mutex when the pthread is canceled.
* When cancellation points are enabled, we need to
* hold the mutex when the pthread is canceled and
* cleanup handlers, if any, are entered.
*/
sinfo("Reacquire mutex...\n");
oldstate = pthread_disable_cancel();
status = pthread_mutex_take(mutex, false);
pthread_enable_cancel(oldstate);
if (ret == OK)
{
/* Report the first failure that occurs */
......
......@@ -95,8 +95,8 @@ static void pthread_mutex_add(FAR struct pthread_mutex_s *mutex)
* mutex to the list of mutexes held by this thread.
*
* Parameters:
* mutex - The mux to be locked
* intr - false: ignore EINTR errors when locking; true tread EINTR as
* mutex - The mutex to be locked
* intr - false: ignore EINTR errors when locking; true treat EINTR as
* other errors by returning the errno value
*
* Return Value:
......@@ -126,15 +126,11 @@ int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr)
else
{
/* Take semaphore underlying the mutex. pthread_takesemaphore
* returns zero on success and a positive errno value on failue.
* returns zero on success and a positive errno value on failure.
*/
ret = pthread_takesemaphore(&mutex->sem, intr);
if (ret != OK)
{
ret = get_errno();
}
else
if (ret == OK)
{
/* Check if the holder of the mutex has terminated without
* releasing. In that case, the state of the mutex is
......@@ -169,8 +165,8 @@ int pthread_mutex_take(FAR struct pthread_mutex_s *mutex, bool intr)
* mutex to the list of mutexes held by this thread.
*
* Parameters:
* mutex - The mux to be locked
* intr - false: ignore EINTR errors when locking; true tread EINTR as
* mutex - The mutex to be locked
* intr - false: ignore EINTR errors when locking; true treat EINTR as
* other errors by returning the errno value
*
* Return Value:
......@@ -283,3 +279,70 @@ int pthread_mutex_give(FAR struct pthread_mutex_s *mutex)
return ret;
}
/****************************************************************************
* Name: pthread_disable_cancel() and pthread_enable_cancel()
*
* Description:
* Temporarily disable cancellation and return old cancel state, which
* can later be restored. This is useful when a cancellation point
* function is called from within the OS by a non-cancellation point:
* In certain such cases, we need to defer the cancellation to prevent
* bad things from happening.
*
* Parameters:
* saved cancel flags for pthread_enable_cancel()
*
* Return Value:
* old cancel flags for pthread_disable_cancel()
*
****************************************************************************/
#ifdef CONFIG_CANCELLATION_POINTS
uint16_t pthread_disable_cancel(void)
{
FAR struct pthread_tcb_s *tcb = (FAR struct pthread_tcb_s *)this_task();
irqstate_t flags;
uint16_t old;
/* We need perform the following operations from within a critical section
* because it can compete with interrupt level activity.
*/
flags = enter_critical_section();
old = tcb->cmn.flags & (TCB_FLAG_CANCEL_PENDING | TCB_FLAG_NONCANCELABLE);
tcb->cmn.flags &= ~(TCB_FLAG_CANCEL_PENDING | TCB_FLAG_NONCANCELABLE);
leave_critical_section(flags);
return old;
}
void pthread_enable_cancel(uint16_t cancelflags)
{
FAR struct pthread_tcb_s *tcb = (FAR struct pthread_tcb_s *)this_task();
irqstate_t flags;
/* We need perform the following operations from within a critical section
* because it can compete with interrupt level activity.
*/
flags = enter_critical_section();
tcb->cmn.flags |= cancelflags;
/* What should we do if there is a pending cancellation?
*
* If the thread is executing with deferred cancellation, we need do
* nothing more; the cancellation cannot occur until the next
* cancellation point.
*
* However, if the thread is executing in asynchronous cancellation mode,
* then we need to terminate now by simply calling pthread_exit().
*/
if ((tcb->cmn.flags & TCB_FLAG_CANCEL_DEFERRED) == 0 &&
(tcb->cmn.flags & TCB_FLAG_CANCEL_PENDING) != 0)
{
pthread_exit(NULL);
}
leave_critical_section(flags);
}
#endif /* CONFIG_CANCELLATION_POINTS */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment