Flesh basic cancellation point support
This commit is contained in:
parent
82a79b9c1b
commit
d35e589d56
@ -168,14 +168,18 @@ EXTERN const pthread_attr_t g_default_pthread_attr;
|
||||
* 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
|
||||
* pthread_exit(), depending upon the type of the thread.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void leave_cancellation_point(void);
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
void enter_cancellation_point(void);
|
||||
#else
|
||||
# define enter_cancellation_point()
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: enter_cancellation_point
|
||||
* Name: leave_cancellation_point
|
||||
*
|
||||
* Description:
|
||||
* Called at the end of the cancellation point. This function does the
|
||||
@ -187,11 +191,15 @@ void leave_cancellation_point(void);
|
||||
* 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
|
||||
* pthread_exit(), depending upon the type of the thread.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void enter_cancellation_point(void);
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
void leave_cancellation_point(void);
|
||||
#else
|
||||
# define leave_cancellation_point()
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
|
@ -142,17 +142,16 @@
|
||||
# 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_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_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_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 << 8) /* Bit 8: Locked to this CPU */
|
||||
#define TCB_FLAG_EXIT_PROCESSING (1 << 9) /* Bit 9: Exitting */
|
||||
/* Bits 10-15: Available */
|
||||
#define TCB_FLAG_CPU_LOCKED (1 << 7) /* Bit 7: Locked to this CPU */
|
||||
#define TCB_FLAG_EXIT_PROCESSING (1 << 8) /* Bit 8: Exitting */
|
||||
/* Bits 9-15: Available */
|
||||
|
||||
/* Values for struct task_group tg_flags */
|
||||
|
||||
@ -584,6 +583,9 @@ struct tcb_s
|
||||
#ifdef CONFIG_SMP
|
||||
int16_t irqcount; /* 0=interrupts enabled */
|
||||
#endif
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
int16_t cpcount; /* Nested cancellation point count */
|
||||
#endif
|
||||
|
||||
#if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC)
|
||||
int32_t timeslice; /* RR timeslice OR Sporadic budget */
|
||||
|
@ -111,9 +111,9 @@ int pthread_setcancelstate(int state, FAR int *oldstate)
|
||||
* notify of the cancellation.
|
||||
*/
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_CANCEL_POINT) != 0)
|
||||
if (tcb->cpcount > 0)
|
||||
{
|
||||
notify_cancellation();
|
||||
notify_cancellation(tcb);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -83,7 +83,7 @@ void task_recover(FAR struct tcb_s *tcb);
|
||||
/* Cancellation points */
|
||||
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
void notify_cancellation(void);
|
||||
void notify_cancellation(FAR struct tcb_s *tcb);
|
||||
#endif
|
||||
|
||||
#endif /* __SCHED_TASK_TASK_H */
|
||||
|
@ -68,9 +68,14 @@
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sched.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/pthread.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "semaphore/semaphore.h"
|
||||
#include "mqueue/mqueue.h"
|
||||
#include "task/task.h"
|
||||
|
||||
#ifdef CONFIG_CANCELLATION_POINTS
|
||||
@ -92,17 +97,67 @@
|
||||
* 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
|
||||
* pthread_exit(), depending upon the type of the thread.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void leave_cancellation_point(void)
|
||||
void enter_cancellation_point(void)
|
||||
{
|
||||
#warning Missing logic
|
||||
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).
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
/* If there is a pending cancellation and we are at the outermost
|
||||
* nesting level of cancellation function calls, then just exit
|
||||
* according to the type of the thread.
|
||||
*/
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_CANCEL_PENDING) != 0 &&
|
||||
tcb->cpcount == 0)
|
||||
{
|
||||
#ifndef CONFIG_DISABLE_PTHREAD
|
||||
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_PTHREAD)
|
||||
{
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: enter_cancellation_point
|
||||
* Name: leave_cancellation_point
|
||||
*
|
||||
* Description:
|
||||
* Called at the end of the cancellation point. This function does the
|
||||
@ -114,13 +169,68 @@ void leave_cancellation_point(void)
|
||||
* 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
|
||||
* pthread_exit(), depending upon the type of the thread.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void enter_cancellation_point(void)
|
||||
void leave_cancellation_point(void)
|
||||
{
|
||||
#warning Missing logic
|
||||
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).
|
||||
*/
|
||||
|
||||
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(NULL);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We are not at the outermost nesting level. Just decrment the
|
||||
* nesting level count.
|
||||
*/
|
||||
|
||||
tcb->cpcount--;
|
||||
}
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -136,9 +246,52 @@ void enter_cancellation_point(void)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void notify_cancellation(void)
|
||||
void notify_cancellation(FAR struct tcb_s *tcb)
|
||||
{
|
||||
#warning Missing logic
|
||||
irqstate_t flags;
|
||||
|
||||
/* We need perform the following operations from within a critical section
|
||||
* because it can compete with interrupt level activity.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Make sure that the cancellation pending indication is set. */
|
||||
|
||||
tcb->flags |= TCB_FLAG_CANCEL_PENDING;
|
||||
|
||||
/* We only notify the cancellation if (1) the thread has not disabled
|
||||
* cancellation, (2) the thread uses the deffered cancellation mode,
|
||||
* (3) the thread is waiting within a cancellation point.
|
||||
*/
|
||||
|
||||
if (((tcb->flags & TCB_FLAG_NONCANCELABLE) == 0 &&
|
||||
(tcb->flags & TCB_FLAG_CANCEL_DEFERRED) != 0) ||
|
||||
tcb->cpcount > 0)
|
||||
{
|
||||
/* If the thread is blocked waiting for a semaphore, then the thread
|
||||
* must be unblocked to handle the cancellation.
|
||||
*/
|
||||
|
||||
if (tcb->task_state == TSTATE_WAIT_SEM)
|
||||
{
|
||||
sem_waitirq(tcb, ECANCELED);
|
||||
}
|
||||
|
||||
/* If the thread is blocked waiting on a message queue, then the
|
||||
* thread must be unblocked to handle the cancellation.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_DISABLE_MQUEUE
|
||||
if (tcb->task_state == TSTATE_WAIT_MQNOTEMPTY ||
|
||||
tcb->task_state == TSTATE_WAIT_MQNOTFULL)
|
||||
{
|
||||
mq_waitirq(tcb, ECANCELED);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_CANCELLATION_POINTS */
|
||||
|
Loading…
Reference in New Issue
Block a user