IRQ handling is now merged into polling

This commit is contained in:
NIIBE Yutaka
2016-05-13 16:35:35 +09:00
parent db6e668524
commit 5046dd45f2
7 changed files with 113 additions and 143 deletions

View File

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

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

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

View File

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

View File

@@ -92,7 +92,6 @@ usb_intr (void *arg)
usb_interrupt_handler ();
}
chopstx_release_irq (&interrupt);
return NULL;
}

View File

@@ -115,7 +115,6 @@ usb_intr (void *arg)
usb_interrupt_handler ();
}
chopstx_release_irq (&interrupt);
return NULL;
}

View File

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