IRQ handling is now merged into polling
This commit is contained in:
15
ChangeLog
15
ChangeLog
@@ -1,3 +1,18 @@
|
||||
2016-05-13 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chopstx_exit): Don't call chx_release_irq_thread.
|
||||
(chx_release_irq_thread): Remove.
|
||||
(q_intr): New variable.
|
||||
(intr_top): Remove.
|
||||
(chx_handle_intr, chx_init, chopstx_claim_irq)
|
||||
(chopstx_intr_wait): Use Q_INTR.
|
||||
(chx_intr_hook): New.
|
||||
(chopstx_poll): Support CHOPSTX_POLL_INTR.
|
||||
(chopstx_release_irq): Remove.
|
||||
(chx_release_irq): New internal function.
|
||||
(THREAD_WAIT_INT): Remove.
|
||||
(chopstx_intr_wait): Remove, now offered as a macro.
|
||||
|
||||
2016-05-13 NIIBE Yutaka <gniibe@fsij.org>
|
||||
|
||||
* chopstx.c (chx_sched) [__ARM_ARCH_6M__]: Fix asm.
|
||||
|
||||
10
NEWS
10
NEWS
@@ -7,13 +7,19 @@ NEWS - Noteworthy changes
|
||||
|
||||
** New feature: polling
|
||||
New function chopstx_poll is added to watch multiple condition
|
||||
variables simultaneously with timeout.
|
||||
variables, threads' exit, or IRQ simultaneously with timeout.
|
||||
|
||||
** Remove the function chopstx_release_irq
|
||||
Releasing irq is now called automaticall, internally.
|
||||
|
||||
** Function chopstx_intr_wait is deprecated
|
||||
It's now a macro with chopstx_poll.
|
||||
|
||||
** FS-BB48: Kinetis L MCU
|
||||
Support for FS-BB48 board with Kinetis L MCU is added.
|
||||
|
||||
** No HardFault at context switch on Cortex-M0
|
||||
By its design, Chopstx does context switch hodling scheduler lock.
|
||||
By its design, Chopstx does context switch holding the scheduler lock.
|
||||
This is implemented with the feature of BASEPRI on Cortex-M3. Because
|
||||
Cortex-M0 doesn't have support of BASEPRI, the context switch (before
|
||||
version 0.11) always caused HardFault exception. Since Cortex-M0
|
||||
|
||||
182
chopstx.c
182
chopstx.c
@@ -239,12 +239,13 @@ static struct chx_queue q_ready;
|
||||
/* Queue of threads waiting for timer. */
|
||||
static struct chx_queue q_timer;
|
||||
|
||||
/* Queue of threads which wait exit of some thread. */
|
||||
/* Queue of threads which wait for the exit of some thread. */
|
||||
static struct chx_queue q_join;
|
||||
|
||||
|
||||
/* Forward declaration(s). */
|
||||
static void chx_request_preemption (uint16_t prio);
|
||||
static int chx_wakeup (struct chx_thread *tp);
|
||||
|
||||
|
||||
/**************/
|
||||
@@ -440,7 +441,6 @@ enum {
|
||||
THREAD_WAIT_MTX,
|
||||
THREAD_WAIT_CND,
|
||||
THREAD_WAIT_TIME,
|
||||
THREAD_WAIT_INT,
|
||||
THREAD_WAIT_POLL,
|
||||
THREAD_JOIN,
|
||||
/**/
|
||||
@@ -612,44 +612,30 @@ chx_timer_expired (void)
|
||||
chx_spin_unlock (&q_timer.lock);
|
||||
}
|
||||
|
||||
static chopstx_intr_t *intr_top;
|
||||
static struct chx_spinlock intr_lock;
|
||||
/* Queue of threads which wait for some interrupts. */
|
||||
static struct chx_queue q_intr;
|
||||
|
||||
void
|
||||
chx_handle_intr (void)
|
||||
{
|
||||
chopstx_intr_t *intr;
|
||||
struct chx_pq *p;
|
||||
register uint32_t irq_num;
|
||||
|
||||
asm volatile ("mrs %0, IPSR\n\t"
|
||||
"sub %0, #16" /* Exception # - 16 = interrupt number. */
|
||||
: "=r" (irq_num) : /* no input */ : "memory");
|
||||
chx_disable_intr (irq_num);
|
||||
chx_spin_lock (&intr_lock);
|
||||
for (intr = intr_top; intr; intr = intr->next)
|
||||
if (intr->irq_num == irq_num)
|
||||
break;
|
||||
chx_spin_lock (&q_intr.lock);
|
||||
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
|
||||
if (p->v == irq_num)
|
||||
{ /* should be one at most. */
|
||||
struct chx_thread *tp = (struct chx_thread *)p;
|
||||
|
||||
if (intr)
|
||||
{
|
||||
intr->ready++;
|
||||
if (intr->tp != running)
|
||||
{
|
||||
if (intr->tp->state == THREAD_WAIT_POLL)
|
||||
{
|
||||
if (intr->tp->parent == &q_timer.q)
|
||||
chx_timer_dequeue (intr->tp);
|
||||
chx_ready_enqueue (intr->tp);
|
||||
chx_request_preemption (intr->tp->prio);
|
||||
ll_dequeue (p);
|
||||
chx_wakeup (tp);
|
||||
break;
|
||||
}
|
||||
else if (intr->tp->state == THREAD_WAIT_INT)
|
||||
{
|
||||
chx_ready_enqueue (intr->tp);
|
||||
chx_request_preemption (intr->tp->prio);
|
||||
}
|
||||
}
|
||||
}
|
||||
chx_spin_unlock (&intr_lock);
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -672,7 +658,6 @@ chopstx_t chopstx_main;
|
||||
void
|
||||
chx_init (struct chx_thread *tp)
|
||||
{
|
||||
chx_spin_init (&intr_lock);
|
||||
chx_prio_init ();
|
||||
memset (&tp->tc, 0, sizeof (tp->tc));
|
||||
q_ready.q.next = q_ready.q.prev = (struct chx_pq *)&q_ready.q;
|
||||
@@ -681,6 +666,8 @@ chx_init (struct chx_thread *tp)
|
||||
chx_spin_init (&q_timer.lock);
|
||||
q_join.q.next = q_join.q.prev = (struct chx_pq *)&q_join.q;
|
||||
chx_spin_init (&q_join.lock);
|
||||
q_intr.q.next = q_intr.q.prev = (struct chx_pq *)&q_intr.q;
|
||||
chx_spin_init (&q_intr.lock);
|
||||
tp->next = tp->prev = (struct chx_pq *)tp;
|
||||
tp->mutex_list = NULL;
|
||||
tp->clp = NULL;
|
||||
@@ -1421,6 +1408,19 @@ chx_cond_hook (struct chx_px *px, struct chx_poll_head *pd)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Release the interrupt request.
|
||||
*/
|
||||
static void
|
||||
chx_release_irq (chopstx_intr_t *intr)
|
||||
{
|
||||
chx_cpu_sched_lock ();
|
||||
chx_spin_lock (&q_intr.lock);
|
||||
chx_enable_intr (intr->irq_num);
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
chx_cpu_sched_unlock ();
|
||||
}
|
||||
|
||||
/**
|
||||
* chopstx_claim_irq - Claim interrupt request to handle by this thread
|
||||
* @intr: Pointer to INTR structure
|
||||
@@ -1432,101 +1432,44 @@ 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;
|
||||
intr->irq_num = irq_num;
|
||||
intr->cln.routine = (void (*)(void *))chx_release_irq;
|
||||
intr->cln.arg = (void *)intr;
|
||||
chopstx_cleanup_push (&intr->cln);
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
chx_spin_lock (&q_intr.lock);
|
||||
chx_disable_intr (irq_num);
|
||||
chx_set_intr_prio (irq_num);
|
||||
chx_spin_lock (&intr_lock);
|
||||
intr->next = intr_top;
|
||||
intr_top = intr;
|
||||
chx_spin_unlock (&intr_lock);
|
||||
chx_cpu_sched_unlock ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* chopstx_realease_irq - Unregister interrupt request
|
||||
* @intr0: Interrupt request to be unregistered
|
||||
*
|
||||
* Release the interrupt request specified by @intr0.
|
||||
*/
|
||||
void
|
||||
chopstx_release_irq (chopstx_intr_t *intr0)
|
||||
{
|
||||
chopstx_intr_t *intr, *intr_prev;
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
chx_enable_intr (intr0->irq_num);
|
||||
chx_spin_lock (&intr_lock);
|
||||
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;
|
||||
chx_spin_unlock (&intr_lock);
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
chx_cpu_sched_unlock ();
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
chx_release_irq_thread (struct chx_thread *tp)
|
||||
chx_intr_hook (struct chx_px *px, struct chx_poll_head *pd)
|
||||
{
|
||||
chopstx_intr_t *intr, *intr_prev;
|
||||
struct chx_intr *intr = (struct chx_intr *)pd;
|
||||
|
||||
chx_cpu_sched_lock ();
|
||||
chx_spin_lock (&intr_lock);
|
||||
intr_prev = intr_top;
|
||||
for (intr = intr_top; intr; intr = intr->next)
|
||||
{
|
||||
if (intr->tp == tp)
|
||||
break;
|
||||
intr_prev = intr;
|
||||
}
|
||||
|
||||
if (intr)
|
||||
{
|
||||
chx_enable_intr (intr->irq_num);
|
||||
if (intr == intr_top)
|
||||
intr_top = intr_top->next;
|
||||
else
|
||||
intr_prev->next = intr->next;
|
||||
}
|
||||
chx_spin_unlock (&intr_lock);
|
||||
chx_cpu_sched_unlock ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* chopstx_intr_wait - Wait for interrupt request from hardware
|
||||
* @intr: Pointer to INTR structure
|
||||
*
|
||||
* Wait for the interrupt @intr to be occured.
|
||||
*/
|
||||
void
|
||||
chopstx_intr_wait (chopstx_intr_t *intr)
|
||||
{
|
||||
chopstx_testcancel ();
|
||||
chx_cpu_sched_lock ();
|
||||
if (intr->ready == 0)
|
||||
if (intr->ready)
|
||||
{
|
||||
chx_enable_intr (intr->irq_num);
|
||||
if (running->flag_sched_rr)
|
||||
chx_timer_dequeue (running);
|
||||
running->state = THREAD_WAIT_INT;
|
||||
running->parent = NULL;
|
||||
running->v = 0;
|
||||
chx_sched (CHX_SLEEP);
|
||||
chx_clr_intr (intr->irq_num);
|
||||
chx_spin_lock (&px->lock);
|
||||
(*px->counter_p)++;
|
||||
*px->ready_p = 1;
|
||||
chx_spin_unlock (&px->lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
px->v = intr->irq_num;
|
||||
chx_spin_lock (&q_intr.lock);
|
||||
chx_enable_intr (intr->irq_num);
|
||||
ll_prio_enqueue ((struct chx_pq *)px, &q_intr.q);
|
||||
chx_spin_unlock (&q_intr.lock);
|
||||
}
|
||||
chx_cpu_sched_unlock ();
|
||||
intr->ready--;
|
||||
}
|
||||
|
||||
|
||||
@@ -1598,7 +1541,6 @@ chopstx_exit (void *retval)
|
||||
chx_cpu_sched_unlock ();
|
||||
}
|
||||
|
||||
chx_release_irq_thread (running);
|
||||
chx_exit (retval);
|
||||
}
|
||||
|
||||
@@ -1742,8 +1684,8 @@ chopstx_cancel (chopstx_t thd)
|
||||
}
|
||||
|
||||
/* 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 || tp->state == THREAD_WAIT_POLL)
|
||||
if (tp->state == THREAD_WAIT_CND || tp->state == THREAD_WAIT_TIME
|
||||
|| tp->state == THREAD_WAIT_POLL)
|
||||
{
|
||||
/* Throw away registers on stack and direct to chopstx_exit. */
|
||||
/* This is pretty much violent, but it works. */
|
||||
@@ -1823,11 +1765,11 @@ 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
|
||||
* chopstx_poll - wait for condition variable, thread's exit, or IRQ
|
||||
* @usec_p: Pointer to usec for timeout. Forever if NULL.
|
||||
* @n: Number of poll descriptors
|
||||
* @VARARGS: Pointers to an object which should be one of:
|
||||
* struct chx_poll_cond, chx_poll_join, or chx_intr.
|
||||
* chopstx_poll_cond_t, chopstx_poll_join_t, or chopstx_intr_t.
|
||||
*
|
||||
* Returns number of active descriptors.
|
||||
*/
|
||||
@@ -1851,6 +1793,8 @@ chopstx_poll (uint32_t *usec_p, int n, ...)
|
||||
pd = va_arg (ap, struct chx_poll_head *);
|
||||
if (pd->type == CHOPSTX_POLL_COND)
|
||||
chx_cond_hook (&px[i], pd);
|
||||
else if (pd->type == CHOPSTX_POLL_INTR)
|
||||
chx_intr_hook (&px[i], pd);
|
||||
else
|
||||
chx_join_hook (&px[i], pd);
|
||||
px[i].ready_p = &pd->ready;
|
||||
@@ -1864,7 +1808,7 @@ chopstx_poll (uint32_t *usec_p, int n, ...)
|
||||
chx_spin_unlock (&px->lock);
|
||||
chx_cpu_sched_unlock ();
|
||||
}
|
||||
else if (*usec_p == 0)
|
||||
else if (usec_p == NULL)
|
||||
{
|
||||
if (running->flag_sched_rr)
|
||||
chx_timer_dequeue (running);
|
||||
@@ -1888,14 +1832,24 @@ 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_head *);
|
||||
if (pd->type == CHOPSTX_POLL_INTR)
|
||||
{
|
||||
struct chx_intr *intr = (struct chx_intr *)pd;
|
||||
if (intr->ready)
|
||||
chx_clr_intr (intr->irq_num);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
39
chopstx.h
39
chopstx.h
@@ -82,21 +82,6 @@ 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);
|
||||
|
||||
struct chx_intr {
|
||||
uint16_t type;
|
||||
uint16_t ready;
|
||||
/**/
|
||||
struct chx_intr *next;
|
||||
struct chx_thread *tp;
|
||||
uint8_t irq_num;
|
||||
};
|
||||
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);
|
||||
|
||||
void chopstx_intr_wait (chopstx_intr_t *intr);
|
||||
|
||||
/*
|
||||
* Library provides default implementation as weak reference.
|
||||
* User can replace it.
|
||||
@@ -125,14 +110,14 @@ void chopstx_testcancel (void);
|
||||
/* NOTE: This signature is different to PTHREAD's one. */
|
||||
int chopstx_setcancelstate (int);
|
||||
|
||||
struct chx_cleanup {
|
||||
typedef struct chx_cleanup {
|
||||
struct chx_cleanup *next;
|
||||
void (*routine) (void *);
|
||||
void *arg;
|
||||
};
|
||||
} chopstx_cleanup_t;
|
||||
|
||||
/* NOTE: This signature is different to PTHREAD's one. */
|
||||
void chopstx_cleanup_push (struct chx_cleanup *clp);
|
||||
void chopstx_cleanup_push (chopstx_cleanup_t *clp);
|
||||
void chopstx_cleanup_pop (int execute);
|
||||
|
||||
|
||||
@@ -140,8 +125,8 @@ void chopstx_wakeup_usec_wait (chopstx_t thd);
|
||||
|
||||
enum {
|
||||
CHOPSTX_POLL_COND = 0,
|
||||
CHOPSTX_POLL_JOIN,
|
||||
CHOPSTX_POLL_INTR,
|
||||
CHOPSTX_POLL_JOIN,
|
||||
};
|
||||
|
||||
struct chx_poll_cond {
|
||||
@@ -153,6 +138,7 @@ struct chx_poll_cond {
|
||||
int (*check) (void *);
|
||||
void *arg;
|
||||
};
|
||||
typedef struct chx_poll_cond chopstx_poll_cond_t;
|
||||
|
||||
struct chx_poll_join {
|
||||
uint16_t type;
|
||||
@@ -160,6 +146,21 @@ struct chx_poll_join {
|
||||
/**/
|
||||
chopstx_t thd;
|
||||
};
|
||||
typedef struct chx_poll_join chopstx_poll_join_t;
|
||||
|
||||
struct chx_intr {
|
||||
uint16_t type;
|
||||
uint16_t ready;
|
||||
/**/
|
||||
uint8_t irq_num;
|
||||
struct chx_cleanup cln;
|
||||
};
|
||||
typedef struct chx_intr chopstx_intr_t;
|
||||
|
||||
void chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num);
|
||||
|
||||
#define chopstx_intr_wait(intr) chopstx_poll (NULL, 1, intr)
|
||||
|
||||
|
||||
struct chx_poll_head {
|
||||
uint16_t type;
|
||||
|
||||
@@ -92,7 +92,6 @@ usb_intr (void *arg)
|
||||
usb_interrupt_handler ();
|
||||
}
|
||||
|
||||
chopstx_release_irq (&interrupt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,7 +115,6 @@ usb_intr (void *arg)
|
||||
usb_interrupt_handler ();
|
||||
}
|
||||
|
||||
chopstx_release_irq (&interrupt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -113,10 +113,6 @@ void adc3_conversion (uint32_t *result)
|
||||
void adc3_stop (void)
|
||||
{
|
||||
|
||||
#if USE_ADC3_INTR
|
||||
chopstx_release_irq (&adc3_intr);
|
||||
#endif
|
||||
|
||||
/* Power off. */
|
||||
ADC3->CR1 = 0;
|
||||
ADC3->CR2 = 0;
|
||||
|
||||
Reference in New Issue
Block a user