aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2016-05-18 11:40:15 +0900
committerNIIBE Yutaka <gniibe@fsij.org>2016-05-18 11:40:15 +0900
commitd93206882d107baf0c27a13606feb6c980342155 (patch)
treebab5cc02255ef4a3cb16d2f8c3255eac55e90dba
parenta17d12192fe74e07ab488e97d0742484f9a5ddcd (diff)
Fix mutex_lock and join
-rw-r--r--ChangeLog3
-rw-r--r--chopstx.c115
2 files changed, 63 insertions, 55 deletions
diff --git a/ChangeLog b/ChangeLog
index 971fd4f..f7d11b6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
diff --git a/chopstx.c b/chopstx.c
index 0b75135..1d9a309 100644
--- a/chopstx.c
+++ b/chopstx.c
@@ -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);