diff --git a/fs/procfs/fs_procfsproc.c b/fs/procfs/fs_procfsproc.c index 04c83d53f7c..c0289f64361 100644 --- a/fs/procfs/fs_procfsproc.c +++ b/fs/procfs/fs_procfsproc.c @@ -578,9 +578,7 @@ static ssize_t proc_status(FAR struct proc_file_s *procfile, /* Show task flags */ linesize = procfs_snprintf(procfile->line, STATUS_LINELEN, - "%-12s%c%c%c\n", "Flags:", - tcb->flags & TCB_FLAG_NONCANCELABLE ? 'N' : '-', - tcb->flags & TCB_FLAG_CANCEL_PENDING ? 'P' : '-', + "%-12s%c\n", "Flags:", tcb->flags & TCB_FLAG_EXIT_PROCESSING ? 'P' : '-'); copysize = procfs_memcpy(procfile->line, linesize, buffer, remaining, diff --git a/include/nuttx/cancelpt.h b/include/nuttx/cancelpt.h index f76be1885e5..014fb77cc88 100644 --- a/include/nuttx/cancelpt.h +++ b/include/nuttx/cancelpt.h @@ -58,6 +58,14 @@ #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CANCEL_FLAG_NONCANCELABLE (1 << 0) /* Pthread is non-cancelable */ +#define CANCEL_FLAG_CANCEL_ASYNC (1 << 1) /* Async (vs deferred) cancellation type */ +#define CANCEL_FLAG_CANCEL_PENDING (1 << 2) /* Pthread cancel is pending */ + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 6e44489b6df..c9581456ed2 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -89,22 +89,20 @@ # define TCB_FLAG_TTYPE_TASK (0 << TCB_FLAG_TTYPE_SHIFT) /* Normal user task */ # define TCB_FLAG_TTYPE_PTHREAD (1 << TCB_FLAG_TTYPE_SHIFT) /* User pthread */ # define TCB_FLAG_TTYPE_KERNEL (2 << TCB_FLAG_TTYPE_SHIFT) /* Kernel thread */ -#define TCB_FLAG_NONCANCELABLE (1 << 2) /* Bit 2: Pthread is non-cancelable */ -#define TCB_FLAG_CANCEL_DEFERRED (1 << 3) /* Bit 3: Deferred (vs asynch) cancellation type */ -#define TCB_FLAG_CANCEL_PENDING (1 << 4) /* Bit 4: Pthread cancel is pending */ -#define TCB_FLAG_POLICY_SHIFT (5) /* Bit 5-6: Scheduling policy */ +#define TCB_FLAG_POLICY_SHIFT (3) /* Bit 3-4: Scheduling policy */ #define TCB_FLAG_POLICY_MASK (3 << TCB_FLAG_POLICY_SHIFT) # define TCB_FLAG_SCHED_FIFO (0 << TCB_FLAG_POLICY_SHIFT) /* FIFO scheding policy */ # define TCB_FLAG_SCHED_RR (1 << TCB_FLAG_POLICY_SHIFT) /* Round robin scheding policy */ # define TCB_FLAG_SCHED_SPORADIC (2 << TCB_FLAG_POLICY_SHIFT) /* Sporadic scheding policy */ -#define TCB_FLAG_CPU_LOCKED (1 << 8) /* Bit 7: Locked to this CPU */ -#define TCB_FLAG_SIGNAL_ACTION (1 << 9) /* Bit 8: In a signal handler */ -#define TCB_FLAG_SYSCALL (1 << 10) /* Bit 9: In a system call */ -#define TCB_FLAG_EXIT_PROCESSING (1 << 11) /* Bit 10: Exitting */ -#define TCB_FLAG_FREE_STACK (1 << 12) /* Bit 12: Free stack after exit */ -#define TCB_FLAG_HEAP_CHECK (1 << 13) /* Bit 13: Heap check */ -#define TCB_FLAG_HEAP_DUMP (1 << 14) /* Bit 14: Heap dump */ -#define TCB_FLAG_DETACHED (1 << 15) /* Bit 15: Pthread detached */ +#define TCB_FLAG_CPU_LOCKED (1 << 5) /* Bit 5: Locked to this CPU */ +#define TCB_FLAG_SIGNAL_ACTION (1 << 6) /* Bit 6: In a signal handler */ +#define TCB_FLAG_SYSCALL (1 << 7) /* Bit 7: In a system call */ +#define TCB_FLAG_EXIT_PROCESSING (1 << 8) /* Bit 8: Exitting */ +#define TCB_FLAG_FREE_STACK (1 << 9) /* Bit 9: Free stack after exit */ +#define TCB_FLAG_HEAP_CHECK (1 << 10) /* Bit 10: Heap check */ +#define TCB_FLAG_HEAP_DUMP (1 << 11) /* Bit 11: Heap dump */ +#define TCB_FLAG_DETACHED (1 << 12) /* Bit 12: Pthread detached */ +#define TCB_FLAG_FORCED_CANCEL (1 << 13) /* Bit 13: Pthread cancel is forced */ /* Values for struct task_group tg_flags */ @@ -572,9 +570,6 @@ struct tcb_s int16_t lockcount; /* 0=preemptible (not-locked) */ #ifdef CONFIG_IRQCOUNT int16_t irqcount; /* 0=Not in critical section */ -#endif -#ifdef CONFIG_CANCELLATION_POINTS - int16_t cpcount; /* Nested cancellation point count */ #endif int16_t errcode; /* Used to pass error information */ diff --git a/include/nuttx/tls.h b/include/nuttx/tls.h index cfdf063fecb..967c6194bbc 100644 --- a/include/nuttx/tls.h +++ b/include/nuttx/tls.h @@ -206,6 +206,12 @@ struct tls_info_s struct pthread_cleanup_s tl_stack[CONFIG_PTHREAD_CLEANUP_STACKSIZE]; #endif + uint8_t tl_cpstate; /* Cancellation state */ + +#ifdef CONFIG_CANCELLATION_POINTS + int16_t tl_cpcount; /* Nested cancellation point count */ +#endif + int tl_errno; /* Per-thread error number */ }; @@ -310,9 +316,28 @@ uintptr_t task_tls_get_value(int tlsindex); #elif defined(CONFIG_TLS_ALIGNED) && !defined(__KERNEL__) # define tls_get_info() TLS_INFO(up_getsp()) #else -FAR struct tls_info_s *tls_get_info(void); +# define tls_get_info() tls_get_info_pid(0) #endif +/**************************************************************************** + * Name: tls_get_info_pid + * + * Description: + * Return a reference to the tls_info_s structure. This is used as part + * of the internal implementation of tls_get/set_elem() and ONLY for the + * where CONFIG_TLS_ALIGNED is *not* defined or __KERNEL__ is defined. + * + * Input Parameters: + * pid - Thread ID to query, set to 0 to query own + * + * Returned Value: + * A reference to the thread-specific tls_info_s structure is return on + * success. NULL would be returned in the event of any failure. + * + ****************************************************************************/ + +FAR struct tls_info_s *tls_get_info_pid(pid_t pid); + /**************************************************************************** * Name: tls_destruct * diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h index ffc0efbfbe1..e624362175a 100644 --- a/include/sys/syscall_lookup.h +++ b/include/sys/syscall_lookup.h @@ -105,13 +105,6 @@ SYSCALL_LOOKUP(sem_wait, 1) SYSCALL_LOOKUP(pgalloc, 2) #endif -SYSCALL_LOOKUP(task_setcancelstate, 2) - -#ifdef CONFIG_CANCELLATION_POINTS - SYSCALL_LOOKUP(task_setcanceltype, 2) - SYSCALL_LOOKUP(task_testcancel, 0) -#endif - /* The following can be individually enabled */ #ifdef CONFIG_ARCH_HAVE_FORK diff --git a/libs/libc/sched/CMakeLists.txt b/libs/libc/sched/CMakeLists.txt index fd4630c2a8c..7436860ce68 100644 --- a/libs/libc/sched/CMakeLists.txt +++ b/libs/libc/sched/CMakeLists.txt @@ -26,11 +26,11 @@ set(SRCS clock_timespec_add.c clock_timespec_subtract.c clock_getcpuclockid.c - clock_getres.c) - -if(NOT CONFIG_CANCELLATION_POINTS) - list(APPEND SRCS task_setcanceltype.c task_testcancel.c) -endif() + clock_getres.c + task_cancelpt.c + task_setcancelstate.c + task_setcanceltype.c + task_testcancel.c) if(CONFIG_SMP) list(APPEND SRCS sched_cpucount.c) diff --git a/libs/libc/sched/Make.defs b/libs/libc/sched/Make.defs index e62603aa7cd..123151b16f9 100644 --- a/libs/libc/sched/Make.defs +++ b/libs/libc/sched/Make.defs @@ -24,10 +24,8 @@ CSRCS += sched_getprioritymax.c sched_getprioritymin.c CSRCS += clock_ticks2time.c clock_time2ticks.c CSRCS += clock_timespec_add.c clock_timespec_subtract.c CSRCS += clock_getcpuclockid.c clock_getres.c - -ifneq ($(CONFIG_CANCELLATION_POINTS),y) -CSRCS += task_setcanceltype.c task_testcancel.c -endif +CSRCS += task_cancelpt.c task_setcancelstate.c task_setcanceltype.c +CSRCS += task_testcancel.c ifeq ($(CONFIG_SMP),y) CSRCS += sched_cpucount.c diff --git a/libs/libc/sched/task_cancelpt.c b/libs/libc/sched/task_cancelpt.c new file mode 100644 index 00000000000..b15cd807f29 --- /dev/null +++ b/libs/libc/sched/task_cancelpt.c @@ -0,0 +1,258 @@ +/**************************************************************************** + * libs/libc/sched/task_cancelpt.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Cancellation Points. + * + * Cancellation points shall occur when a thread is executing the following + * functions: + * + * accept() mq_timedsend() putpmsg() sigtimedwait() + * aio_suspend() msgrcv() pwrite() sigwait() + * clock_nanosleep() msgsnd() read() sigwaitinfo() + * close() msync() readv() sleep() + * connect() nanosleep() recv() system() + * creat() open() recvfrom() tcdrain() + * fcntl() pause() recvmsg() usleep() + * fdatasync() poll() select() wait() + * fsync() pread() sem_timedwait() waitid() + * getmsg() pselect() sem_wait() waitpid() + * getpmsg() pthread_cond_timedwait() send() write() + * lockf() pthread_cond_wait() sendmsg() writev() + * mq_receive() pthread_join() sendto() + * mq_send() pthread_testcancel() sigpause() + * mq_timedreceive() putmsg() sigsuspend() + * + * Each of the above function must call enter_cancellation_point() on entry + * in order to establish the cancellation point and + * leave_cancellation_point() on exit. These functions are described below. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_CANCELLATION_POINTS + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: enter_cancellation_point + * + * Description: + * Called at the beginning of the cancellation point to establish the + * cancellation point. This function does the following: + * + * 1. If deferred cancellation does not apply to this thread, nothing is + * done, otherwise, it + * 2. Sets state information in the caller's TCB and increments a nesting + * count. + * 3. If this is the outermost nesting level, it checks if there is a + * pending cancellation and, if so, calls either exit() or + * pthread_exit(), depending upon the type of the thread. + * + * Input Parameters: + * None + * + * Returned Value: + * true is returned if a cancellation is pending but cannot be performed + * now due to the nesting level. + * + ****************************************************************************/ + +bool enter_cancellation_point(void) +{ + FAR struct tls_info_s *tls = tls_get_info(); + bool ret = false; + + /* If cancellation is disabled on this thread or if this thread is using + * asynchronous cancellation, then do nothing. + * + * Special case: if the cpcount count is greater than zero, then we are + * nested and the above condition was certainly true at the outermost + * nesting level. + */ + + if (((tls->tl_cpstate & CANCEL_FLAG_NONCANCELABLE) == 0 && + (tls->tl_cpstate & CANCEL_FLAG_CANCEL_ASYNC) == 0) || + tls->tl_cpcount > 0) + { + /* Check if there is a pending cancellation */ + + if ((tls->tl_cpstate & CANCEL_FLAG_CANCEL_PENDING) != 0) + { + /* Yes... return true (if we don't exit here) */ + + ret = true; + + /* If there is a pending cancellation and we are at the outermost + * nesting level of cancellation function calls, then exit + * according to the type of the thread. + */ + + if (tls->tl_cpcount == 0) + { +#ifndef CONFIG_DISABLE_PTHREAD + pthread_exit(PTHREAD_CANCELED); +#else + exit(EXIT_FAILURE); +#endif + } + } + + /* Otherwise, indicate that we are at a cancellation point by + * incrementing the nesting level of the cancellation point + * functions. + */ + + DEBUGASSERT(tls->tl_cpcount < INT16_MAX); + tls->tl_cpcount++; + } + + return ret; +} + +/**************************************************************************** + * Name: leave_cancellation_point + * + * Description: + * Called at the end of the cancellation point. This function does the + * following: + * + * 1. If deferred cancellation does not apply to this thread, nothing is + * done, otherwise, it + * 2. Clears state information in the caller's TCB and decrements a + * nesting count. + * 3. If this is the outermost nesting level, it checks if there is a + * pending cancellation and, if so, calls either exit() or + * pthread_exit(), depending upon the type of the thread. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void leave_cancellation_point(void) +{ + FAR struct tls_info_s *tls = tls_get_info(); + + /* If cancellation is disabled on this thread or if this thread is using + * asynchronous cancellation, then do nothing. Here we check only the + * nesting level: if the cpcount count is greater than zero, then the + * required condition was certainly true at the outermost nesting level. + */ + + if (tls->tl_cpcount > 0) + { + /* Decrement the nesting level. If if would decrement to zero, then + * we are at the outermost nesting level and may need to do more. + */ + + if (tls->tl_cpcount == 1) + { + /* We are no longer at the cancellation point */ + + tls->tl_cpcount = 0; + + /* If there is a pending cancellation then just exit according to + * the type of the thread. + */ + + if ((tls->tl_cpstate & CANCEL_FLAG_CANCEL_PENDING) != 0) + { +#ifndef CONFIG_DISABLE_PTHREAD + pthread_exit(PTHREAD_CANCELED); +#else + exit(EXIT_FAILURE); +#endif + } + } + else + { + /* We are not at the outermost nesting level. Just decrment the + * nesting level count. + */ + + tls->tl_cpcount--; + } + } +} + +/**************************************************************************** + * Name: check_cancellation_point + * + * Description: + * Returns true if: + * + * 1. Deferred cancellation does applies to this thread, + * 2. We are within a cancellation point (i.e., the nesting level in the + * TCB is greater than zero). + * + * Input Parameters: + * None + * + * Returned Value: + * true is returned if a cancellation is pending but cannot be performed + * now due to the nesting level. + * + ****************************************************************************/ + +bool check_cancellation_point(void) +{ + FAR struct tls_info_s *tls = tls_get_info(); + bool ret = false; + + /* If cancellation is disabled on this thread or if this thread is using + * asynchronous cancellation, then return false. + * + * If the cpcount count is greater than zero, then we within a + * cancellation and will true if there is a pending cancellation. + */ + + if (((tls->tl_cpstate & CANCEL_FLAG_NONCANCELABLE) == 0 && + (tls->tl_cpstate & CANCEL_FLAG_CANCEL_ASYNC) == 0) || + tls->tl_cpcount > 0) + { + /* Check if there is a pending cancellation. If so, return true. */ + + ret = ((tls->tl_cpstate & CANCEL_FLAG_CANCEL_PENDING) != 0); + } + + return ret; +} + +#endif /* CONFIG_CANCELLATION_POINTS */ diff --git a/sched/task/task_setcancelstate.c b/libs/libc/sched/task_setcancelstate.c similarity index 79% rename from sched/task/task_setcancelstate.c rename to libs/libc/sched/task_setcancelstate.c index 2d384eac14d..e329dc69206 100644 --- a/sched/task/task_setcancelstate.c +++ b/libs/libc/sched/task_setcancelstate.c @@ -1,5 +1,5 @@ /**************************************************************************** - * sched/task/task_setcancelstate.c + * libs/libc/sched/task_setcancelstate.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with @@ -24,13 +24,14 @@ #include -#include -#include #include +#include #include +#include +#include -#include "sched/sched.h" -#include "task/task.h" +#include +#include /**************************************************************************** * Public Functions @@ -61,20 +62,14 @@ int task_setcancelstate(int state, FAR int *oldstate) { - FAR struct tcb_s *tcb = this_task(); + FAR struct tls_info_s *tls = tls_get_info(); int ret = OK; - /* Suppress context changes for a bit so that the flags are stable. (the - * flags should not change in interrupt handling). - */ - - sched_lock(); - /* Return the current state if so requested */ if (oldstate != NULL) { - if ((tcb->flags & TCB_FLAG_NONCANCELABLE) != 0) + if ((tls->tl_cpstate & CANCEL_FLAG_NONCANCELABLE) != 0) { *oldstate = TASK_CANCEL_DISABLE; } @@ -90,35 +85,29 @@ int task_setcancelstate(int state, FAR int *oldstate) { /* Clear the non-cancelable flag */ - tcb->flags &= ~TCB_FLAG_NONCANCELABLE; + tls->tl_cpstate &= ~CANCEL_FLAG_NONCANCELABLE; /* Check if a cancellation was pending */ - if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0) + if ((tls->tl_cpstate & CANCEL_FLAG_CANCEL_PENDING) != 0) { #ifdef CONFIG_CANCELLATION_POINTS /* If we are using deferred cancellation? */ - if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) == 0) + if ((tls->tl_cpstate & CANCEL_FLAG_CANCEL_ASYNC) != 0) #endif { /* No.. We are using asynchronous cancellation. If the * cancellation was pending in this case, then just exit. */ - tcb->flags &= ~TCB_FLAG_CANCEL_PENDING; + tls->tl_cpstate &= ~CANCEL_FLAG_CANCEL_PENDING; #ifndef CONFIG_DISABLE_PTHREAD - if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == - TCB_FLAG_TTYPE_PTHREAD) - { - pthread_exit(PTHREAD_CANCELED); - } - else + pthread_exit(PTHREAD_CANCELED); +#else + exit(EXIT_FAILURE); #endif - { - _exit(EXIT_FAILURE); - } } } } @@ -126,7 +115,7 @@ int task_setcancelstate(int state, FAR int *oldstate) { /* Set the non-cancelable state */ - tcb->flags |= TCB_FLAG_NONCANCELABLE; + tls->tl_cpstate |= CANCEL_FLAG_NONCANCELABLE; } else { @@ -134,6 +123,5 @@ int task_setcancelstate(int state, FAR int *oldstate) ret = ERROR; } - sched_unlock(); return ret; } diff --git a/libs/libc/sched/task_setcanceltype.c b/libs/libc/sched/task_setcanceltype.c index 0130d07e04a..dcad4e4e87d 100644 --- a/libs/libc/sched/task_setcanceltype.c +++ b/libs/libc/sched/task_setcanceltype.c @@ -22,8 +22,16 @@ * Included Files ****************************************************************************/ +#include + #include +#include #include +#include +#include + +#include +#include /**************************************************************************** * Public Functions @@ -46,14 +54,63 @@ int task_setcanceltype(int type, FAR int *oldtype) { + FAR struct tls_info_s *tls = tls_get_info(); + int ret = OK; + /* Return the current type if so requested */ if (oldtype != NULL) { - *oldtype = TASK_CANCEL_ASYNCHRONOUS; + if ((tls->tl_cpstate & CANCEL_FLAG_CANCEL_ASYNC) != 0) + { + *oldtype = TASK_CANCEL_ASYNCHRONOUS; + } + else + { + *oldtype = TASK_CANCEL_DEFERRED; + } } - /* Check the requested cancellation type */ + /* Set the new cancellation type */ - return (type == TASK_CANCEL_ASYNCHRONOUS) ? OK : EINVAL; + if (type == TASK_CANCEL_ASYNCHRONOUS) + { + /* Set the asynchronous cancellation bit */ + + tls->tl_cpstate |= CANCEL_FLAG_CANCEL_ASYNC; + +#ifdef CONFIG_CANCELLATION_POINTS + /* If we just switched from deferred to asynchronous type and if a + * cancellation is pending, then exit now. + */ + + if ((tls->tl_cpstate & CANCEL_FLAG_CANCEL_PENDING) != 0 && + (tls->tl_cpstate & CANCEL_FLAG_NONCANCELABLE) == 0) + { + tls->tl_cpstate &= ~CANCEL_FLAG_CANCEL_PENDING; + + /* Exit according to the type of the thread */ + +#ifndef CONFIG_DISABLE_PTHREAD + pthread_exit(PTHREAD_CANCELED); +#else + exit(EXIT_FAILURE); +#endif + } +#endif + } +#ifdef CONFIG_CANCELLATION_POINTS + else if (type == TASK_CANCEL_DEFERRED) + { + /* Set the deferred cancellation type */ + + tls->tl_cpstate &= ~CANCEL_FLAG_CANCEL_ASYNC; + } +#endif + else + { + ret = EINVAL; + } + + return ret; } diff --git a/libs/libc/sched/task_testcancel.c b/libs/libc/sched/task_testcancel.c index 6f3dfe6d959..6173cbcd5c3 100644 --- a/libs/libc/sched/task_testcancel.c +++ b/libs/libc/sched/task_testcancel.c @@ -22,7 +22,12 @@ * Included Files ****************************************************************************/ +#include + #include +#include + +#include /**************************************************************************** * Public Functions @@ -40,4 +45,8 @@ void task_testcancel(void) { +#ifdef CONFIG_CANCELLATION_POINTS + enter_cancellation_point(); + leave_cancellation_point(); +#endif } diff --git a/libs/libc/tls/tls_getinfo.c b/libs/libc/tls/tls_getinfo.c index faeb3da96b0..f613ea85a4c 100644 --- a/libs/libc/tls/tls_getinfo.c +++ b/libs/libc/tls/tls_getinfo.c @@ -36,7 +36,7 @@ ****************************************************************************/ /**************************************************************************** - * Name: tls_get_info + * Name: tls_get_info_pid * * Description: * Return a reference to the tls_info_s structure. This is used as part @@ -44,7 +44,7 @@ * where CONFIG_TLS_ALIGNED is *not* defined or __KERNEL__ is defined. * * Input Parameters: - * None + * pid - Thread ID to query, set to 0 to query own * * Returned Value: * A reference to the thread-specific tls_info_s structure is return on @@ -52,13 +52,13 @@ * ****************************************************************************/ -FAR struct tls_info_s *tls_get_info(void) +FAR struct tls_info_s *tls_get_info_pid(pid_t pid) { FAR struct tls_info_s *info = NULL; struct stackinfo_s stackinfo; int ret; - ret = nxsched_get_stackinfo(0, &stackinfo); + ret = nxsched_get_stackinfo(pid, &stackinfo); if (ret >= 0) { /* The TLS data lies at the lowest address of the stack allocation. diff --git a/sched/group/group_killchildren.c b/sched/group/group_killchildren.c index 06c300e91e4..bafe7340719 100644 --- a/sched/group/group_killchildren.c +++ b/sched/group/group_killchildren.c @@ -97,22 +97,12 @@ static int group_cancel_children_handler(pid_t pid, FAR void *arg) if (pid != (pid_t)((uintptr_t)arg)) { - /* 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 nxtask_delete() from doing what they - * need to do. - */ - rtcb = nxsched_get_tcb(pid); if (rtcb != NULL) { - /* This is a forced cancellation. Make sure that cancellation is - * not disabled by the task/thread. That bit would prevent - * pthread_cancel() or task_delete() from doing what they need - * to do. - */ + /* Cancel this thread. This is a forced cancellation. */ - rtcb->flags &= ~TCB_FLAG_NONCANCELABLE; + rtcb->flags |= TCB_FLAG_FORCED_CANCEL; /* 'pid' could refer to the main task of the thread. That pid * will appear in the group member list as well! diff --git a/sched/init/nx_start.c b/sched/init/nx_start.c index 21da0583f1e..9398a417aa6 100644 --- a/sched/init/nx_start.c +++ b/sched/init/nx_start.c @@ -367,9 +367,7 @@ void nx_start(void) */ #ifdef CONFIG_SMP - g_idletcb[i].cmn.flags = (TCB_FLAG_TTYPE_KERNEL | - TCB_FLAG_NONCANCELABLE | - TCB_FLAG_CPU_LOCKED); + g_idletcb[i].cmn.flags = (TCB_FLAG_TTYPE_KERNEL | TCB_FLAG_CPU_LOCKED); g_idletcb[i].cmn.cpu = i; /* Set the affinity mask to allow the thread to run on all CPUs. No, @@ -383,8 +381,7 @@ void nx_start(void) g_idletcb[i].cmn.affinity = (cpu_set_t)(CONFIG_SMP_DEFAULT_CPUSET & SCHED_ALL_CPUS); #else - g_idletcb[i].cmn.flags = (TCB_FLAG_TTYPE_KERNEL | - TCB_FLAG_NONCANCELABLE); + g_idletcb[i].cmn.flags = TCB_FLAG_TTYPE_KERNEL; #endif #if CONFIG_TASK_NAME_SIZE > 0 diff --git a/sched/misc/assert.c b/sched/misc/assert.c index 14dfa749537..a4e4f1bd14e 100644 --- a/sched/misc/assert.c +++ b/sched/misc/assert.c @@ -341,7 +341,7 @@ static void dump_task(FAR struct tcb_s *tcb, FAR void *arg) #ifdef CONFIG_SMP " %4d" #endif - " %3d %-8s %-7s %c%c%c" + " %3d %-8s %-7s %c" " %-18s" " " SIGSET_FMT " %p" @@ -363,8 +363,6 @@ static void dump_task(FAR struct tcb_s *tcb, FAR void *arg) TCB_FLAG_POLICY_SHIFT] , g_ttypenames[(tcb->flags & TCB_FLAG_TTYPE_MASK) >> TCB_FLAG_TTYPE_SHIFT] - , tcb->flags & TCB_FLAG_NONCANCELABLE ? 'N' : '-' - , tcb->flags & TCB_FLAG_CANCEL_PENDING ? 'P' : '-' , tcb->flags & TCB_FLAG_EXIT_PROCESSING ? 'P' : '-' , state , SIGSET_ELEM(&tcb->sigprocmask) diff --git a/sched/pthread/pthread_create.c b/sched/pthread/pthread_create.c index 65b172dec42..87452cdc3af 100644 --- a/sched/pthread/pthread_create.c +++ b/sched/pthread/pthread_create.c @@ -448,12 +448,6 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread, #endif } -#ifdef CONFIG_CANCELLATION_POINTS - /* Set the deferred cancellation type */ - - ptcb->cmn.flags |= TCB_FLAG_CANCEL_DEFERRED; -#endif - /* Get the assigned pid before we start the task (who knows what * could happen to ptcb after this!). */ diff --git a/sched/task/CMakeLists.txt b/sched/task/CMakeLists.txt index 061a8c90cc2..9e0f98ac544 100644 --- a/sched/task/CMakeLists.txt +++ b/sched/task/CMakeLists.txt @@ -33,7 +33,6 @@ set(SRCS task_recover.c task_restart.c task_spawnparms.c - task_setcancelstate.c task_cancelpt.c task_terminate.c task_gettid.c @@ -51,10 +50,6 @@ if(NOT CONFIG_BUILD_KERNEL) list(APPEND SRCS task_spawn.c) endif() -if(CONFIG_CANCELLATION_POINTS) - list(APPEND SRCS task_setcanceltype.c task_testcancel.c) -endif() - if(NOT CONFIG_BINFMT_DISABLE) if(CONFIG_LIBC_EXECFUNCS) list(APPEND SRCS task_execve.c task_posixspawn.c) diff --git a/sched/task/Make.defs b/sched/task/Make.defs index 41124aff07c..1db20a6a054 100644 --- a/sched/task/Make.defs +++ b/sched/task/Make.defs @@ -21,8 +21,8 @@ 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_cancelpt.c task_terminate.c task_gettid.c exit.c +CSRCS += task_restart.c task_spawnparms.c task_cancelpt.c task_terminate.c +CSRCS += task_gettid.c exit.c ifeq ($(CONFIG_SCHED_HAVE_PARENT),y) CSRCS += task_getppid.c task_reparent.c @@ -36,10 +36,6 @@ ifneq ($(CONFIG_BUILD_KERNEL),y) CSRCS += task_spawn.c endif -ifeq ($(CONFIG_CANCELLATION_POINTS),y) -CSRCS += task_setcanceltype.c task_testcancel.c -endif - ifneq ($(CONFIG_BINFMT_DISABLE),y) ifeq ($(CONFIG_LIBC_EXECFUNCS),y) CSRCS += task_execve.c task_posixspawn.c diff --git a/sched/task/task_cancelpt.c b/sched/task/task_cancelpt.c index 815d356cc68..4001152d181 100644 --- a/sched/task/task_cancelpt.c +++ b/sched/task/task_cancelpt.c @@ -58,6 +58,7 @@ #include #include +#include #include "sched/sched.h" #include "semaphore/semaphore.h" @@ -65,245 +66,10 @@ #include "mqueue/mqueue.h" #include "task/task.h" -#ifdef CONFIG_CANCELLATION_POINTS - /**************************************************************************** * Public Functions ****************************************************************************/ -/**************************************************************************** - * Name: enter_cancellation_point - * - * Description: - * Called at the beginning of the cancellation point to establish the - * cancellation point. This function does the following: - * - * 1. If deferred cancellation does not apply to this thread, nothing is - * done, otherwise, it - * 2. Sets state information in the caller's TCB and increments a nesting - * count. - * 3. If this is the outermost nesting level, it checks if there is a - * pending cancellation and, if so, calls either exit() or - * pthread_exit(), depending upon the type of the thread. - * - * Input Parameters: - * None - * - * Returned Value: - * true is returned if a cancellation is pending but cannot be performed - * now due to the nesting level. - * - ****************************************************************************/ - -bool enter_cancellation_point(void) -{ - FAR struct tcb_s *tcb = this_task(); - bool ret = false; - - /* Disabling pre-emption should provide sufficient protection. We only - * need the TCB to be stationary (no interrupt level modification is - * anticipated). - * - * REVISIT: is locking the scheduler sufficient in SMP mode? - */ - - sched_lock(); - - /* If cancellation is disabled on this thread or if this thread is using - * asynchronous cancellation, then do nothing. - * - * Special case: if the cpcount count is greater than zero, then we are - * nested and the above condition was certainly true at the outermost - * nesting level. - */ - - if (((tcb->flags & TCB_FLAG_NONCANCELABLE) == 0 && - (tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) || - tcb->cpcount > 0) - { - /* Check if there is a pending cancellation */ - - if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0) - { - /* Yes... return true (if we don't exit here) */ - - ret = true; - - /* If there is a pending cancellation and we are at the outermost - * nesting level of cancellation function calls, then exit - * according to the type of the thread. - */ - - if (tcb->cpcount == 0) - { -#ifndef CONFIG_DISABLE_PTHREAD - if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == - TCB_FLAG_TTYPE_PTHREAD) - { - pthread_exit(PTHREAD_CANCELED); - } - else -#endif - { - _exit(EXIT_FAILURE); - } - } - } - - /* Otherwise, indicate that we are at a cancellation point by - * incrementing the nesting level of the cancellation point - * functions. - */ - - DEBUGASSERT(tcb->cpcount < INT16_MAX); - tcb->cpcount++; - } - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: leave_cancellation_point - * - * Description: - * Called at the end of the cancellation point. This function does the - * following: - * - * 1. If deferred cancellation does not apply to this thread, nothing is - * done, otherwise, it - * 2. Clears state information in the caller's TCB and decrements a - * nesting count. - * 3. If this is the outermost nesting level, it checks if there is a - * pending cancellation and, if so, calls either exit() or - * pthread_exit(), depending upon the type of the thread. - * - * Input Parameters: - * None - * - * Returned Value: - * None - * - ****************************************************************************/ - -void leave_cancellation_point(void) -{ - FAR struct tcb_s *tcb = this_task(); - - /* Disabling pre-emption should provide sufficient protection. We only - * need the TCB to be stationary (no interrupt level modification is - * anticipated). - * - * REVISIT: is locking the scheduler sufficient in SMP mode? - */ - - sched_lock(); - - /* If cancellation is disabled on this thread or if this thread is using - * asynchronous cancellation, then do nothing. Here we check only the - * nesting level: if the cpcount count is greater than zero, then the - * required condition was certainly true at the outermost nesting level. - */ - - if (tcb->cpcount > 0) - { - /* Decrement the nesting level. If if would decrement to zero, then - * we are at the outermost nesting level and may need to do more. - */ - - if (tcb->cpcount == 1) - { - /* We are no longer at the cancellation point */ - - tcb->cpcount = 0; - - /* If there is a pending cancellation then just exit according to - * the type of the thread. - */ - - if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0) - { -#ifndef CONFIG_DISABLE_PTHREAD - if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == - TCB_FLAG_TTYPE_PTHREAD) - { - pthread_exit(PTHREAD_CANCELED); - } - else -#endif - { - _exit(EXIT_FAILURE); - } - } - } - else - { - /* We are not at the outermost nesting level. Just decrment the - * nesting level count. - */ - - tcb->cpcount--; - } - } - - sched_unlock(); -} - -/**************************************************************************** - * Name: check_cancellation_point - * - * Description: - * Returns true if: - * - * 1. Deferred cancellation does applies to this thread, - * 2. We are within a cancellation point (i.e., the nesting level in the - * TCB is greater than zero). - * - * Input Parameters: - * None - * - * Returned Value: - * true is returned if a cancellation is pending but cannot be performed - * now due to the nesting level. - * - ****************************************************************************/ - -bool check_cancellation_point(void) -{ - FAR struct tcb_s *tcb = this_task(); - bool ret = false; - - /* Disabling pre-emption should provide sufficient protection. We only - * need the TCB to be stationary (no interrupt level modification is - * anticipated). - * - * REVISIT: is locking the scheduler sufficient in SMP mode? - */ - - sched_lock(); - - /* If cancellation is disabled on this thread or if this thread is using - * asynchronous cancellation, then return false. - * - * If the cpcount count is greater than zero, then we within a - * cancellation and will true if there is a pending cancellation. - */ - - if (((tcb->flags & TCB_FLAG_NONCANCELABLE) == 0 && - (tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) || - tcb->cpcount > 0) - { - /* Check if there is a pending cancellation. If so, return true. */ - - ret = ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0); - } - - sched_unlock(); - return ret; -} - -#endif /* CONFIG_CANCELLATION_POINTS */ - /**************************************************************************** * Name: nxnotify_cancellation * @@ -322,6 +88,7 @@ bool check_cancellation_point(void) bool nxnotify_cancellation(FAR struct tcb_s *tcb) { + FAR struct tls_info_s *tls = tls_get_info_pid(tcb->pid); irqstate_t flags; bool ret = false; @@ -338,7 +105,8 @@ bool nxnotify_cancellation(FAR struct tcb_s *tcb) /* Check to see if this task has the non-cancelable bit set. */ - if ((tcb->flags & TCB_FLAG_NONCANCELABLE) != 0) + if ((tcb->flags & TCB_FLAG_FORCED_CANCEL) == 0 && + (tls->tl_cpstate & CANCEL_FLAG_NONCANCELABLE) != 0) { /* Then we cannot cancel the thread now. Here is how this is * supposed to work: @@ -353,7 +121,7 @@ bool nxnotify_cancellation(FAR struct tcb_s *tcb) * immediately, interrupting the thread with its processing." */ - tcb->flags |= TCB_FLAG_CANCEL_PENDING; + tls->tl_cpstate |= CANCEL_FLAG_CANCEL_PENDING; leave_critical_section(flags); return true; } @@ -361,7 +129,7 @@ bool nxnotify_cancellation(FAR struct tcb_s *tcb) #ifdef CONFIG_CANCELLATION_POINTS /* Check if this task supports deferred cancellation */ - if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) + if ((tls->tl_cpstate & CANCEL_FLAG_CANCEL_ASYNC) == 0) { /* Then we cannot cancel the task asynchronously. */ @@ -369,13 +137,13 @@ bool nxnotify_cancellation(FAR struct tcb_s *tcb) /* Mark the cancellation as pending. */ - tcb->flags |= TCB_FLAG_CANCEL_PENDING; + tls->tl_cpstate |= CANCEL_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 (tls->tl_cpcount > 0) { /* If the thread is blocked waiting for a semaphore, then the * thread must be unblocked to handle the cancellation. diff --git a/sched/task/task_exithook.c b/sched/task/task_exithook.c index ae6dcc76cd6..ca1a7ef2daa 100644 --- a/sched/task/task_exithook.c +++ b/sched/task/task_exithook.c @@ -430,17 +430,6 @@ void nxtask_exithook(FAR struct tcb_s *tcb, int status) return; } -#ifdef CONFIG_CANCELLATION_POINTS - /* Mark the task as non-cancelable to avoid additional calls to exit() - * due to any cancellation point logic that might get kicked off by - * actions taken during exit processing. - */ - - tcb->flags |= TCB_FLAG_NONCANCELABLE; - tcb->flags &= ~TCB_FLAG_CANCEL_PENDING; - tcb->cpcount = 0; -#endif - /* If the task was terminated by another task, it may be in an unknown * state. Make some feeble effort to recover the state. */ diff --git a/sched/task/task_setcanceltype.c b/sched/task/task_setcanceltype.c deleted file mode 100644 index cf4f7bcd389..00000000000 --- a/sched/task/task_setcanceltype.c +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** - * sched/task/task_setcanceltype.c - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include -#include -#include - -#include "sched/sched.h" -#include "task/task.h" - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_setcanceltype - * - * Description: - * The task_setcanceltype() function atomically both sets the calling - * thread's cancellability type to the indicated type and returns the - * previous cancellability type at the location referenced by oldtype - * Legal values for type are TASK_CANCEL_DEFERRED and - * TASK_CANCEL_ASYNCHRONOUS. - * - * The cancellability state and type of any newly created threads, - * including the thread in which main() was first invoked, are - * TASK_CANCEL_ENABLE and TASK_CANCEL_DEFERRED respectively. - * - ****************************************************************************/ - -int task_setcanceltype(int type, FAR int *oldtype) -{ - FAR struct tcb_s *tcb = this_task(); - int ret = OK; - - /* Suppress context changes for a bit so that the flags are stable. (the - * flags should not change in interrupt handling). - */ - - sched_lock(); - - /* Return the current type if so requested */ - - if (oldtype != NULL) - { - if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) - { - *oldtype = TASK_CANCEL_DEFERRED; - } - else - { - *oldtype = TASK_CANCEL_ASYNCHRONOUS; - } - } - - /* Set the new cancellation type */ - - if (type == TASK_CANCEL_ASYNCHRONOUS) - { - /* Clear the deferred cancellation bit */ - - tcb->flags &= ~TCB_FLAG_CANCEL_DEFERRED; - -#ifdef CONFIG_CANCELLATION_POINTS - /* If we just switched from deferred to asynchronous type and if a - * cancellation is pending, then exit now. - */ - - if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0 && - (tcb->flags & TCB_FLAG_NONCANCELABLE) == 0) - { - tcb->flags &= ~TCB_FLAG_CANCEL_PENDING; - - /* Exit according to the type of the thread */ - -#ifndef CONFIG_DISABLE_PTHREAD - if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD) - { - pthread_exit(PTHREAD_CANCELED); - } - else -#endif - { - _exit(EXIT_FAILURE); - } - } -#endif - } -#ifdef CONFIG_CANCELLATION_POINTS - else if (type == TASK_CANCEL_DEFERRED) - { - /* Set the deferred cancellation type */ - - tcb->flags |= TCB_FLAG_CANCEL_DEFERRED; - } -#endif - else - { - ret = EINVAL; - } - - sched_unlock(); - return ret; -} diff --git a/sched/task/task_setup.c b/sched/task/task_setup.c index 3adf7df2577..b41a37899c3 100644 --- a/sched/task/task_setup.c +++ b/sched/task/task_setup.c @@ -409,12 +409,6 @@ static int nxthread_setup_scheduler(FAR struct tcb_s *tcb, int priority, tcb->flags |= TCB_FLAG_SCHED_FIFO; #endif -#ifdef CONFIG_CANCELLATION_POINTS - /* Set the deferred cancellation type */ - - tcb->flags |= TCB_FLAG_CANCEL_DEFERRED; -#endif - /* Save the task ID of the parent task in the TCB and allocate * a child status structure. */ diff --git a/sched/task/task_testcancel.c b/sched/task/task_testcancel.c deleted file mode 100644 index c2c1a45ea99..00000000000 --- a/sched/task/task_testcancel.c +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** - * sched/task/task_testcancel.c - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -#include -#include - -#include - -#include "task/task.h" - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_testcancel - * - * Description: - * The task_testcancel() function creates a cancellation point in the - * calling thread. The task_testcancel() function has no effect if - * cancellability is disabled - * - ****************************************************************************/ - -void task_testcancel(void) -{ - enter_cancellation_point(); - leave_cancellation_point(); -} diff --git a/syscall/syscall.csv b/syscall/syscall.csv index 687e856cf1f..92b1532e206 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -184,10 +184,7 @@ "task_create","sched.h","!defined(CONFIG_BUILD_KERNEL)", "int","FAR const char *","int","int","main_t","FAR char * const []|FAR char * const *" "task_delete","sched.h","!defined(CONFIG_BUILD_KERNEL)","int","pid_t" "task_restart","sched.h","!defined(CONFIG_BUILD_KERNEL)","int","pid_t" -"task_setcancelstate","sched.h","","int","int","FAR int *" -"task_setcanceltype","sched.h","defined(CONFIG_CANCELLATION_POINTS)","int","int","FAR int *" "task_spawn","nuttx/spawn.h","!defined(CONFIG_BUILD_KERNEL)","int","FAR const char *","main_t","FAR const posix_spawn_file_actions_t *","FAR const posix_spawnattr_t *","FAR char * const []|FAR char * const *","FAR char * const []|FAR char * const *" -"task_testcancel","sched.h","defined(CONFIG_CANCELLATION_POINTS)","void" "tgkill","signal.h","","int","pid_t","pid_t","int" "time","time.h","","time_t","FAR time_t *" "timer_create","time.h","!defined(CONFIG_DISABLE_POSIX_TIMERS)","int","clockid_t","FAR struct sigevent *","FAR timer_t *"