diff --git a/sched/group/group_killchildren.c b/sched/group/group_killchildren.c index cba53ec1dab..38433122acc 100644 --- a/sched/group/group_killchildren.c +++ b/sched/group/group_killchildren.c @@ -1,7 +1,7 @@ /**************************************************************************** * sched/group/group_killchildren.c * - * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2013, 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -39,8 +39,14 @@ #include +#include +#include #include +#include +#include + +#include "sched/sched.h" #include "group/group.h" #ifdef HAVE_GROUP_MEMBERS @@ -66,15 +72,34 @@ static int group_killchildren_handler(pid_t pid, FAR void *arg) { + FAR struct tcb_s *rtcb; int ret = OK; - /* Is this the pthread that we are looking for? */ + /* Cancel all threads except for the one specified by the argument */ if (pid != (pid_t)((uintptr_t)arg)) { - /* Yes.. cancel it */ + /* Cancel this thread. This is a forced cancellation. Make sure that + * cancellation is not disabled by the task/thread. That bit will + * prevent pthread_cancel() or task_delete() from doing what they need + * to do. + */ - ret = pthread_cancel(pid); + rtcb = sched_gettcb(pid); + rtcb->flags &= ~TCB_FLAG_NONCANCELABLE; + + /* 'pid' could refer to the main task of the thread. That pid will + * appear in the group member list as well! + */ + + if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) + { + ret = pthread_cancel(pid); + } + else + { + ret = task_delete(pid); + } } return ret; diff --git a/sched/signal/sig_default.c b/sched/signal/sig_default.c index 72303131d1b..c13ed89f2b7 100644 --- a/sched/signal/sig_default.c +++ b/sched/signal/sig_default.c @@ -39,7 +39,10 @@ #include +#include +#include #include +#include #include #include @@ -155,17 +158,41 @@ static const struct nxsig_defaction_s g_defactions[] = static void nxsig_abnormal_termination(int signo) { + FAR struct tcb_s *rtcb = (FAR struct tcb_s *)this_task(); + + /* Careful: In the multi-threaded task, the signal may be handled on a + * child pthread. + */ + #ifdef HAVE_GROUP_MEMBERS - FAR struct task_tcb_s *tcb = (FAR struct task_tcb_s *)this_task(); + /* Kill of of the children of the task. If we are running on a pthread, + * this will not kill the currently running task/pthread (this_task). It + * will kill the main thread of the task group if the this_task is a + * pthread. + */ - /* Kill of of the children of the task */ - - group_killchildren(tcb); + group_killchildren((FAR struct task_tcb_s *)rtcb); #endif - /* And exit to terminate the task (note exit() vs. _exit() is used. */ +#ifndef CONFIG_DISABLE_PTHREAD + /* Check if the currently running task is actually a pthread */ - exit(EXIT_FAILURE); + if ((rtcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) + { + /* Exit the final thread of the task group. + * + * REVISIT: This will not work if HAVE_GROUP_MEMBERS is not set. + */ + + pthread_exit(NULL); + } + else +#endif + { + /* Exit to terminate the task (note that exit() vs. _exit() is used. */ + + exit(EXIT_FAILURE); + } } /****************************************************************************