diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h index 1db8b70a24..0eb9432973 100644 --- a/include/nuttx/sched.h +++ b/include/nuttx/sched.h @@ -141,16 +141,18 @@ # 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_PENDING (1 << 3) /* Bit 3: Pthread cancel is pending */ -#define TCB_FLAG_POLICY_SHIFT (4) /* Bit 4-5: Scheduling policy */ +#define TCB_FLAG_CANCEL_DEFERRED (1 << 3) /* Bit 3: Deferred (vs asynch) cancellation type */ +#define TCB_FLAG_CANCEL_POINT (1 << 4) /* Bit 4: At a cancellation point */ +#define TCB_FLAG_CANCEL_PENDING (1 << 5) /* Bit 5: Pthread cancel is pending */ +#define TCB_FLAG_POLICY_SHIFT (6) /* Bit 6-7: 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_SCHED_OTHER (3 << TCB_FLAG_POLICY_SHIFT) /* Other scheding policy */ -#define TCB_FLAG_CPU_LOCKED (1 << 6) /* Bit 6: Locked to this CPU */ -#define TCB_FLAG_EXIT_PROCESSING (1 << 7) /* Bit 7: Exitting */ - /* Bits 8-15: Available */ +#define TCB_FLAG_CPU_LOCKED (1 << 8) /* Bit 8: Locked to this CPU */ +#define TCB_FLAG_EXIT_PROCESSING (1 << 9) /* Bit 9: Exitting */ + /* Bits 10-15: Available */ /* Values for struct task_group tg_flags */ diff --git a/include/pthread.h b/include/pthread.h index 28bb0add97..d943a843e2 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -115,11 +115,16 @@ #define PTHREAD_DEFAULT_PRIORITY 100 -/* Cancellation states returned by pthread_cancelstate() */ +/* Cancellation states used by pthread_setcancelstate() */ #define PTHREAD_CANCEL_ENABLE (0) #define PTHREAD_CANCEL_DISABLE (1) +/* Cancellation types used by pthread_setcanceltype() */ + +#define PTHREAD_CANCEL_DEFERRED (0) +#define PTHREAD_CANCEL_ASYNCHRONOUS (1) + /* Thread return value when a pthread is canceled */ #define PTHREAD_CANCELED ((FAR void*)ERROR) @@ -340,6 +345,7 @@ int pthread_detach(pthread_t thread); void pthread_exit(pthread_addr_t value) noreturn_function; int pthread_cancel(pthread_t thread); int pthread_setcancelstate(int state, FAR int *oldstate); +int pthread_setcanceltype(int type, FAR int *oldtype); void pthread_testcancel(void); /* A thread may set up cleanup functions to execut when the thread exits or diff --git a/sched/Kconfig b/sched/Kconfig index 58078d10fa..d3d9230d6e 100644 --- a/sched/Kconfig +++ b/sched/Kconfig @@ -560,6 +560,15 @@ config PTHREAD_CLEANUP_STACKSIZE endmenu # Pthread Options +config CANCELLATION_POINTS + bool "Cancellation points" + default n + depends on EXPERIMENTAL + ---help--- + Enable POSIX cancellation points for pthread_cancel(). If selected, + cancellation points will also used with the () task_delete() API even if + pthreads are not enabled. + menu "Performance Monitoring" config SCHED_CPULOAD diff --git a/sched/pthread/Make.defs b/sched/pthread/Make.defs index a08315c732..f589f3dfef 100644 --- a/sched/pthread/Make.defs +++ b/sched/pthread/Make.defs @@ -42,7 +42,8 @@ CSRCS += pthread_mutexlock.c pthread_mutextrylock.c pthread_mutexunlock.c CSRCS += pthread_condinit.c pthread_conddestroy.c CSRCS += pthread_condwait.c pthread_condsignal.c pthread_condbroadcast.c CSRCS += pthread_barrierinit.c pthread_barrierdestroy.c pthread_barrierwait.c -CSRCS += pthread_cancel.c pthread_setcancelstate.c +CSRCS += pthread_cancel.c pthread_setcancelstate.c pthread_setcanceltype.c +CSRCS += pthread_testcancel.c CSRCS += pthread_keycreate.c pthread_setspecific.c pthread_getspecific.c pthread_keydelete.c CSRCS += pthread_initialize.c pthread_completejoin.c pthread_findjoininfo.c CSRCS += pthread_once.c pthread_release.c pthread_setschedprio.c diff --git a/sched/pthread/pthread_cleanup.c b/sched/pthread/pthread_cleanup.c index 7310c08cb6..6c71cd8c13 100644 --- a/sched/pthread/pthread_cleanup.c +++ b/sched/pthread/pthread_cleanup.c @@ -67,6 +67,9 @@ * Return Value: * None * + * Assumptions: + * The scheduler is locked. + * ****************************************************************************/ static void pthread_cleanup_pop_tcb(FAR struct pthread_tcb_s *tcb, int execute) diff --git a/sched/pthread/pthread_create.c b/sched/pthread/pthread_create.c index 6efc9aa21a..7a4e628e00 100644 --- a/sched/pthread/pthread_create.c +++ b/sched/pthread/pthread_create.c @@ -483,6 +483,12 @@ int pthread_create(FAR pthread_t *thread, FAR const pthread_attr_t *attr, #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!). Copy this ID into the join structure * as well. diff --git a/sched/pthread/pthread_setcancelstate.c b/sched/pthread/pthread_setcancelstate.c index b9aab9a7d1..4c457766fa 100644 --- a/sched/pthread/pthread_setcancelstate.c +++ b/sched/pthread/pthread_setcancelstate.c @@ -47,6 +47,18 @@ /**************************************************************************** * Name: pthread_setcancelstate + * + * Description: + * The pthread_setcancelstate() function atomically both sets the calling + * thread's cancelability state to the indicated state and returns the + * previous cancelability state at the location referenced by oldstate. + * Legal values for state are PTHREAD_CANCEL_ENABLE and + * PTHREAD_CANCEL_DISABLE. + * + * The cancelability state and type of any newly created threads, + * including the thread in which main() was first invoked, are + * PTHREAD_CANCEL_ENABLE and PTHREAD_CANCEL_DEFERRED respectively. + * ****************************************************************************/ int pthread_setcancelstate(int state, FAR int *oldstate) @@ -78,17 +90,38 @@ int pthread_setcancelstate(int state, FAR int *oldstate) if (state == PTHREAD_CANCEL_ENABLE) { - unsigned flags = tcb->flags; + /* Clear the non-cancelable flag */ - /* Clear the non-cancelable and cancel pending flags */ + tcb->flags &= ~TCB_FLAG_NONCANCELABLE; - tcb->flags &= ~(TCB_FLAG_NONCANCELABLE | TCB_FLAG_CANCEL_PENDING); + /* Check if a cancellation was pending */ - /* If the cancel was pending, then just exit as requested */ - - if (flags & TCB_FLAG_CANCEL_PENDING) + if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0) { - pthread_exit(PTHREAD_CANCELED); +#ifdef CONFIG_CANCELLATION_POINTS + /* If we are using deferred cancellation? */ + + if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) + { + /* Yes.. If we are within a cancellation point, then + * notify of the cancellation. + */ + + if (tcb->flags & TCB_FLAG_CANCEL_POINT) != 0) + { +# warning Missing logic + } + } + else +#endif + { + /* No.. We are using asynchronous cancellation. If the + * cancellation was pending in this case, then just exit. + */ + + tcb->flags &= ~TCB_FLAG_CANCEL_PENDING; + pthread_exit(PTHREAD_CANCELED); + } } } else if (state == PTHREAD_CANCEL_DISABLE) diff --git a/sched/pthread/pthread_setcanceltype.c b/sched/pthread/pthread_setcanceltype.c new file mode 100644 index 0000000000..ca88ea3ddb --- /dev/null +++ b/sched/pthread/pthread_setcanceltype.c @@ -0,0 +1,128 @@ +/**************************************************************************** + * sched/pthread/pthread_setcanceltype.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sched/sched.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_setcancelstate + * + * Description: + * The pthread_setcanceltype() function atomically both sets the calling + * thread's cancelability type to the indicated type and returns the + * previous cancelability type at the location referenced by oldtype + * Legal values for type are PTHREAD_CANCEL_DEFERRED and + * PTHREAD_CANCEL_ASYNCHRONOUS. + * + * The cancelability state and type of any newly created threads, + * including the thread in which main() was first invoked, are + * PTHREAD_CANCEL_ASYNCHRONOUS and PTHREAD_CANCEL_DEFERRED respectively. + * + ****************************************************************************/ + +int pthread_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 requrested */ + + if (oldtype) + { + if ((tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) + { + *oldtype = PTHREAD_CANCEL_DEFERRED; + } + else + { + *oldtype = PTHREAD_CANCEL_ASYNCHRONOUS; + } + } + + /* Set the new cancellation type */ + + if (type == PTHREAD_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; + pthread_exit(PTHREAD_CANCELED); + } +#endif + } +#ifdef CONFIG_CANCELLATION_POINTS + else if (type == PTHREAD_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/pthread/pthread_testcancel.c b/sched/pthread/pthread_testcancel.c new file mode 100644 index 0000000000..0e6186dec2 --- /dev/null +++ b/sched/pthread/pthread_testcancel.c @@ -0,0 +1,66 @@ +/**************************************************************************** + * sched/pthread/pthread_testcancel.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include "sched/sched.h" + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_testcancel + * + * Description: + * The pthread_testcancel() function creates a cancellation point in the + * calling thread. The pthread_testcancel() function has no effect if + * cancelability is disabled + * + ****************************************************************************/ + +void pthread_testcancel(void) +{ +#ifdef CONFIG_CANCELLATION_POINTS +# warning Missing Logic +#endif +} diff --git a/sched/task/task_setup.c b/sched/task/task_setup.c index 7b8b086434..19736f86ab 100644 --- a/sched/task/task_setup.c +++ b/sched/task/task_setup.c @@ -378,6 +378,12 @@ static int thread_schedsetup(FAR struct tcb_s *tcb, int priority, tcb->flags &= ~TCB_FLAG_TTYPE_MASK; tcb->flags |= ttype; +#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. */