diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-18 11:40:15 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-18 11:40:15 +0900 |
commit | d93206882d107baf0c27a13606feb6c980342155 (patch) | |
tree | bab5cc02255ef4a3cb16d2f8c3255eac55e90dba | |
parent | a17d12192fe74e07ab488e97d0742484f9a5ddcd (diff) |
Fix mutex_lock and join
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | chopstx.c | 115 |
2 files changed, 63 insertions, 55 deletions
@@ -1,5 +1,8 @@ 2016-05-18 NIIBE Yutaka <gniibe@fsij.org> + * chopstx.c (requeue): New. + (chopstx_mutex_lock, chopstx_join): Fix by requeue. + * example-cdc/usb-cdc.c: Prepare multiple TTYs. 2016-05-17 NIIBE Yutaka <gniibe@fsij.org> @@ -1184,6 +1184,44 @@ chopstx_mutex_init (chopstx_mutex_t *mutex) } +/* + * Re-queue TP after priority change. + * Returns a thread which can wake up this thread TP. + */ +static struct chx_thread * +requeue (struct chx_thread *tp) +{ + if (tp->state == THREAD_READY) + { + chx_spin_lock (&q_ready.lock); + ll_prio_enqueue (ll_dequeue ((struct chx_pq *)tp), tp->parent); + chx_spin_unlock (&q_ready.lock); + } + else if (tp->state == THREAD_WAIT_MTX) + { + struct chx_mtx *mutex = (struct chx_mtx *)tp->parent; + + chx_spin_lock (&mutex->lock); + ll_prio_enqueue (ll_dequeue ((struct chx_pq *)tp), tp->parent); + chx_spin_unlock (&mutex->lock); + return mutex->owner; + } + else if (tp->state == THREAD_WAIT_CND) + { + struct chx_cond *cond = (struct chx_cond *)tp->parent; + + chx_spin_lock (&cond->lock); + ll_prio_enqueue (ll_dequeue ((struct chx_pq *)tp), tp->parent); + chx_spin_unlock (&cond->lock); + /* We don't know who can wake up this thread. */ + } + else if (tp->state == THREAD_JOIN) + /* Requeue is not needed as waiting for the thread is only by one. */ + return (struct chx_thread *)tp->v; + + return NULL; +} + /** * chopstx_mutex_lock - Lock the mutex * @mutex: Mutex @@ -1198,7 +1236,7 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex) while (1) { chopstx_mutex_t *m = mutex; - struct chx_thread *owner; + struct chx_thread *tp0; chx_cpu_sched_lock (); chx_spin_lock (&m->lock); @@ -1213,59 +1251,23 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex) break; } - owner = m->owner; - while (1) - { /* Priority inheritance. */ - owner->prio = tp->prio; - if (owner->state == THREAD_READY) - { - chx_spin_lock (&q_ready.lock); - ll_prio_enqueue (ll_dequeue ((struct chx_pq *)owner), - owner->parent); - chx_spin_unlock (&q_ready.lock); - break; - } - if (owner->state == THREAD_WAIT_CND) - { - struct chx_cond *cond = (struct chx_cond *)owner->parent; - - chx_spin_lock (&cond->lock); - ll_prio_enqueue (ll_dequeue ((struct chx_pq *)owner), - owner->parent); - chx_spin_unlock (&cond->lock); - } - else if (owner->state == THREAD_WAIT_MTX) - { - struct chx_mtx *mutex = (struct chx_mtx *)owner->parent; - - chx_spin_lock (&mutex->lock); - ll_prio_enqueue (ll_dequeue ((struct chx_pq *)owner), - owner->parent); - chx_spin_unlock (&mutex->lock); - owner = m->owner; - continue; - } - else if (owner->state == THREAD_JOIN) - { - ((struct chx_stack_regs *)owner->tc.reg[REG_SP])->reg[REG_R0] = 1; - chx_spin_lock (&q_join.lock); - ll_dequeue ((struct chx_pq *)owner); - chx_spin_unlock (&q_join.lock); - chx_ready_enqueue (owner); - break; - } - else if (owner->state == THREAD_WAIT_TIME - || owner->state == THREAD_WAIT_POLL) + /* Priority inheritance. */ + tp0 = m->owner; + while (tp0 && tp0->prio < tp->prio) + { + tp0->prio = tp->prio; + if (tp0->state == THREAD_WAIT_TIME + || tp0->state == THREAD_WAIT_POLL) { - ((struct chx_stack_regs *)owner->tc.reg[REG_SP])->reg[REG_R0] = 1; - if (tp->parent == &q_timer.q) - chx_timer_dequeue (tp); + ((struct chx_stack_regs *)tp0->tc.reg[REG_SP])->reg[REG_R0] = 1; + if (tp0->parent == &q_timer.q) + chx_timer_dequeue (tp0); - chx_ready_enqueue (owner); - break; + chx_ready_enqueue (tp0); + tp0 = NULL; } else - break; + tp0 = requeue (tp0); } if (tp->flag_sched_rr) @@ -1588,6 +1590,8 @@ chopstx_join (chopstx_t thd, void **ret) if (tp->state != THREAD_EXITED) { + struct chx_thread *tp0 = tp; + if (running->flag_sched_rr) chx_timer_dequeue (running); chx_spin_lock (&q_join.lock); @@ -1595,12 +1599,13 @@ chopstx_join (chopstx_t thd, void **ret) running->v = (uint32_t)tp; running->state = THREAD_JOIN; tp->flag_join_req = 1; - if (tp->prio < running->prio) + + /* Priority inheritance. */ + tp0 = tp; + while (tp0 && tp0->prio < running->prio) { - tp->prio = running->prio; - if (tp->state == THREAD_READY - || tp->state == THREAD_WAIT_MTX || tp->state == THREAD_WAIT_CND) - ll_prio_enqueue (ll_dequeue ((struct chx_pq *)tp), tp->parent); + tp0->prio = running->prio; + tp0 = requeue (tp0); } chx_spin_unlock (&q_join.lock); r = chx_sched (CHX_SLEEP); |