diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2013-05-29 08:28:05 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2013-05-29 08:28:05 +0900 |
commit | b5cdd769ee79395690582d42cb5857df15b545c9 (patch) | |
tree | 092b5ea0387b9077cecde8ba840f81114d64ed65 | |
parent | 5552a9590dc5e91878c882951d1188472f49b58a (diff) |
Fix race of chopstx_cond_wait.
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | chopstx.c | 79 |
2 files changed, 56 insertions, 29 deletions
@@ -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. @@ -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); |