diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-13 14:22:12 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-13 14:22:12 +0900 |
commit | daa7aebd6f774de5079b0d3c211293db597084fc (patch) | |
tree | cc1cf2b339d128200ec7770af82f1357061acc5e | |
parent | 5fc2617ae5d16b7f6f4fb00a617d14888d6c74cc (diff) |
Add READY field for chx_poll_XXX so that we can check if it's ready
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | chopstx.c | 151 | ||||
-rw-r--r-- | chopstx.h | 25 | ||||
-rw-r--r-- | example-cdc/sample.c | 11 | ||||
-rw-r--r-- | example-fs-bb48/sample.c | 11 |
5 files changed, 132 insertions, 83 deletions
@@ -1,3 +1,20 @@ +2016-05-13 NIIBE Yutaka <gniibe@fsij.org> + + * chopstx.c (chx_sched) [__ARM_ARCH_6M__]: Fix asm. + + * example-cdc/sample.c (main): Update chopstx_poll example. + * example-fs-bb48/sample.c (main): Ditto. + + * chopstx.c (struct chx_px): Add READY_P and LOCK. + (chx_proxy_init): Add initialization of new members. + (chx_wakeup): Spinlock PX. + (chopstx_mutex_lock): Add protection by splinlock. + (chx_cond_hook, chx_join_hook): Change arguments. + (chx_cond_unhook, chx_join_unhook): Remove. + (chopstx_claim_irq): Compatible to chx_poll. + (chopstx_join): Fix spinlocking. + (chopstx_cancel): Fix spinlocking. + 2016-05-12 NIIBE Yutaka <gniibe@fsij.org> * example-cdc/sample.c: Update using chopstx_poll. @@ -315,6 +315,8 @@ struct chx_px { /* inherits PQ */ uint32_t v; struct chx_thread *master; uint32_t *counter_p; + uint16_t *ready_p; + struct chx_spinlock lock; /* spinlock to update the COUNTER */ }; struct chx_thread { /* inherits PQ */ @@ -791,7 +793,7 @@ chx_sched (uint32_t yield) "mov r2, r1\n\t" "mov r3, r1\n\t" "push {r1, r2, r3}\n\t" - "push {%1, r1}" + "push {%0, r1}" : /* no output*/ : "r" (yield) : "r1", "r2", "r3", "memory"); @@ -876,7 +878,7 @@ chx_sched (uint32_t yield) 24: pc 28: psr 32: possibly exists for alignment - [28 or 32] <-- pc + [28 or 32] <-- pc */ "ldr r0, [sp, #28]\n\t" "lsl r1, r0, #23\n\t" @@ -930,19 +932,23 @@ chx_wakeup (struct chx_thread *tp) { struct chx_px *px = (struct chx_px *)tp; + chx_spin_lock (&px->lock); (*px->counter_p)++; + *px->ready_p = 1; tp = px->master; if (tp->state == THREAD_WAIT_POLL) { chx_timer_dequeue (tp); ((struct chx_stack_regs *)tp->tc.reg[REG_SP])->reg[REG_R0] = -1; - goto wakeup; + chx_ready_enqueue (tp); + if (tp->prio > running->prio) + yield = 1; } + chx_spin_unlock (&px->lock); } else { ((struct chx_stack_regs *)tp->tc.reg[REG_SP])->reg[REG_R0] = 0; - wakeup: chx_ready_enqueue (tp); if (tp->prio > running->prio) yield = 1; @@ -1213,16 +1219,31 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex) while (1) { /* Priority inheritance. */ owner->prio = tp->prio; - if (owner->state == THREAD_READY || owner->state == THREAD_WAIT_CND) + 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; } @@ -1370,41 +1391,35 @@ chopstx_cond_broadcast (chopstx_cond_t *cond) static void -chx_cond_hook (struct chx_px *px, chopstx_cond_t *cond, - chopstx_mutex_t *mutex, int (*check) (void *), void *arg) +chx_cond_hook (struct chx_px *px, struct chx_poll_head *pd) { + struct chx_poll_cond *pc = (struct chx_poll_cond *)pd; + chopstx_testcancel (); - if (mutex) - chopstx_mutex_lock (mutex); + if (pc->mutex) + chopstx_mutex_lock (pc->mutex); - if ((*check) (arg) != 0) - (*px->counter_p)++; + if ((*pc->check) (pc->arg) != 0) + { + chx_spin_lock (&px->lock); + (*px->counter_p)++; + *px->ready_p = 1; + chx_spin_unlock (&px->lock); + } else { /* Condition doesn't met. * Register the proxy to wait for the condition. */ chx_cpu_sched_lock (); - chx_spin_lock (&cond->lock); - ll_prio_enqueue ((struct chx_pq *)px, &cond->q); - chx_spin_unlock (&cond->lock); + chx_spin_lock (&pc->cond->lock); + ll_prio_enqueue ((struct chx_pq *)px, &pc->cond->q); + chx_spin_unlock (&pc->cond->lock); chx_cpu_sched_unlock (); } - if (mutex) - chopstx_mutex_unlock (mutex); -} - -static void -chx_cond_unhook (struct chx_px *px, chopstx_cond_t *cond) -{ - chx_cpu_sched_lock (); - if (px->parent == &cond->q) - { - ll_dequeue ((struct chx_pq *)px); - px->parent = NULL; - } - chx_cpu_sched_unlock (); + if (pc->mutex) + chopstx_mutex_unlock (pc->mutex); } @@ -1418,6 +1433,7 @@ chx_cond_unhook (struct chx_px *px, chopstx_cond_t *cond) void chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num) { + intr->type = CHOPSTX_POLL_INTR; intr->irq_num = irq_num; intr->tp = running; intr->ready = 0; @@ -1620,7 +1636,6 @@ chopstx_join (chopstx_t thd, void **ret) ll_prio_enqueue ((struct chx_pq *)running, &q_join.q); running->v = (uint32_t)tp; running->state = THREAD_JOIN; - chx_spin_unlock (&q_join.lock); tp->flag_join_req = 1; if (tp->prio < running->prio) { @@ -1629,6 +1644,7 @@ chopstx_join (chopstx_t thd, void **ret) || tp->state == THREAD_WAIT_MTX || tp->state == THREAD_WAIT_CND) ll_prio_enqueue (ll_dequeue ((struct chx_pq *)tp), tp->parent); } + chx_spin_unlock (&q_join.lock); chx_sched (CHX_SLEEP); } else @@ -1641,9 +1657,10 @@ chopstx_join (chopstx_t thd, void **ret) static void -chx_join_hook (struct chx_px *px, chopstx_t thd) +chx_join_hook (struct chx_px *px, struct chx_poll_head *pd) { - struct chx_thread *tp = (struct chx_thread *)thd; + struct chx_poll_join *pj = (struct chx_poll_join *)pd; + struct chx_thread *tp = (struct chx_thread *)pj->thd; chopstx_testcancel (); chx_cpu_sched_lock (); @@ -1655,12 +1672,16 @@ chx_join_hook (struct chx_px *px, chopstx_t thd) } if (tp->state == THREAD_EXITED) - (*px->counter_p)++; + { + chx_spin_lock (&px->lock); + (*px->counter_p)++; + *px->ready_p = 1; + chx_spin_unlock (&px->lock); + } else { /* Not yet exited. * Register the proxy to wait for TP's exit. */ - chx_cpu_sched_lock (); px->v = (uint32_t)tp; chx_spin_lock (&q_join.lock); ll_prio_enqueue ((struct chx_pq *)px, &q_join.q); @@ -1670,18 +1691,6 @@ chx_join_hook (struct chx_px *px, chopstx_t thd) chx_cpu_sched_unlock (); } -static void -chx_join_unhook (struct chx_px *px) -{ - chx_cpu_sched_lock (); - if (px->parent == &q_join.q) - { - ll_dequeue ((struct chx_pq *)px); - px->parent = NULL; - } - chx_cpu_sched_unlock (); -} - /** * chopstx_wakeup_usec_wait - wakeup the sleeping thread for timer @@ -1745,7 +1754,13 @@ chopstx_cancel (chopstx_t thd) p->reg[REG_PC] = (uint32_t)chopstx_exit; if (tp->state == THREAD_WAIT_CND) - ll_dequeue ((struct chx_pq *)tp); + { + struct chx_cond *cond = (struct chx_cond *)tp->parent; + + chx_spin_lock (&cond->lock); + ll_dequeue ((struct chx_pq *)tp); + chx_spin_unlock (&cond->lock); + } else if (tp->state == THREAD_WAIT_TIME || tp->state == THREAD_WAIT_POLL) chx_timer_dequeue (tp); @@ -1778,7 +1793,7 @@ chopstx_testcancel (void) /** * chopstx_setcancelstate - set cancelability state * @cancel_disable: 0 to enable cancelation, otherwise disabled. - * + * * Calling chopstx_setcancelstate sets cancelability state. * * Returns old state which is 0 when it was enabled. @@ -1803,6 +1818,8 @@ chx_proxy_init (struct chx_px *px, uint32_t *cp) px->v = 0; px->master = running; px->counter_p = cp; + px->ready_p = NULL; + chx_spin_init (&px->lock); } @@ -1810,7 +1827,8 @@ chx_proxy_init (struct chx_px *px, uint32_t *cp) * chopstx_poll - wait for condition variable or thread's exit * @usec_p: Pointer to usec * @n: Number of poll descriptors - * @VARARGS: Pointers to an object of struct chx_poll_desc + * @VARARGS: Pointers to an object which should be one of: + * struct chx_poll_cond, chx_poll_join, or chx_intr. * * Returns number of active descriptors. */ @@ -1821,7 +1839,7 @@ chopstx_poll (uint32_t *usec_p, int n, ...) int i; va_list ap; struct chx_px px[n]; - struct chx_poll_desc *pd; + struct chx_poll_head *pd; chopstx_testcancel (); @@ -1831,29 +1849,36 @@ chopstx_poll (uint32_t *usec_p, int n, ...) va_start (ap, n); for (i = 0; i < n; i++) { - pd = va_arg (ap, struct chx_poll_desc *); - if (pd->type == CHOPSTX_POLL_COND) - chx_cond_hook (&px[i], pd->c.cond, pd->c.mutex, pd->c.check, pd->c.arg); + pd = va_arg (ap, struct chx_poll_head *); + if (pd->type == CHOPSTX_POLL_COND) + chx_cond_hook (&px[i], pd); else - chx_join_hook (&px[i], pd->j.thd); + chx_join_hook (&px[i], pd); + px[i].ready_p = &pd->ready; } va_end (ap); chx_cpu_sched_lock (); + chx_spin_lock (&px->lock); if (counter) - chx_cpu_sched_unlock (); + { + chx_spin_unlock (&px->lock); + chx_cpu_sched_unlock (); + } else if (*usec_p == 0) { if (running->flag_sched_rr) chx_timer_dequeue (running); running->state = THREAD_WAIT_POLL; + chx_spin_unlock (&px->lock); chx_sched (CHX_SLEEP); } else { int r; + chx_spin_unlock (&px->lock); chx_cpu_sched_unlock (); do { @@ -1864,23 +1889,21 @@ chopstx_poll (uint32_t *usec_p, int n, ...) while (r == 0); } - va_start (ap, n); for (i = 0; i < n; i++) { - pd = va_arg (ap, struct chx_poll_desc *); - if (pd->type == CHOPSTX_POLL_COND) - chx_cond_unhook (&px[i], pd->c.cond); - else - chx_join_unhook (&px[i]); + chx_cpu_sched_lock (); + chx_spin_lock (&px[i].lock); + ll_dequeue ((struct chx_pq *)&px[i]); + chx_spin_unlock (&px[i].lock); + chx_cpu_sched_unlock (); } - va_end (ap); - return counter; /* Bitmap??? */ + return counter; } /* * Lower layer architecture specific exception handling entries. - * + * */ void __attribute__ ((naked)) @@ -1923,7 +1946,7 @@ preempt (void) * Memory clobber constraint here is not accurate, but this * works. R7 keeps its value, but having "r7" here prevents * use of R7 before this asm statement. - */ + */ : "r2", "r3", "r4", "r5", "r6", "r7", "memory"); if (tp) @@ -82,12 +82,15 @@ void chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex); void chopstx_cond_signal (chopstx_cond_t *cond); void chopstx_cond_broadcast (chopstx_cond_t *cond); -typedef struct chx_intr { +struct chx_intr { + uint16_t type; + uint16_t ready; + /**/ struct chx_intr *next; struct chx_thread *tp; - uint32_t ready; uint8_t irq_num; -} chopstx_intr_t; +}; +typedef struct chx_intr chopstx_intr_t; void chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num); void chopstx_release_irq (chopstx_intr_t *intr); @@ -138,9 +141,13 @@ void chopstx_wakeup_usec_wait (chopstx_t thd); enum { CHOPSTX_POLL_COND = 0, CHOPSTX_POLL_JOIN, + CHOPSTX_POLL_INTR, }; struct chx_poll_cond { + uint16_t type; + uint16_t ready; + /**/ chopstx_cond_t *cond; chopstx_mutex_t *mutex; int (*check) (void *); @@ -148,15 +155,15 @@ struct chx_poll_cond { }; struct chx_poll_join { + uint16_t type; + uint16_t ready; + /**/ chopstx_t thd; }; -struct chx_poll_desc { - int type; - union { - struct chx_poll_cond c; - struct chx_poll_join j; - }; +struct chx_poll_head { + uint16_t type; + uint16_t ready; }; int chopstx_poll (uint32_t *usec_p, int n, ...); diff --git a/example-cdc/sample.c b/example-cdc/sample.c index 17b7cd5..d2951fc 100644 --- a/example-cdc/sample.c +++ b/example-cdc/sample.c @@ -201,13 +201,14 @@ main (int argc, const char *argv[]) { int size; uint32_t usec; - struct chx_poll_desc poll_desc; + struct chx_poll_cond poll_desc; poll_desc.type = CHOPSTX_POLL_COND; - poll_desc.c.cond = &st->cnd; - poll_desc.c.mutex = &st->mtx; - poll_desc.c.check = check_recv; - poll_desc.c.arg = st; + poll_desc.ready = 0; + poll_desc.cond = &st->cnd; + poll_desc.mutex = &st->mtx; + poll_desc.check = check_recv; + poll_desc.arg = st; /* With chopstx_poll, we can do timed cond_wait */ usec = 3000000; /* 3.0 seconds */ diff --git a/example-fs-bb48/sample.c b/example-fs-bb48/sample.c index b224003..39864d4 100644 --- a/example-fs-bb48/sample.c +++ b/example-fs-bb48/sample.c @@ -232,13 +232,14 @@ main (int argc, const char *argv[]) { int size; uint32_t usec; - struct chx_poll_desc poll_desc; + struct chx_poll_cond poll_desc; poll_desc.type = CHOPSTX_POLL_COND; - poll_desc.c.cond = &st->cnd; - poll_desc.c.mutex = &st->mtx; - poll_desc.c.check = check_recv; - poll_desc.c.arg = st; + poll_desc.ready = 0; + poll_desc.cond = &st->cnd; + poll_desc.mutex = &st->mtx; + poll_desc.check = check_recv; + poll_desc.arg = st; /* With chopstx_poll, we can do timed cond_wait */ usec = 3000000; |