From e42b3040ee14a8fa1be0b3cf56767c475f4f460f Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 24 Mar 2016 07:52:27 -0600 Subject: [PATCH] Fix some issues with the initial implementation of sched_mergeprioritized. --- sched/sched/sched.h | 5 +- sched/sched/sched_lock.c | 3 +- sched/sched/sched_mergepending.c | 6 ++- sched/sched/sched_mergeprioritized.c | 69 +++++++++++++++++++--------- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/sched/sched/sched.h b/sched/sched/sched.h index 9c793aee06..2b62e9f660 100644 --- a/sched/sched/sched.h +++ b/sched/sched/sched.h @@ -370,8 +370,9 @@ extern volatile cpu_set_t g_cpu_lockset; bool sched_addreadytorun(FAR struct tcb_s *rtrtcb); bool sched_removereadytorun(FAR struct tcb_s *rtrtcb); -bool sched_addprioritized(FAR struct tcb_s *newTcb, DSEG dq_queue_t *list); -void sched_mergeprioritized(FAR dq_queue_t *list1, FAR dq_queue_t *list2); +bool sched_addprioritized(FAR struct tcb_s *tcb, DSEG dq_queue_t *list); +void sched_mergeprioritized(FAR dq_queue_t *list1, FAR dq_queue_t *list2, + uint8_t task_state); bool sched_mergepending(void); void sched_addblocked(FAR struct tcb_s *btcb, tstate_t task_state); void sched_removeblocked(FAR struct tcb_s *btcb); diff --git a/sched/sched/sched_lock.c b/sched/sched/sched_lock.c index fb4675fa7b..36b53775d2 100644 --- a/sched/sched/sched_lock.c +++ b/sched/sched/sched_lock.c @@ -211,7 +211,8 @@ int sched_lock(void) */ sched_mergeprioritized((FAR dq_queue_t *)&g_readytorun, - (FAR dq_queue_t *)&g_pendingtasks); + (FAR dq_queue_t *)&g_pendingtasks, + TSTATE_TASK_PENDING); #endif } diff --git a/sched/sched/sched_mergepending.c b/sched/sched/sched_mergepending.c index 75b30d0642..07a554ff06 100644 --- a/sched/sched/sched_mergepending.c +++ b/sched/sched/sched_mergepending.c @@ -251,7 +251,8 @@ bool sched_mergepending(void) */ sched_mergeprioritized((FAR dq_queue_t *)&g_readytorun, - (FAR dq_queue_t *)&g_pendingtasks); + (FAR dq_queue_t *)&g_pendingtasks, + TSTATE_TASK_PENDING); /* And return with the schedule locked and tasks in the * pending task list. @@ -279,7 +280,8 @@ bool sched_mergepending(void) */ sched_mergeprioritized((FAR dq_queue_t *)&g_pendingtasks, - (FAR dq_queue_t *)&g_readytorun); + (FAR dq_queue_t *)&g_readytorun, + TSTATE_TASK_READYTORUN); } return ret; diff --git a/sched/sched/sched_mergeprioritized.c b/sched/sched/sched_mergeprioritized.c index 8af1c8e51e..90ef9dfbad 100644 --- a/sched/sched/sched_mergeprioritized.c +++ b/sched/sched/sched_mergeprioritized.c @@ -63,6 +63,7 @@ * will be empty upon return. * list2 - That list that will contained the prioritized content of * both lists upon return. + * task_state - The task state/list index associated with list2. * * Return Value: * None @@ -74,16 +75,26 @@ * ****************************************************************************/ -void sched_mergeprioritized(FAR dq_queue_t *list1, FAR dq_queue_t *list2) +void sched_mergeprioritized(FAR dq_queue_t *list1, FAR dq_queue_t *list2, + uint8_t task_state) { + FAR dq_queue_t clone; FAR struct tcb_s *tcb1; FAR struct tcb_s *tcb2; + FAR struct tcb_s *tmp; DEBUGASSERT(list1 != NULL && list2 != NULL); - /* Get the head of list1 and list2 */ + /* Get a private copy of list1, clearing list1. We do this early so that + * we can be assured that the list is stationary before we start any + * operations on it. + */ - tcb1 = (FAR struct tcb_s *)dq_peek(list1); + dq_move(list1, &clone); + + /* Get the TCB at the head of list1 */ + + tcb1 = (FAR struct tcb_s *)dq_peek(&clone); if (tcb1 == NULL) { /* Special case.. list1 is empty. There is nothing to be done. */ @@ -91,42 +102,64 @@ void sched_mergeprioritized(FAR dq_queue_t *list1, FAR dq_queue_t *list2) return; } + /* Now the TCBs are no longer accessible and we can change the state on + * each TCB. We go through extra precaution to assure that a TCB is never + * in a list with the wrong state. + */ + + for (tmp = tcb1; + tmp != NULL; + tmp = (FAR struct tcb_s *)dq_next((FAR dq_entry_t *)tmp)) + { + tmp->task_state = task_state; + } + + /* Get the head of list2 */ + tcb2 = (FAR struct tcb_s *)dq_peek(list2); if (tcb2 == NULL) { /* Special case.. list2 is empty. Move list1 to list2. */ - dq_move(list1, list2); + dq_move(&clone, list2); return; } - /* Now loop until all entries from list1 have been merged into list2 */ + /* Now loop until all entries from list1 have been merged into list2. tcb1 + * points at the TCB at the head of list1; tcb2 points to the TCB at the + * current working position in list2 + */ - while (tcb1 != NULL) + do { - /* Are we at the end of list2? */ + /* Are we at the end of list2 with TCBs remaining to be merged in + * list1? + */ if (tcb2 == NULL) { /* Yes.. Just append the remainder of list1 to the end of list2. */ - tcb1->blink = NULL; - list1->head = (FAR dq_entry_t *)tcb1; - dq_cat(list1, list2); + dq_cat(&clone, list2); break; } - /* Which has higher priority? */ + /* Which TCB has higher priority? */ else if (tcb1->sched_priority > tcb2->sched_priority) { /* The TCB from list1 has higher priority than the TCB from list2. - * Insert the TCB from list1 before the TCB from list2. + * Remove the TCB from list1 and insert it before the TCB from + * list2. */ - dq_addbefore((FAR dq_entry_t *)tcb2, (FAR dq_entry_t *)tcb2, + tmp = (FAR struct tcb_s *)dq_remfirst(&clone); + DEBUGASSERT(tmp == tcb1); + + dq_addbefore((FAR dq_entry_t *)tcb2, (FAR dq_entry_t *)tmp, list2); - tcb1 = (FAR struct tcb_s *)dq_next((FAR dq_entry_t *)tcb1); + + tcb1 = (FAR struct tcb_s *)dq_peek(&clone); } else { @@ -137,11 +170,5 @@ void sched_mergeprioritized(FAR dq_queue_t *list1, FAR dq_queue_t *list2) tcb2 = (FAR struct tcb_s *)dq_next((FAR dq_entry_t *)tcb2); } } - - /* All of the TCBs from list1 have been moved. Now we can now mark list1 - * empty. - */ - - dq_init(list1); + while (tcb1 != NULL); } -