Implement cancellation. Rename, etc.
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
2013-05-28 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chopstx_intr_wait): Rename from chopstx_wait_intr.
|
||||
(chopstx_usec_wait): Rename from chosptx_usleep.
|
||||
(chopstx_cancel, chopstx_testcancel): New.
|
||||
|
||||
2013-05-27 Niibe Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chx_fatal, chopstx_exit, chopstx_join): New.
|
||||
|
||||
317
chopstx.c
317
chopstx.c
@@ -31,7 +31,7 @@
|
||||
#include <string.h>
|
||||
#include <chopstx.h>
|
||||
|
||||
void __attribute__((weak))
|
||||
void __attribute__((weak, noreturn))
|
||||
chx_fatal (uint32_t err_code)
|
||||
{
|
||||
(void)err_code;
|
||||
@@ -157,10 +157,11 @@ struct chx_thread {
|
||||
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 flag_join_req : 1;
|
||||
uint32_t flag_sched_rr : 1;
|
||||
uint32_t : 8;
|
||||
uint32_t prio_orig : 8;
|
||||
uint32_t prio : 8;
|
||||
uint32_t v;
|
||||
struct chx_mtx *mutex_list;
|
||||
};
|
||||
@@ -250,7 +251,8 @@ ll_prio_enqueue (struct chx_thread *tp0, void *head)
|
||||
#define THREAD_WAIT_INT 0x05
|
||||
#define THREAD_JOIN 0x06
|
||||
/**/
|
||||
#define THREAD_EXITED 0x0F
|
||||
#define THREAD_EXITED 0x0E
|
||||
#define THREAD_FINISHED 0x0F
|
||||
|
||||
|
||||
static uint32_t
|
||||
@@ -269,21 +271,21 @@ chx_ready_pop (void)
|
||||
|
||||
|
||||
static void
|
||||
chx_ready_push (struct chx_thread *t)
|
||||
chx_ready_push (struct chx_thread *tp)
|
||||
{
|
||||
chx_LOCK (&q_ready.lock);
|
||||
t->state = THREAD_READY;
|
||||
ll_prio_push (t, &q_ready);
|
||||
tp->state = THREAD_READY;
|
||||
ll_prio_push (tp, &q_ready);
|
||||
chx_UNLOCK (&q_ready.lock);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
chx_ready_enqueue (struct chx_thread *t)
|
||||
chx_ready_enqueue (struct chx_thread *tp)
|
||||
{
|
||||
chx_LOCK (&q_ready.lock);
|
||||
t->state = THREAD_READY;
|
||||
ll_prio_enqueue (t, &q_ready);
|
||||
tp->state = THREAD_READY;
|
||||
ll_prio_enqueue (tp, &q_ready);
|
||||
chx_UNLOCK (&q_ready.lock);
|
||||
}
|
||||
|
||||
@@ -472,34 +474,62 @@ chx_timer_insert (struct chx_thread *tp, uint32_t usec)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
chx_timer_dequeue (struct chx_thread *tp)
|
||||
{
|
||||
struct chx_thread *tp_prev;
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
chx_LOCK (&q_timer.lock);
|
||||
tp_prev = tp->prev;
|
||||
if (tp_prev == (struct chx_thread *)&q_timer)
|
||||
{
|
||||
if (tp->next == (struct chx_thread *)&q_timer)
|
||||
chx_set_timer (tp_prev, 0); /* Cancel timer*/
|
||||
else
|
||||
{ /* Update timer. */
|
||||
uint32_t next_ticks = *SYST_CVR + tp->v;
|
||||
|
||||
chx_set_timer (tp_prev, next_ticks);
|
||||
}
|
||||
}
|
||||
else
|
||||
tp_prev->v += tp->v;
|
||||
ll_dequeue (tp);
|
||||
tp->v = 0;
|
||||
chx_UNLOCK (&q_timer.lock);
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chx_timer_expired (void)
|
||||
{
|
||||
struct chx_thread *t;
|
||||
struct chx_thread *tp;
|
||||
chopstx_prio_t prio = 0;
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
chx_LOCK (&q_timer.lock);
|
||||
if ((t = ll_pop (&q_timer)))
|
||||
if ((tp = ll_pop (&q_timer)))
|
||||
{
|
||||
uint32_t next_tick = t->v;
|
||||
uint32_t next_tick = tp->v;
|
||||
|
||||
chx_ready_enqueue (t);
|
||||
chx_ready_enqueue (tp);
|
||||
|
||||
if (!ll_empty (&q_timer))
|
||||
{
|
||||
struct chx_thread *t_next;
|
||||
struct chx_thread *tp_next;
|
||||
|
||||
for (t = q_timer.next;
|
||||
t != (struct chx_thread *)&q_timer && next_tick == 0;
|
||||
t = t_next)
|
||||
for (tp = q_timer.next;
|
||||
tp != (struct chx_thread *)&q_timer && next_tick == 0;
|
||||
tp = tp_next)
|
||||
{
|
||||
next_tick = t->v;
|
||||
t_next = t->next;
|
||||
ll_dequeue (t);
|
||||
chx_ready_enqueue (t);
|
||||
if (t->prio > prio)
|
||||
prio = t->prio;
|
||||
next_tick = tp->v;
|
||||
tp_next = tp->next;
|
||||
ll_dequeue (tp);
|
||||
chx_ready_enqueue (tp);
|
||||
if (tp->prio > prio)
|
||||
prio = tp->prio;
|
||||
}
|
||||
|
||||
if (!ll_empty (&q_timer))
|
||||
@@ -555,11 +585,11 @@ chx_handle_intr (void)
|
||||
if (intr->irq_num == irq_num)
|
||||
break;
|
||||
|
||||
if (intr && intr->t && intr->t->state == THREAD_WAIT_INT)
|
||||
if (intr && intr->tp && intr->tp->state == THREAD_WAIT_INT)
|
||||
{
|
||||
intr->ready++;
|
||||
chx_ready_enqueue (intr->t);
|
||||
if (running == NULL || running->prio < intr->t->prio)
|
||||
chx_ready_enqueue (intr->tp);
|
||||
if (running == NULL || running->prio < intr->tp->prio)
|
||||
chx_request_preemption ();
|
||||
}
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
@@ -586,10 +616,12 @@ chx_init (struct chx_thread *tp)
|
||||
memset (&tp->tc, 0, sizeof (tp->tc));
|
||||
q_ready.next = q_ready.prev = (struct chx_thread *)&q_ready;
|
||||
q_timer.next = q_timer.prev = (struct chx_thread *)&q_timer;
|
||||
tp->prio_orig = tp->prio = PRIO_DEFAULT;
|
||||
tp->next = tp->prev = tp;
|
||||
tp->mutex_list = NULL;
|
||||
tp->state = THREAD_RUNNING;
|
||||
tp->flag_detached = tp->flag_got_cancel
|
||||
= tp->flag_join_req = tp->flag_sched_rr = 0;
|
||||
tp->prio_orig = tp->prio = PRIO_DEFAULT;
|
||||
tp->v = 0;
|
||||
|
||||
running = tp;
|
||||
@@ -620,6 +652,42 @@ chx_yield (void)
|
||||
|
||||
asm volatile ("svc #0" : : "r" (r0) : "memory");
|
||||
}
|
||||
|
||||
/* The RETVAL is saved into register R4. */
|
||||
static void __attribute__((noreturn))
|
||||
chx_exit (void *retval)
|
||||
{
|
||||
register uint32_t r4 __asm__ ("r4") = (uint32_t)retval;
|
||||
struct chx_thread *q;
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
if (!running->flag_join_req)
|
||||
{ /* wake up a thread which requests to join */
|
||||
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_join.lock);
|
||||
}
|
||||
|
||||
chx_LOCK (&q_exit.lock);
|
||||
if (!running->flag_detached)
|
||||
{
|
||||
ll_insert (running, &q_exit);
|
||||
running->state = THREAD_EXITED;
|
||||
}
|
||||
else
|
||||
running->state = THREAD_FINISHED;
|
||||
chx_UNLOCK (&q_exit.lock);
|
||||
asm volatile ("cpsie i" : : "r" (r4) : "memory");
|
||||
chx_sched ();
|
||||
/* never comes here. */
|
||||
for (;;);
|
||||
}
|
||||
|
||||
void
|
||||
chopstx_attr_init (chopstx_attr_t *attr)
|
||||
@@ -642,6 +710,7 @@ chopstx_attr_setstack (chopstx_attr_t *attr, uint32_t addr, size_t size)
|
||||
attr->size = size;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chopstx_create (chopstx_t *thd, const chopstx_attr_t *attr,
|
||||
void *(thread_entry) (void *), void *arg)
|
||||
@@ -658,17 +727,19 @@ chopstx_create (chopstx_t *thd, const chopstx_attr_t *attr,
|
||||
memset (stack, 0, sizeof (struct chx_stack_regs));
|
||||
p = (struct chx_stack_regs *)stack;
|
||||
p->reg[REG_R0] = (uint32_t)arg;
|
||||
p->reg[REG_LR] = 0; /* XXX: address of exit??? */
|
||||
p->reg[REG_LR] = (uint32_t)chopstx_exit;
|
||||
p->reg[REG_PC] = (uint32_t)thread_entry;
|
||||
p->reg[REG_XPSR] = INITIAL_XPSR;
|
||||
|
||||
tp = (struct chx_thread *)(stack + sizeof (struct chx_stack_regs));
|
||||
memset (&tp->tc, 0, sizeof (tp->tc));
|
||||
tp->prio_orig = tp->prio = attr->prio;
|
||||
tp->tc.reg[REG_SP] = (uint32_t)stack;
|
||||
tp->next = tp->prev = tp;
|
||||
tp->mutex_list = NULL;
|
||||
tp->state = THREAD_EXITED;
|
||||
tp->flag_detached = tp->flag_got_cancel
|
||||
= tp->flag_join_req = tp->flag_sched_rr = 0;
|
||||
tp->prio_orig = tp->prio = attr->prio;
|
||||
tp->v = 0;
|
||||
*thd = (uint32_t)tp;
|
||||
|
||||
@@ -681,7 +752,7 @@ chopstx_create (chopstx_t *thd, const chopstx_attr_t *attr,
|
||||
|
||||
|
||||
void
|
||||
chopstx_usleep (uint32_t usec)
|
||||
chopstx_usec_wait (uint32_t usec)
|
||||
{
|
||||
while (usec)
|
||||
{
|
||||
@@ -702,12 +773,13 @@ chopstx_mutex_init (chopstx_mutex_t *mutex)
|
||||
mutex->list = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
struct chx_thread *t = running;
|
||||
struct chx_thread *tp = running;
|
||||
chopstx_mutex_t *m;
|
||||
struct chx_thread *owner;
|
||||
|
||||
@@ -716,9 +788,9 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
if (mutex->owner == NULL)
|
||||
{
|
||||
/* The mutex is acquired. */
|
||||
mutex->owner = t;
|
||||
mutex->list = t->mutex_list;
|
||||
t->mutex_list = mutex;
|
||||
mutex->owner = tp;
|
||||
mutex->list = tp->mutex_list;
|
||||
tp->mutex_list = mutex;
|
||||
chx_UNLOCK (&mutex->lock);
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
return;
|
||||
@@ -728,7 +800,7 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
owner = m->owner;
|
||||
while (1)
|
||||
{
|
||||
owner->prio = t->prio;
|
||||
owner->prio = tp->prio;
|
||||
if (owner->state == THREAD_READY)
|
||||
{
|
||||
ll_prio_enqueue (ll_dequeue (owner), &q_ready);
|
||||
@@ -751,22 +823,23 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex)
|
||||
}
|
||||
else
|
||||
break;
|
||||
/* XXX: RUNNING and SMP??? */
|
||||
/* Assume it's UP no case of: ->state==RUNNING on SMP??? */
|
||||
}
|
||||
|
||||
ll_prio_enqueue (t, &mutex->q);
|
||||
t->state = THREAD_WAIT_MTX;
|
||||
t->v = (uint32_t)mutex;
|
||||
ll_prio_enqueue (tp, &mutex->q);
|
||||
tp->state = THREAD_WAIT_MTX;
|
||||
tp->v = (uint32_t)mutex;
|
||||
chx_UNLOCK (&mutex->lock);
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
chx_sched ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chopstx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *t;
|
||||
struct chx_thread *tp;
|
||||
int yield = 0;
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
@@ -775,13 +848,13 @@ chopstx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
running->mutex_list = mutex->list;
|
||||
mutex->list = NULL;
|
||||
|
||||
t = ll_pop (&mutex->q);
|
||||
if (t)
|
||||
tp = ll_pop (&mutex->q);
|
||||
if (tp)
|
||||
{
|
||||
uint16_t newprio = running->prio_orig;
|
||||
chopstx_mutex_t *m;
|
||||
|
||||
chx_ready_enqueue (t);
|
||||
chx_ready_enqueue (tp);
|
||||
|
||||
/* Examine mutexes we hold, and determine new priority for running. */
|
||||
for (m = running->mutex_list; m; m = m->list)
|
||||
@@ -790,7 +863,7 @@ chopstx_mutex_unlock (chopstx_mutex_t *mutex)
|
||||
/* Then, assign it. */
|
||||
running->prio = newprio;
|
||||
|
||||
if (t->prio > running->prio)
|
||||
if (tp->prio > running->prio)
|
||||
yield = 1;
|
||||
}
|
||||
|
||||
@@ -807,19 +880,20 @@ chopstx_cond_init (chopstx_cond_t *cond)
|
||||
cond->q.next = cond->q.prev = (struct chx_thread *)cond;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex)
|
||||
{
|
||||
struct chx_thread *t = running;
|
||||
struct chx_thread *tp = running;
|
||||
|
||||
if (mutex)
|
||||
chopstx_mutex_unlock (mutex);
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
chx_LOCK (&cond->lock);
|
||||
ll_prio_enqueue (t, &cond->q);
|
||||
t->state = THREAD_WAIT_CND;
|
||||
t->v = (uint32_t)cond;
|
||||
ll_prio_enqueue (tp, &cond->q);
|
||||
tp->state = THREAD_WAIT_CND;
|
||||
tp->v = (uint32_t)cond;
|
||||
chx_UNLOCK (&cond->lock);
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
|
||||
@@ -829,19 +903,20 @@ chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex)
|
||||
chopstx_mutex_lock (mutex);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chopstx_cond_signal (chopstx_cond_t *cond)
|
||||
{
|
||||
struct chx_thread *t;
|
||||
struct chx_thread *tp;
|
||||
int yield = 0;
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
chx_LOCK (&cond->lock);
|
||||
t = ll_pop (&cond->q);
|
||||
if (t)
|
||||
tp = ll_pop (&cond->q);
|
||||
if (tp)
|
||||
{
|
||||
chx_ready_enqueue (t);
|
||||
if (t->prio > running->prio)
|
||||
chx_ready_enqueue (tp);
|
||||
if (tp->prio > running->prio)
|
||||
yield = 1;
|
||||
}
|
||||
chx_UNLOCK (&cond->lock);
|
||||
@@ -851,18 +926,19 @@ chopstx_cond_signal (chopstx_cond_t *cond)
|
||||
chx_yield ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chopstx_cond_broadcast (chopstx_cond_t *cond)
|
||||
{
|
||||
struct chx_thread *t;
|
||||
struct chx_thread *tp;
|
||||
int yield = 1;
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
chx_LOCK (&cond->lock);
|
||||
while ((t = ll_pop (&cond->q)))
|
||||
while ((tp = ll_pop (&cond->q)))
|
||||
{
|
||||
chx_ready_enqueue (t);
|
||||
if (t->prio > running->prio)
|
||||
chx_ready_enqueue (tp);
|
||||
if (tp->prio > running->prio)
|
||||
yield = 1;
|
||||
}
|
||||
chx_UNLOCK (&cond->lock);
|
||||
@@ -876,7 +952,7 @@ void
|
||||
chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num)
|
||||
{
|
||||
intr->irq_num = irq_num;
|
||||
intr->t = running;
|
||||
intr->tp = running;
|
||||
intr->ready = 0;
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
chx_disable_intr (irq_num);
|
||||
@@ -907,14 +983,36 @@ chopstx_release_irq (chopstx_intr_t *intr0)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
chopstx_release_irq_thread (struct chx_thread *tp)
|
||||
{
|
||||
chopstx_intr_t *intr, *intr_prev;
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
intr_prev = intr_top;
|
||||
for (intr = intr_top; intr; intr = intr->next)
|
||||
if (intr->tp == tp)
|
||||
break;
|
||||
|
||||
if (intr)
|
||||
{
|
||||
chx_disable_intr (intr->irq_num);
|
||||
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)
|
||||
chopstx_intr_wait (chopstx_intr_t *intr)
|
||||
{
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
chx_enable_intr (intr->irq_num);
|
||||
while (intr->ready == 0)
|
||||
{
|
||||
intr->t = running;
|
||||
running->state = THREAD_WAIT_INT;
|
||||
running->v = 0;
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
@@ -930,40 +1028,37 @@ chopstx_wait_intr (chopstx_intr_t *intr)
|
||||
void __attribute__((noreturn))
|
||||
chopstx_exit (void *retval)
|
||||
{
|
||||
register uint32_t r4 __asm__ ("r4") = (uint32_t)retval;
|
||||
struct chx_thread *q;
|
||||
struct chx_mtx *m, *m_next;
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
/* wake up a thread waiting to join */
|
||||
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_join.lock);
|
||||
/* XXX: Call registered "release" routines here. */
|
||||
|
||||
chx_LOCK (&q_exit.lock);
|
||||
ll_insert (running, &q_exit);
|
||||
running->state = THREAD_EXITED;
|
||||
chx_UNLOCK (&q_exit.lock);
|
||||
asm volatile ("cpsie i" : : "r" (r4) : "memory");
|
||||
chx_sched ();
|
||||
/* never comes here. */
|
||||
for (;;);
|
||||
/* Release all mutexes this thread still holds. */
|
||||
for (m = running->mutex_list; m; m = m_next)
|
||||
{
|
||||
m_next = m->list;
|
||||
chopstx_mutex_unlock (m);
|
||||
}
|
||||
|
||||
chopstx_release_irq_thread (running);
|
||||
chx_exit (retval);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
void
|
||||
chopstx_join (chopstx_t thd, void **ret)
|
||||
{
|
||||
struct chx_thread *tp = (struct chx_thread *)thd;
|
||||
|
||||
/* XXX: check if another thread is waiting same thread and return error. */
|
||||
/* XXX: dead lock detection (waiting each other) and return error. */
|
||||
/* XXX: check if another thread is waiting same thread and call fatal. */
|
||||
/* XXX: dead lock detection (waiting each other) and call fatal. */
|
||||
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
if (tp->flag_detached)
|
||||
{
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
chx_fatal (CHOPSTX_ERR_JOIN);
|
||||
}
|
||||
|
||||
if (tp->state != THREAD_EXITED)
|
||||
{
|
||||
chx_LOCK (&q_join.lock);
|
||||
@@ -971,14 +1066,58 @@ chopstx_join (chopstx_t thd, void **ret)
|
||||
running->v = (uint32_t)tp;
|
||||
running->state = THREAD_JOIN;
|
||||
chx_UNLOCK (&q_join.lock);
|
||||
tp->flag_join_req = 1;
|
||||
if (tp->prio < running->prio)
|
||||
tp->prio = running->prio;
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
chx_sched ();
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
}
|
||||
else
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
|
||||
tp->state = THREAD_FINISHED;
|
||||
*ret = (void *)tp->tc.reg[0];
|
||||
return 0;
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chopstx_cancel (chopstx_t thd)
|
||||
{
|
||||
struct chx_thread *tp = (struct chx_thread *)thd;
|
||||
struct chx_stack_regs *p;
|
||||
int yield = 0;
|
||||
|
||||
/* Assume it's UP no case of: tp->state==RUNNING on SMP??? */
|
||||
asm volatile ("cpsid i" : : : "memory");
|
||||
tp->flag_got_cancel = 1;
|
||||
/* Cancellation points: cond_wait, intr_wait, and usec_wait. */
|
||||
if (tp->state == THREAD_WAIT_CND || tp->state == THREAD_WAIT_INT
|
||||
|| tp->state == THREAD_WAIT_TIME)
|
||||
{
|
||||
/* Throw away registers on stack and direct to copstx_exit. */
|
||||
/* This is pretty much violent, but it works. */
|
||||
p = (struct chx_stack_regs *)tp->tc.reg[REG_SP];
|
||||
p->reg[REG_R0] = CHOPSTX_EXIT_CANCELED;
|
||||
p->reg[REG_PC] = (uint32_t)chopstx_exit;
|
||||
|
||||
if (tp->state == THREAD_WAIT_CND)
|
||||
ll_dequeue (tp);
|
||||
else if (tp->state == THREAD_WAIT_TIME)
|
||||
chx_timer_dequeue (tp);
|
||||
|
||||
chx_ready_enqueue (tp);
|
||||
if (tp->prio > running->prio)
|
||||
yield = 1;
|
||||
}
|
||||
asm volatile ("cpsie i" : : : "memory");
|
||||
if (yield)
|
||||
chx_yield ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
chopstx_testcancel (void)
|
||||
{
|
||||
if (running->flag_got_cancel)
|
||||
chopstx_exit ((void *)CHOPSTX_EXIT_CANCELED_IN_SYNC);
|
||||
}
|
||||
|
||||
26
chopstx.h
26
chopstx.h
@@ -41,7 +41,7 @@ void chopstx_attr_setstack (chopstx_attr_t *attr, uint32_t addr,
|
||||
void chopstx_create (chopstx_t *thd, const chopstx_attr_t *attr,
|
||||
void *(thread_entry) (void *), void *);
|
||||
|
||||
void chopstx_usleep (uint32_t useconds);
|
||||
void chopstx_usec_wait (uint32_t useconds);
|
||||
|
||||
struct chx_spinlock {
|
||||
/* nothing for uniprocessor. */
|
||||
@@ -81,7 +81,7 @@ void chopstx_cond_broadcast (chopstx_cond_t *cond);
|
||||
typedef struct chx_intr {
|
||||
struct chx_intr *next;
|
||||
struct chx_spinlock lock;
|
||||
struct chx_thread *t;
|
||||
struct chx_thread *tp;
|
||||
uint8_t irq_num;
|
||||
uint8_t ready;
|
||||
} chopstx_intr_t;
|
||||
@@ -89,7 +89,25 @@ typedef struct chx_intr {
|
||||
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);
|
||||
void chopstx_intr_wait (chopstx_intr_t *intr);
|
||||
|
||||
/* Library provides default as weak reference. User can replace it. */
|
||||
void chx_fatal (uint32_t err_code);
|
||||
void chx_fatal (uint32_t err_code) __attribute__((__noreturn__));
|
||||
|
||||
void chopstx_join (chopstx_t, void **);
|
||||
void chopstx_exit (void *retval) __attribute__((__noreturn__));
|
||||
|
||||
|
||||
enum {
|
||||
CHOPSTX_ERR_NONE = 0,
|
||||
CHOPSTX_ERR_JOIN,
|
||||
};
|
||||
|
||||
enum {
|
||||
CHOPSTX_EXIT_SUCCESS = 0,
|
||||
CHOPSTX_EXIT_CANCELED = 256,
|
||||
CHOPSTX_EXIT_CANCELED_IN_SYNC = 257,
|
||||
};
|
||||
|
||||
void chopstx_cancel (chopstx_t thd);
|
||||
void chopstx_testcancel (void);
|
||||
|
||||
@@ -27,9 +27,9 @@ pwm (void *arg)
|
||||
while (1)
|
||||
{
|
||||
set_led (u&v);
|
||||
chopstx_usleep (m);
|
||||
chopstx_usec_wait (m);
|
||||
set_led (0);
|
||||
chopstx_usleep (100-m);
|
||||
chopstx_usec_wait (100-m);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -47,9 +47,9 @@ blk (void *arg)
|
||||
while (1)
|
||||
{
|
||||
v = 0;
|
||||
chopstx_usleep (200*1000);
|
||||
chopstx_usec_wait (200*1000);
|
||||
v = 1;
|
||||
chopstx_usleep (200*1000);
|
||||
chopstx_usec_wait (200*1000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -75,7 +75,7 @@ usb_intr (void *arg)
|
||||
|
||||
while (1)
|
||||
{
|
||||
chopstx_wait_intr (&interrupt);
|
||||
chopstx_intr_wait (&interrupt);
|
||||
|
||||
/* Process interrupt. */
|
||||
usb_interrupt_handler ();
|
||||
@@ -138,7 +138,7 @@ main (int argc, const char *argv[])
|
||||
|
||||
chopstx_create (&thd, &attr, usb_intr, NULL);
|
||||
|
||||
chopstx_usleep (200*1000);
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_signal (&cnd0);
|
||||
@@ -158,7 +158,7 @@ main (int argc, const char *argv[])
|
||||
while (1)
|
||||
{
|
||||
u ^= 1;
|
||||
chopstx_usleep (200*1000*6);
|
||||
chopstx_usec_wait (200*1000*6);
|
||||
|
||||
usb_lld_write (ENDP1, "Hello, World with Chopstx!\r\n", 28);
|
||||
chopstx_mutex_lock (&usb_mtx);
|
||||
|
||||
@@ -22,9 +22,9 @@ pwm (void *arg)
|
||||
while (1)
|
||||
{
|
||||
set_led (u&v);
|
||||
chopstx_usleep (m);
|
||||
chopstx_usec_wait (m);
|
||||
set_led (0);
|
||||
chopstx_usleep (100-m);
|
||||
chopstx_usec_wait (100-m);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -42,9 +42,9 @@ blk (void *arg)
|
||||
while (1)
|
||||
{
|
||||
v = 0;
|
||||
chopstx_usleep (200*1000);
|
||||
chopstx_usec_wait (200*1000);
|
||||
v = 1;
|
||||
chopstx_usleep (200*1000);
|
||||
chopstx_usec_wait (200*1000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -89,7 +89,7 @@ main (int argc, const char *argv[])
|
||||
|
||||
chopstx_create (&thd, &attr, blk, NULL);
|
||||
|
||||
chopstx_usleep (200*1000);
|
||||
chopstx_usec_wait (200*1000);
|
||||
|
||||
chopstx_mutex_lock (&mtx);
|
||||
chopstx_cond_signal (&cnd0);
|
||||
@@ -99,7 +99,7 @@ main (int argc, const char *argv[])
|
||||
while (1)
|
||||
{
|
||||
u ^= 1;
|
||||
chopstx_usleep (200*1000*6);
|
||||
chopstx_usec_wait (200*1000*6);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user