task/pthread_cancelpt: Move cancel point handling to libc, data to TLS

This moves task / thread cancel point logic from the NuttX kernel into
libc, while the data needed by the cancel point logic is moved to TLS.

The change is an enabler to move user-space APIs to libc as well, for
a coherent user/kernel separation.
This commit is contained in:
Ville Juven 2023-11-10 12:56:10 +02:00 committed by Xiang Xiao
parent 1e31ec8003
commit 0dedbcd4ae
24 changed files with 414 additions and 547 deletions

View file

@ -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,

View file

@ -58,6 +58,14 @@
#include <stdbool.h>
/****************************************************************************
* 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
****************************************************************************/

View file

@ -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 */

View file

@ -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
*

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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 <nuttx/config.h>
#include <sched.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <nuttx/cancelpt.h>
#include <nuttx/tls.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 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 */

View file

@ -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 <nuttx/config.h>
#include <stdlib.h>
#include <pthread.h>
#include <sched.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include "sched/sched.h"
#include "task/task.h"
#include <nuttx/cancelpt.h>
#include <nuttx/tls.h>
/****************************************************************************
* 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
#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;
}

View file

@ -22,8 +22,16 @@
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sched.h>
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <nuttx/cancelpt.h>
#include <nuttx/tls.h>
/****************************************************************************
* 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)
{
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;
}

View file

@ -22,7 +22,12 @@
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sched.h>
#include <errno.h>
#include <nuttx/cancelpt.h>
/****************************************************************************
* Public Functions
@ -40,4 +45,8 @@
void task_testcancel(void)
{
#ifdef CONFIG_CANCELLATION_POINTS
enter_cancellation_point();
leave_cancellation_point();
#endif
}

View file

@ -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.

View file

@ -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!

View file

@ -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

View file

@ -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)

View file

@ -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!).
*/

View file

@ -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)

View file

@ -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

View file

@ -58,6 +58,7 @@
#include <nuttx/irq.h>
#include <nuttx/cancelpt.h>
#include <nuttx/tls.h>
#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.

View file

@ -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.
*/

View file

@ -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 <nuttx/config.h>
#include <stdlib.h>
#include <pthread.h>
#include <sched.h>
#include <errno.h>
#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;
}

View file

@ -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.
*/

View file

@ -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 <nuttx/config.h>
#include <sched.h>
#include <errno.h>
#include <nuttx/cancelpt.h>
#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();
}

View file

@ -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 *"

Can't render this file because it has a wrong number of fields in line 2.