This is an automated email from the ASF dual-hosted git repository. aguettouche pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 4d634b9006760555c48ce70375190dc57fb594e2 Author: Xiang Xiao <xiaoxi...@xiaomi.com> AuthorDate: Sun Jun 7 00:41:47 2020 +0800 sched: Consolidate the cancellation notification logic to avoid the code duplication Signed-off-by: Xiang Xiao <xiaoxi...@xiaomi.com> Change-Id: Ie2ba55c382eb3eb7c8d9f04bba1b9e294aaf6196 --- sched/pthread/pthread_cancel.c | 50 +-------------------- sched/signal/sig_default.c | 53 +---------------------- sched/task/Make.defs | 6 +-- sched/task/task.h | 4 +- sched/task/task_cancelpt.c | 98 +++++++++++++++++++++++++++++------------- sched/task/task_delete.c | 50 +-------------------- 6 files changed, 77 insertions(+), 184 deletions(-) diff --git a/sched/pthread/pthread_cancel.c b/sched/pthread/pthread_cancel.c index 02b8087..dcc58f6 100644 --- a/sched/pthread/pthread_cancel.c +++ b/sched/pthread/pthread_cancel.c @@ -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). - */ - - sched_lock(); - if ((tcb->flags & TCB_FLAG_NONCANCELABLE) != 0) - { - /* 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 */ + /* Notify the target if the non-cancelable or deferred cancellation set */ - if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) + if (nxnotify_cancellation(tcb)) { - /* 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). */ diff --git a/sched/signal/sig_default.c b/sched/signal/sig_default.c index 28bad31..70a2238 100644 --- a/sched/signal/sig_default.c +++ b/sched/signal/sig_default.c @@ -207,61 +207,12 @@ 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). - */ - - sched_lock(); - if ((rtcb->flags & TCB_FLAG_NONCANCELABLE) != 0) - { - /* 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 */ + /* Notify the target if the non-cancelable or deferred cancellation set */ - if ((rtcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) + if (nxnotify_cancellation(rtcb)) { - /* 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. diff --git a/sched/task/Make.defs b/sched/task/Make.defs index a5c2295..1fa00c7 100644 --- a/sched/task/Make.defs +++ b/sched/task/Make.defs @@ -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 diff --git a/sched/task/task.h b/sched/task/task.h index 80279a7..3de2d42 100644 --- a/sched/task/task.h +++ b/sched/task/task.h @@ -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 */ diff --git a/sched/task/task_cancelpt.c b/sched/task/task_cancelpt.c index 988e9bf..cad59df 100644 --- a/sched/task/task_cancelpt.c +++ b/sched/task/task_cancelpt.c @@ -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); - } + tcb->flags |= TCB_FLAG_CANCEL_PENDING; + leave_critical_section(flags); + return true; + } + +#ifdef CONFIG_CANCELLATION_POINTS + /* Check if this task supports deferred cancellation */ - /* If the thread is blocked waiting on a signal, then the - * thread must be unblocked to handle the cancellation. + if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) + { + /* Then we cannot cancel the task asynchronously. + * Mark the cancellation as pending. */ - else if (tcb->task_state == TSTATE_WAIT_SIG) - { - nxsig_wait_irq(tcb, ECANCELED); - } + tcb->flags |= TCB_FLAG_CANCEL_PENDING; -#ifndef CONFIG_DISABLE_MQUEUE - /* If the thread is blocked waiting on a message queue, then the - * thread must be unblocked to handle the cancellation. + /* If the task is waiting at a cancellation point, then notify of the + * cancellation thereby waking the task up with an ECANCELED error. */ - else if (tcb->task_state == TSTATE_WAIT_MQNOTEMPTY || - tcb->task_state == TSTATE_WAIT_MQNOTFULL) + if (tcb->cpcount > 0) { - nxmq_wait_irq(tcb, ECANCELED); - } + /* 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; } - -#endif /* CONFIG_CANCELLATION_POINTS */ diff --git a/sched/task/task_delete.c b/sched/task/task_delete.c index 8a6fe5b..eef94c1 100644 --- a/sched/task/task_delete.c +++ b/sched/task/task_delete.c @@ -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. */