summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNIIBE Yutaka <gniibe@fsij.org>2013-05-29 08:28:05 +0900
committerNIIBE Yutaka <gniibe@fsij.org>2013-05-29 08:28:05 +0900
commitb5cdd769ee79395690582d42cb5857df15b545c9 (patch)
tree092b5ea0387b9077cecde8ba840f81114d64ed65
parent5552a9590dc5e91878c882951d1188472f49b58a (diff)
Fix race of chopstx_cond_wait.
-rw-r--r--ChangeLog6
-rw-r--r--chopstx.c79
2 files changed, 56 insertions, 29 deletions
diff --git a/ChangeLog b/ChangeLog
index 77cea14..a830ea8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-05-29 Niibe Yutaka <gniibe@fsij.org>
+
+ * chopstx.c (chx_mutex_unlock, chopstx_exit): New.
+ (chopstx_mutex_unlock): Use chx_mutex_unlock.
+ (chopstx_cond_wait): Fix race condition.
+
2013-05-28 Niibe Yutaka <gniibe@fsij.org>
* chopstx.c (chopstx_intr_wait): Rename from chopstx_wait_intr.
diff --git a/chopstx.c b/chopstx.c
index a624012..8cd3473 100644
--- a/chopstx.c
+++ b/chopstx.c
@@ -700,6 +700,39 @@ chx_exit (void *retval)
/* never comes here. */
for (;;);
}
+
+
+static chopstx_prio_t
+chx_mutex_unlock (chopstx_mutex_t *mutex)
+{
+ struct chx_thread *tp;
+ chopstx_prio_t prio = 0;
+
+ mutex->owner = NULL;
+ running->mutex_list = mutex->list;
+ mutex->list = NULL;
+
+ tp = ll_pop (&mutex->q);
+ if (tp)
+ {
+ uint16_t newprio = running->prio_orig;
+ chopstx_mutex_t *m;
+
+ chx_ready_enqueue (tp);
+
+ /* Examine mutexes we hold, and determine new priority for running. */
+ for (m = running->mutex_list; m; m = m->list)
+ if (!ll_empty (&m->q) && m->q.next->prio > newprio)
+ newprio = m->q.next->prio;
+ /* Then, assign it. */
+ running->prio = newprio;
+
+ if (prio < tp->prio)
+ prio = tp->prio;
+ }
+
+ return prio;
+}
void
chopstx_attr_init (chopstx_attr_t *attr)
@@ -851,37 +884,15 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
void
chopstx_mutex_unlock (chopstx_mutex_t *mutex)
{
- struct chx_thread *tp;
- int yield = 0;
+ chopstx_prio_t prio;
asm volatile ("cpsid i" : : : "memory");
chx_LOCK (&mutex->lock);
- mutex->owner = NULL;
- running->mutex_list = mutex->list;
- mutex->list = NULL;
-
- tp = ll_pop (&mutex->q);
- if (tp)
- {
- uint16_t newprio = running->prio_orig;
- chopstx_mutex_t *m;
-
- chx_ready_enqueue (tp);
-
- /* Examine mutexes we hold, and determine new priority for running. */
- for (m = running->mutex_list; m; m = m->list)
- if (!ll_empty (&m->q) && m->q.next->prio > newprio)
- newprio = m->q.next->prio;
- /* Then, assign it. */
- running->prio = newprio;
-
- if (tp->prio > running->prio)
- yield = 1;
- }
-
+ prio = chx_mutex_unlock (mutex);
chx_UNLOCK (&mutex->lock);
asm volatile ("cpsie i" : : : "memory");
- if (yield)
+
+ if (prio > running->prio)
chx_yield ();
}
@@ -898,10 +909,15 @@ chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex)
{
struct chx_thread *tp = running;
+ asm volatile ("cpsid i" : : : "memory");
+
if (mutex)
- chopstx_mutex_unlock (mutex);
+ {
+ chx_LOCK (&mutex->lock);
+ chx_mutex_unlock (mutex);
+ chx_UNLOCK (&mutex->lock);
+ }
- asm volatile ("cpsid i" : : : "memory");
chx_LOCK (&cond->lock);
ll_prio_enqueue (tp, &cond->q);
tp->state = THREAD_WAIT_CND;
@@ -1048,7 +1064,12 @@ chopstx_exit (void *retval)
for (m = running->mutex_list; m; m = m_next)
{
m_next = m->list;
- chopstx_mutex_unlock (m);
+
+ asm volatile ("cpsid i" : : : "memory");
+ chx_LOCK (&m->lock);
+ chx_mutex_unlock (m);
+ chx_UNLOCK (&m->lock);
+ asm volatile ("cpsie i" : : : "memory");
}
chopstx_release_irq_thread (running);