Bit fields, intr handling, etc.

This commit is contained in:
NIIBE Yutaka
2013-05-27 17:34:22 +09:00
parent b0cfda694f
commit 6d568f9184
4 changed files with 103 additions and 48 deletions

View File

@@ -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>

136
chopstx.c
View File

@@ -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 ();
}

View File

@@ -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);

View File

@@ -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;
}