sched: Consolidate the cancellation notification logic
to avoid the code duplication Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com> Change-Id: Ie2ba55c382eb3eb7c8d9f04bba1b9e294aaf6196
This commit is contained in:
parent
2160a65030
commit
4d634b9006
@ -67,61 +67,15 @@ int pthread_cancel(pthread_t thread)
|
||||
DEBUGASSERT((tcb->flags & TCB_FLAG_TTYPE_MASK) ==
|
||||
TCB_FLAG_TTYPE_PTHREAD);
|
||||
|
||||
/* Check to see if this thread has the non-cancelable bit set in its
|
||||
* flags. Suppress context changes for a bit so that the flags are stable.
|
||||
* (the flags should not change in interrupt handling).
|
||||
*/
|
||||
/* Notify the target if the non-cancelable or deferred cancellation set */
|
||||
|
||||
sched_lock();
|
||||
if ((tcb->flags & TCB_FLAG_NONCANCELABLE) != 0)
|
||||
if (nxnotify_cancellation(tcb))
|
||||
{
|
||||
/* Then we cannot cancel the thread now. Here is how this is
|
||||
* supposed to work:
|
||||
*
|
||||
* "When cancellability is disabled, all cancels are held pending
|
||||
* in the target thread until the thread changes the cancellability.
|
||||
* When cancellability is deferred, all cancels are held pending in
|
||||
* the target thread until the thread changes the cancellability,
|
||||
* calls a function which is a cancellation point or calls
|
||||
* pthread_testcancel(), thus creating a cancellation point. When
|
||||
* cancellability is asynchronous, all cancels are acted upon
|
||||
* immediately, interrupting the thread with its processing."
|
||||
*/
|
||||
|
||||
tcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
sched_unlock();
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
/* Check if this thread supports deferred cancellation */
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0)
|
||||
{
|
||||
/* Then we cannot cancel the thread asynchronously. Mark the
|
||||
* cancellation as pending.
|
||||
*/
|
||||
|
||||
tcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
|
||||
/* If the thread is waiting at a cancellation point, then notify of the
|
||||
* cancellation thereby waking the task up with an ECANCELED error.
|
||||
*/
|
||||
|
||||
if (tcb->cpcount > 0)
|
||||
{
|
||||
nxnotify_cancellation(tcb);
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Otherwise, perform the asyncrhonous cancellation */
|
||||
|
||||
sched_unlock();
|
||||
|
||||
/* Check to see if the ID refers to ourselves.. this would be the
|
||||
* same as pthread_exit(PTHREAD_CANCELED).
|
||||
*/
|
||||
|
@ -207,62 +207,13 @@ static void nxsig_abnormal_termination(int signo)
|
||||
{
|
||||
FAR struct tcb_s *rtcb = (FAR struct tcb_s *)this_task();
|
||||
|
||||
/* Check to see if this task has the non-cancelable bit set in its
|
||||
* flags. Suppress context changes for a bit so that the flags are stable.
|
||||
* (the flags should not change in interrupt handling).
|
||||
*/
|
||||
/* Notify the target if the non-cancelable or deferred cancellation set */
|
||||
|
||||
sched_lock();
|
||||
if ((rtcb->flags & TCB_FLAG_NONCANCELABLE) != 0)
|
||||
if (nxnotify_cancellation(rtcb))
|
||||
{
|
||||
/* Then we cannot cancel the thread now. Here is how this is
|
||||
* supposed to work:
|
||||
*
|
||||
* "When cancellability is disabled, all cancels are held pending
|
||||
* in the target thread until the thread changes the cancellability.
|
||||
* When cancellability is deferred, all cancels are held pending in
|
||||
* the target thread until the thread changes the cancellability,
|
||||
* calls a function which is a cancellation point or calls
|
||||
* pthread_testcancel(), thus creating a cancellation point. When
|
||||
* cancellability is asynchronous, all cancels are acted upon
|
||||
* immediately, interrupting the thread with its processing."
|
||||
*
|
||||
* REVISIT: Does this rule apply to equally to both SIGKILL and
|
||||
* SIGINT?
|
||||
*/
|
||||
|
||||
rtcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
sched_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
/* Check if this task supports deferred cancellation */
|
||||
|
||||
if ((rtcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0)
|
||||
{
|
||||
/* Then we cannot cancel the task asynchronously.
|
||||
* Mark the cancellation as pending.
|
||||
*/
|
||||
|
||||
rtcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
|
||||
/* If the task is waiting at a cancellation point, then notify of the
|
||||
* cancellation thereby waking the task up with an ECANCELED error.
|
||||
*/
|
||||
|
||||
if (rtcb->cpcount > 0)
|
||||
{
|
||||
nxnotify_cancellation(rtcb);
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
sched_unlock();
|
||||
|
||||
/* Careful: In the multi-threaded task, the signal may be handled on a
|
||||
* child pthread.
|
||||
*/
|
||||
|
@ -37,7 +37,7 @@ CSRCS += task_create.c task_init.c task_setup.c task_activate.c
|
||||
CSRCS += task_start.c task_delete.c task_exit.c task_exithook.c
|
||||
CSRCS += task_getgroup.c task_getpid.c task_prctl.c task_recover.c
|
||||
CSRCS += task_restart.c task_spawnparms.c task_setcancelstate.c
|
||||
CSRCS += task_terminate.c exit.c
|
||||
CSRCS += task_cancelpt.c task_terminate.c exit.c
|
||||
|
||||
ifeq ($(CONFIG_ARCH_HAVE_VFORK),y)
|
||||
ifeq ($(CONFIG_SCHED_WAITPID),y)
|
||||
@ -71,10 +71,6 @@ ifeq ($(CONFIG_SCHED_ONEXIT),y)
|
||||
CSRCS += task_onexit.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_CANCELLATION_POINTS),y)
|
||||
CSRCS += task_cancelpt.c
|
||||
endif
|
||||
|
||||
# Include task build support
|
||||
|
||||
DEPPATH += --dep-path task
|
||||
|
@ -71,8 +71,6 @@ void nxtask_recover(FAR struct tcb_s *tcb);
|
||||
|
||||
/* Cancellation points */
|
||||
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
void nxnotify_cancellation(FAR struct tcb_s *tcb);
|
||||
#endif
|
||||
bool nxnotify_cancellation(FAR struct tcb_s *tcb);
|
||||
|
||||
#endif /* __SCHED_TASK_TASK_H */
|
||||
|
@ -316,6 +316,8 @@ bool check_cancellation_point(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CANCELLATION_POINTS */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: nxnotify_cancellation
|
||||
*
|
||||
@ -327,9 +329,12 @@ bool check_cancellation_point(void)
|
||||
* leave_cancellation_point() would then follow, causing the thread to
|
||||
* exit.
|
||||
*
|
||||
* Returned Value:
|
||||
* Indicate whether the notification delivery to the target
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void nxnotify_cancellation(FAR struct tcb_s *tcb)
|
||||
bool nxnotify_cancellation(FAR struct tcb_s *tcb)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
@ -339,51 +344,86 @@ void nxnotify_cancellation(FAR struct tcb_s *tcb)
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Make sure that the cancellation pending indication is set. */
|
||||
|
||||
tcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
|
||||
/* We only notify the cancellation if (1) the thread has not disabled
|
||||
* cancellation, (2) the thread uses the deferred cancellation mode,
|
||||
* (3) the thread is waiting within a cancellation point.
|
||||
*/
|
||||
|
||||
if (((tcb->flags & TCB_FLAG_NONCANCELABLE) == 0 &&
|
||||
(tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) ||
|
||||
tcb->cpcount > 0)
|
||||
/* Check to see if this task has the non-cancelable bit set. */
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_NONCANCELABLE) != 0)
|
||||
{
|
||||
/* If the thread is blocked waiting for a semaphore, then the thread
|
||||
* must be unblocked to handle the cancellation.
|
||||
/* Then we cannot cancel the thread now. Here is how this is
|
||||
* supposed to work:
|
||||
*
|
||||
* "When cancellability is disabled, all cancels are held pending
|
||||
* in the target thread until the thread changes the cancellability.
|
||||
* When cancellability is deferred, all cancels are held pending in
|
||||
* the target thread until the thread changes the cancellability,
|
||||
* calls a function which is a cancellation point or calls
|
||||
* pthread_testcancel(), thus creating a cancellation point. When
|
||||
* cancellability is asynchronous, all cancels are acted upon
|
||||
* immediately, interrupting the thread with its processing."
|
||||
*/
|
||||
|
||||
if (tcb->task_state == TSTATE_WAIT_SEM)
|
||||
{
|
||||
nxsem_wait_irq(tcb, ECANCELED);
|
||||
}
|
||||
|
||||
/* If the thread is blocked waiting on a signal, then the
|
||||
* thread must be unblocked to handle the cancellation.
|
||||
*/
|
||||
|
||||
else if (tcb->task_state == TSTATE_WAIT_SIG)
|
||||
{
|
||||
nxsig_wait_irq(tcb, ECANCELED);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DISABLE_MQUEUE
|
||||
/* If the thread is blocked waiting on a message queue, then the
|
||||
* thread must be unblocked to handle the cancellation.
|
||||
*/
|
||||
|
||||
else if (tcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
|
||||
tcb->task_state == TSTATE_WAIT_MQNOTFULL)
|
||||
{
|
||||
nxmq_wait_irq(tcb, ECANCELED);
|
||||
}
|
||||
#endif
|
||||
tcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
leave_critical_section(flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
/* Check if this task supports deferred cancellation */
|
||||
|
||||
#endif /* CONFIG_CANCELLATION_POINTS */
|
||||
if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0)
|
||||
{
|
||||
/* Then we cannot cancel the task asynchronously.
|
||||
* Mark the cancellation as pending.
|
||||
*/
|
||||
|
||||
tcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
|
||||
/* If the task is waiting at a cancellation point, then notify of the
|
||||
* cancellation thereby waking the task up with an ECANCELED error.
|
||||
*/
|
||||
|
||||
if (tcb->cpcount > 0)
|
||||
{
|
||||
/* If the thread is blocked waiting for a semaphore, then the
|
||||
* thread must be unblocked to handle the cancellation.
|
||||
*/
|
||||
|
||||
if (tcb->task_state == TSTATE_WAIT_SEM)
|
||||
{
|
||||
nxsem_wait_irq(tcb, ECANCELED);
|
||||
}
|
||||
|
||||
/* If the thread is blocked waiting on a signal, then the
|
||||
* thread must be unblocked to handle the cancellation.
|
||||
*/
|
||||
|
||||
else if (tcb->task_state == TSTATE_WAIT_SIG)
|
||||
{
|
||||
nxsig_wait_irq(tcb, ECANCELED);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DISABLE_MQUEUE
|
||||
/* If the thread is blocked waiting on a message queue, then
|
||||
* the thread must be unblocked to handle the cancellation.
|
||||
*/
|
||||
|
||||
else if (tcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
|
||||
tcb->task_state == TSTATE_WAIT_MQNOTFULL)
|
||||
{
|
||||
nxmq_wait_irq(tcb, ECANCELED);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
leave_critical_section(flags);
|
||||
return false;
|
||||
}
|
||||
|
@ -143,59 +143,13 @@ int task_delete(pid_t pid)
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Check to see if this task has the non-cancelable bit set in its
|
||||
* flags. Suppress context changes for a bit so that the flags are stable.
|
||||
* (the flags should not change in interrupt handling).
|
||||
*/
|
||||
/* Notify the target if the non-cancelable or deferred cancellation set */
|
||||
|
||||
sched_lock();
|
||||
if ((dtcb->flags & TCB_FLAG_NONCANCELABLE) != 0)
|
||||
if (nxnotify_cancellation(dtcb))
|
||||
{
|
||||
/* Then we cannot cancel the thread now. Here is how this is
|
||||
* supposed to work:
|
||||
*
|
||||
* "When cancellability is disabled, all cancels are held pending
|
||||
* in the target thread until the thread changes the cancellability.
|
||||
* When cancellability is deferred, all cancels are held pending in
|
||||
* the target thread until the thread changes the cancellability,
|
||||
* calls a function which is a cancellation point or calls
|
||||
* pthread_testcancel(), thus creating a cancellation point. When
|
||||
* cancellability is asynchronous, all cancels are acted upon
|
||||
* immediately, interrupting the thread with its processing."
|
||||
*/
|
||||
|
||||
dtcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
sched_unlock();
|
||||
return OK;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
/* Check if this task supports deferred cancellation */
|
||||
|
||||
if ((dtcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0)
|
||||
{
|
||||
/* Then we cannot cancel the task asynchronously. Mark the
|
||||
* cancellation as pending.
|
||||
*/
|
||||
|
||||
dtcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
|
||||
/* If the task is waiting at a cancellation point, then notify of the
|
||||
* cancellation thereby waking the task up with an ECANCELED error.
|
||||
*/
|
||||
|
||||
if (dtcb->cpcount > 0)
|
||||
{
|
||||
nxnotify_cancellation(dtcb);
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
sched_unlock();
|
||||
|
||||
/* Otherwise, perform the asynchronous cancellation, letting
|
||||
* nxtask_terminate() do all of the heavy lifting.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user