From 6d568f91847ef8a35036cff25e1e8987c1b23763 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka <gniibe@fsij.org> Date: Mon, 27 May 2013 17:34:22 +0900 Subject: Bit fields, intr handling, etc. --- ChangeLog | 7 +++ chopstx.c | 136 ++++++++++++++++++++++++++++++++++----------------- chopstx.h | 5 +- example-cdc/sample.c | 3 +- 4 files changed, 103 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index 74bf763..6cf457b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,13 @@ 2013-05-27 Niibe Yutaka <gniibe@fsij.org> * chopstx.c (chx_fatal, chopstx_exit, chopstx_join): New. + (struct chx_thread): Independent member of state. Use bit fields. + (chx_timer_expired, chx_handle_intr): Check priority before + calling chx_request_preemption. + (chx_disable_intr): Clear pending interrupt too. + (chopstx_claim_irq): Rename from chopstx_intr_register. + (chopstx_release_irq): New. + (chopstx_join): Promote priority of thread to be joined. 2013-05-24 Niibe Yutaka <gniibe@fsij.org> diff --git a/chopstx.c b/chopstx.c index 41dd603..d4dd954 100644 --- a/chopstx.c +++ b/chopstx.c @@ -71,7 +71,7 @@ static struct chx_timer q_timer; static struct chx_timer q_exit; /* Queue of threads which wait exit of some thread. */ -static struct chx_timer q_waitexit; +static struct chx_timer q_join; /* Forward declaration(s). */ @@ -154,11 +154,16 @@ static uint32_t usec_to_ticks (uint32_t usec) struct chx_thread { struct chx_thread *next, *prev; struct tcontext tc; - uint16_t prio; - uint16_t prio_orig; + uint32_t state : 4; + uint32_t flag_detached : 1; + uint32_t flag_got_cancel : 1; + uint32_t : 2; + uint32_t prio : 8; + uint32_t prio_orig : 8; + uint32_t : 8; uint32_t v; struct chx_mtx *mutex_list; -} __attribute__((packed)); +}; /* @@ -235,16 +240,18 @@ ll_prio_enqueue (struct chx_thread *tp0, void *head) /* - * Thread status encoded in ->v. + * Thread status. */ -#define THREAD_WAIT_MTX 0x00000001 -#define THREAD_WAIT_CND 0x00000002 -#define THREAD_WAIT_OBJ 0x00000003 /* Timer (24-bit), thread */ +#define THREAD_RUNNING 0x00 +#define THREAD_READY 0x01 +#define THREAD_WAIT_MTX 0x02 +#define THREAD_WAIT_CND 0x03 +#define THREAD_WAIT_TIME 0x04 +#define THREAD_WAIT_INT 0x05 +#define THREAD_JOIN 0x06 +/**/ +#define THREAD_EXITED 0x0F -#define THREAD_RUNNING 0x00000000 -#define THREAD_WAIT_INT 0x00000004 -#define THREAD_EXITED 0x00000008 -#define THREAD_READY 0x0000000C static uint32_t chx_ready_pop (void) @@ -254,7 +261,7 @@ chx_ready_pop (void) chx_LOCK (&q_ready.lock); tp = ll_pop (&q_ready); if (tp) - tp->v = THREAD_RUNNING; + tp->state = THREAD_RUNNING; chx_UNLOCK (&q_ready.lock); return (uint32_t)tp; @@ -265,7 +272,7 @@ static void chx_ready_push (struct chx_thread *t) { chx_LOCK (&q_ready.lock); - t->v = THREAD_READY; + t->state = THREAD_READY; ll_prio_push (t, &q_ready); chx_UNLOCK (&q_ready.lock); } @@ -275,7 +282,7 @@ static void chx_ready_enqueue (struct chx_thread *t) { chx_LOCK (&q_ready.lock); - t->v = THREAD_READY; + t->state = THREAD_READY; ll_prio_enqueue (t, &q_ready); chx_UNLOCK (&q_ready.lock); } @@ -345,8 +352,9 @@ preempt (void) "msr MSP, r1\n\t" "b sched\n" "0:\n\t" - "ldr r2, [r0, 48]\n\t" /* Check ->v to avoid RACE. */ - "cbz r2, 1f\n\t" + "ldr r2, [r0, 44]\n\t" /* Check ->state to avoid RACE. */ + "tst r2, #0x0f\n\t" + "beq 1f\n\t" /* RUNNING is busy on transition, do nothing. */ "bx lr\n" "1:\n\t" @@ -421,7 +429,10 @@ chx_set_timer (struct chx_thread *q, uint32_t ticks) *SYST_RVR = 0; } else - q->v = (ticks<<8)|THREAD_WAIT_OBJ; + { + q->state = THREAD_WAIT_TIME; + q->v = ticks; + } } static void @@ -446,7 +457,7 @@ chx_timer_insert (struct chx_thread *tp, uint32_t usec) else { ticks -= next_ticks; - next_ticks = (q->v >> 8); + next_ticks = q->v; } } @@ -465,12 +476,13 @@ void chx_timer_expired (void) { struct chx_thread *t; + chopstx_prio_t prio = 0; asm volatile ("cpsid i" : : : "memory"); chx_LOCK (&q_timer.lock); if ((t = ll_pop (&q_timer))) { - uint32_t next_tick = t->v >> 8; + uint32_t next_tick = t->v; chx_ready_enqueue (t); @@ -482,10 +494,12 @@ chx_timer_expired (void) t != (struct chx_thread *)&q_timer && next_tick == 0; t = t_next) { - next_tick = (t->v >> 8); + next_tick = t->v; t_next = t->next; ll_dequeue (t); chx_ready_enqueue (t); + if (t->prio > prio) + prio = t->prio; } if (!ll_empty (&q_timer)) @@ -493,7 +507,8 @@ chx_timer_expired (void) } } - chx_request_preemption (); + if (running == NULL || running->prio < prio) + chx_request_preemption (); chx_UNLOCK (&q_timer.lock); asm volatile ("cpsie i" : : : "memory"); } @@ -509,6 +524,8 @@ static void chx_disable_intr (uint8_t irq_num) { NVIC_ICER (irq_num) = 1 << (irq_num & 0x1f); + /* Clear pending, too. */ + NVIC_ICPR (irq_num) = 1 << (irq_num & 0x1f); } #define INTR_PRIO (11<<4) @@ -538,11 +555,12 @@ chx_handle_intr (void) if (intr->irq_num == irq_num) break; - if (intr && intr->t && intr->t->v == THREAD_WAIT_INT) + if (intr && intr->t && intr->t->state == THREAD_WAIT_INT) { intr->ready++; chx_ready_enqueue (intr->t); - chx_request_preemption (); + if (running == NULL || running->prio < intr->t->prio) + chx_request_preemption (); } asm volatile ("cpsie i" : : : "memory"); } @@ -571,7 +589,8 @@ chx_init (struct chx_thread *tp) tp->prio_orig = tp->prio = PRIO_DEFAULT; tp->next = tp->prev = tp; tp->mutex_list = NULL; - tp->v = THREAD_RUNNING; + tp->state = THREAD_RUNNING; + tp->v = 0; running = tp; } @@ -649,7 +668,8 @@ chopstx_create (chopstx_t *thd, const chopstx_attr_t *attr, tp->tc.reg[REG_SP] = (uint32_t)stack; tp->next = tp->prev = tp; tp->mutex_list = NULL; - tp->v = THREAD_EXITED; + tp->state = THREAD_EXITED; + tp->v = 0; *thd = (uint32_t)tp; asm volatile ("cpsid i" : : : "memory"); @@ -709,22 +729,22 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex) while (1) { owner->prio = t->prio; - if (owner->v == THREAD_READY) + if (owner->state == THREAD_READY) { ll_prio_enqueue (ll_dequeue (owner), &q_ready); break; } - else if ((owner->v & 0x03) == THREAD_WAIT_MTX) + else if (owner->state == THREAD_WAIT_MTX) { - m = (chopstx_mutex_t *)(owner->v & ~0x03); + m = (chopstx_mutex_t *)owner->v; ll_prio_enqueue (ll_dequeue (owner), m); owner = m->owner; continue; } - else if ((owner->v & 0x03) == THREAD_WAIT_CND) + else if (owner->state == THREAD_WAIT_CND) { - chopstx_cond_t *cnd = (chopstx_cond_t *)(owner->v & ~0x03); + chopstx_cond_t *cnd = (chopstx_cond_t *)owner->v; ll_prio_enqueue (ll_dequeue (owner), cnd); break; @@ -735,7 +755,8 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex) } ll_prio_enqueue (t, &mutex->q); - t->v = (uint32_t)mutex | THREAD_WAIT_MTX; + t->state = THREAD_WAIT_MTX; + t->v = (uint32_t)mutex; chx_UNLOCK (&mutex->lock); asm volatile ("cpsie i" : : : "memory"); chx_sched (); @@ -797,7 +818,8 @@ chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex) asm volatile ("cpsid i" : : : "memory"); chx_LOCK (&cond->lock); ll_prio_enqueue (t, &cond->q); - t->v = (uint32_t)cond | THREAD_WAIT_CND; + t->state = THREAD_WAIT_CND; + t->v = (uint32_t)cond; chx_UNLOCK (&cond->lock); asm volatile ("cpsie i" : : : "memory"); @@ -851,7 +873,7 @@ chopstx_cond_broadcast (chopstx_cond_t *cond) void -chopstx_intr_register (chopstx_intr_t *intr, uint8_t irq_num) +chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num) { intr->irq_num = irq_num; intr->t = running; @@ -865,6 +887,26 @@ chopstx_intr_register (chopstx_intr_t *intr, uint8_t irq_num) } +void +chopstx_release_irq (chopstx_intr_t *intr0) +{ + chopstx_intr_t *intr, *intr_prev; + + asm volatile ("cpsid i" : : : "memory"); + chx_disable_intr (intr0->irq_num); + intr_prev = intr_top; + for (intr = intr_top; intr; intr = intr->next) + if (intr == intr0) + break; + + if (intr == intr_top) + intr_top = intr_top->next; + else + intr_prev->next = intr->next; + asm volatile ("cpsie i" : : : "memory"); +} + + void chopstx_wait_intr (chopstx_intr_t *intr) { @@ -873,7 +915,8 @@ chopstx_wait_intr (chopstx_intr_t *intr) while (intr->ready == 0) { intr->t = running; - running->v = THREAD_WAIT_INT; + running->state = THREAD_WAIT_INT; + running->v = 0; asm volatile ("cpsie i" : : : "memory"); chx_sched (); asm volatile ("cpsid i" : : : "memory"); @@ -892,19 +935,19 @@ chopstx_exit (void *retval) asm volatile ("cpsid i" : : : "memory"); /* wake up a thread waiting to join */ - chx_LOCK (&q_waitexit.lock); - for (q = q_waitexit.next; q != (struct chx_thread *)&q_waitexit; q = q->next) - if ((q->v & ~3) == (uint32_t)running) + chx_LOCK (&q_join.lock); + for (q = q_join.next; q != (struct chx_thread *)&q_join; q = q->next) + if (q->v == (uint32_t)running) { /* should be one at most. */ ll_dequeue (q); chx_ready_enqueue (q); break; } - chx_UNLOCK (&q_waitexit.lock); + chx_UNLOCK (&q_join.lock); chx_LOCK (&q_exit.lock); ll_insert (running, &q_exit); - running->v = THREAD_EXITED; + running->state = THREAD_EXITED; chx_UNLOCK (&q_exit.lock); asm volatile ("cpsie i" : : "r" (r4) : "memory"); chx_sched (); @@ -921,12 +964,15 @@ chopstx_join (chopstx_t thd, void **ret) /* XXX: dead lock detection (waiting each other) and return error. */ asm volatile ("cpsid i" : : : "memory"); - if (tp->v != THREAD_EXITED) + if (tp->state != THREAD_EXITED) { - chx_LOCK (&q_waitexit.lock); - ll_insert (running, &q_waitexit); - running->v = ((uint32_t) tp) | THREAD_WAIT_OBJ; - chx_UNLOCK (&q_waitexit.lock); + chx_LOCK (&q_join.lock); + ll_insert (running, &q_join); + running->v = (uint32_t)tp; + running->state = THREAD_JOIN; + chx_UNLOCK (&q_join.lock); + if (tp->prio < running->prio) + tp->prio = running->prio; asm volatile ("cpsie i" : : : "memory"); chx_sched (); } diff --git a/chopstx.h b/chopstx.h index 52e457d..8d65e34 100644 --- a/chopstx.h +++ b/chopstx.h @@ -47,7 +47,7 @@ struct chx_spinlock { /* nothing for uniprocessor. */ }; -typedef uint16_t chopstx_prio_t; +typedef uint8_t chopstx_prio_t; typedef struct chx_mtx { struct { struct chx_thread *next, *prev; @@ -86,7 +86,8 @@ typedef struct chx_intr { uint8_t ready; } chopstx_intr_t; -void chopstx_intr_register (chopstx_intr_t *intr, uint8_t irq_num); +void chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num); +void chopstx_release_irq (chopstx_intr_t *intr); void chopstx_wait_intr (chopstx_intr_t *intr); diff --git a/example-cdc/sample.c b/example-cdc/sample.c index 0c0481d..80b5ef5 100644 --- a/example-cdc/sample.c +++ b/example-cdc/sample.c @@ -69,7 +69,7 @@ usb_intr (void *arg) asm volatile ("cpsid i" : : : "memory"); /* Disable because of usb_lld_init assumes interrupt handler. */ usb_lld_init (0x80); /* Bus powered. */ - chopstx_intr_register (&interrupt, INTR_REQ_USB); + chopstx_claim_irq (&interrupt, INTR_REQ_USB); /* Enable */ asm volatile ("cpsie i" : : : "memory"); @@ -81,6 +81,7 @@ usb_intr (void *arg) usb_interrupt_handler (); } + chopstx_release_irq (&interrupt); return NULL; } -- cgit v1.2.3