diff --git a/sched/sched/sched_lock.c b/sched/sched/sched_lock.c index d07e751b994..f0400b57dc2 100644 --- a/sched/sched/sched_lock.c +++ b/sched/sched/sched_lock.c @@ -148,13 +148,15 @@ int sched_lock(void) if (rtcb != NULL && !up_interrupt_context()) { + irqstate_t flags; + /* Catch attempts to increment the lockcount beyond the range of the * integer type. */ DEBUGASSERT(rtcb->lockcount < MAX_LOCK_COUNT); - irqstate_t flags = enter_critical_section(); + flags = enter_critical_section(); /* We must hold the lock on this CPU before we increment the lockcount * for the first time. Holding the lock is sufficient to lockout @@ -234,12 +236,17 @@ int sched_lock(void) if (rtcb != NULL && !up_interrupt_context()) { + FAR struct tcb_s *ptcb; + irqstate_t flags; + /* Catch attempts to increment the lockcount beyond the range of the * integer type. */ DEBUGASSERT(rtcb->lockcount < MAX_LOCK_COUNT); + flags = enter_critical_section(); + /* A counter is used to support locking. This allows nested lock * operations on this thread (on any CPU) */ @@ -262,6 +269,22 @@ int sched_lock(void) #endif } #endif + + /* Move any tasks in the ready-to-run list to the pending task list + * where they will not be available to run until the scheduler is + * unlocked and nxsched_merge_pending() is called. So ready-to-run + * will consist only from the currently runnig task and the idle task. + */ + + for (ptcb = rtcb->flink; ptcb && ptcb->flink; ptcb = rtcb->flink) + { + dq_rem((FAR dq_entry_t *)ptcb, &g_readytorun); + + nxsched_add_prioritized(ptcb, &g_pendingtasks); + ptcb->task_state = TSTATE_TASK_PENDING; + } + + leave_critical_section(flags); } return OK; diff --git a/sched/sched/sched_mergepending.c b/sched/sched/sched_mergepending.c index 5c30d3ca6c7..9915eb3abde 100644 --- a/sched/sched/sched_mergepending.c +++ b/sched/sched/sched_mergepending.c @@ -82,73 +82,79 @@ bool nxsched_merge_pending(void) rtcb = this_task(); - /* Process every TCB in the g_pendingtasks list */ + /* Process every TCB in the g_pendingtasks list + * + * Do nothing if pre-emption is still disabled + */ - for (ptcb = (FAR struct tcb_s *)g_pendingtasks.head; - ptcb; - ptcb = pnext) + if (rtcb->lockcount == 0) { - pnext = ptcb->flink; - - /* REVISIT: Why don't we just remove the ptcb from pending task list - * and call nxsched_add_readytorun? - */ - - /* Search the ready-to-run list to find the location to insert the - * new ptcb. Each is list is maintained in ascending sched_priority - * order. - */ - - for (; - (rtcb && ptcb->sched_priority <= rtcb->sched_priority); - rtcb = rtcb->flink) + for (ptcb = (FAR struct tcb_s *)g_pendingtasks.head; + ptcb; + ptcb = pnext) { + pnext = ptcb->flink; + + /* REVISIT: Why don't we just remove the ptcb from pending task + * list and call nxsched_add_readytorun? + */ + + /* Search the ready-to-run list to find the location to insert the + * new ptcb. Each is list is maintained in ascending sched_priority + * order. + */ + + for (; + (rtcb && ptcb->sched_priority <= rtcb->sched_priority); + rtcb = rtcb->flink) + { + } + + /* Add the ptcb to the spot found in the list. Check if the + * ptcb goes at the ends of the ready-to-run list. This would be + * error condition since the idle test must always be at the end of + * the ready-to-run list! + */ + + DEBUGASSERT(rtcb); + + /* The ptcb goes just before rtcb */ + + rprev = rtcb->blink; + if (rprev == NULL) + { + /* Special case: Inserting ptcb at the head of the list */ + + ptcb->flink = rtcb; + ptcb->blink = NULL; + rtcb->blink = ptcb; + g_readytorun.head = (FAR dq_entry_t *)ptcb; + rtcb->task_state = TSTATE_TASK_READYTORUN; + ptcb->task_state = TSTATE_TASK_RUNNING; + ret = true; + } + else + { + /* Insert in the middle of the list */ + + ptcb->flink = rtcb; + ptcb->blink = rprev; + rprev->flink = ptcb; + rtcb->blink = ptcb; + ptcb->task_state = TSTATE_TASK_READYTORUN; + } + + /* Set up for the next time through */ + + rtcb = ptcb; } - /* Add the ptcb to the spot found in the list. Check if the - * ptcb goes at the ends of the ready-to-run list. This would be - * error condition since the idle test must always be at the end of - * the ready-to-run list! - */ + /* Mark the input list empty */ - DEBUGASSERT(rtcb); - - /* The ptcb goes just before rtcb */ - - rprev = rtcb->blink; - if (rprev == NULL) - { - /* Special case: Inserting ptcb at the head of the list */ - - ptcb->flink = rtcb; - ptcb->blink = NULL; - rtcb->blink = ptcb; - g_readytorun.head = (FAR dq_entry_t *)ptcb; - rtcb->task_state = TSTATE_TASK_READYTORUN; - ptcb->task_state = TSTATE_TASK_RUNNING; - ret = true; - } - else - { - /* Insert in the middle of the list */ - - ptcb->flink = rtcb; - ptcb->blink = rprev; - rprev->flink = ptcb; - rtcb->blink = ptcb; - ptcb->task_state = TSTATE_TASK_READYTORUN; - } - - /* Set up for the next time through */ - - rtcb = ptcb; + g_pendingtasks.head = NULL; + g_pendingtasks.tail = NULL; } - /* Mark the input list empty */ - - g_pendingtasks.head = NULL; - g_pendingtasks.tail = NULL; - return ret; } #endif /* !CONFIG_SMP */