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> 2016-05-13 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chx_sched) [__ARM_ARCH_6M__]: Fix asm. * chopstx.c (chx_sched) [__ARM_ARCH_6M__]: Fix asm.

10
NEWS
View File

@@ -7,13 +7,19 @@ NEWS - Noteworthy changes
** New feature: polling ** New feature: polling
New function chopstx_poll is added to watch multiple condition 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 ** FS-BB48: Kinetis L MCU
Support for FS-BB48 board with Kinetis L MCU is added. Support for FS-BB48 board with Kinetis L MCU is added.
** No HardFault at context switch on Cortex-M0 ** 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 This is implemented with the feature of BASEPRI on Cortex-M3. Because
Cortex-M0 doesn't have support of BASEPRI, the context switch (before Cortex-M0 doesn't have support of BASEPRI, the context switch (before
version 0.11) always caused HardFault exception. Since Cortex-M0 version 0.11) always caused HardFault exception. Since Cortex-M0

186
chopstx.c
View File

@@ -239,12 +239,13 @@ static struct chx_queue q_ready;
/* Queue of threads waiting for timer. */ /* Queue of threads waiting for timer. */
static struct chx_queue q_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; static struct chx_queue q_join;
/* Forward declaration(s). */ /* Forward declaration(s). */
static void chx_request_preemption (uint16_t prio); 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_MTX,
THREAD_WAIT_CND, THREAD_WAIT_CND,
THREAD_WAIT_TIME, THREAD_WAIT_TIME,
THREAD_WAIT_INT,
THREAD_WAIT_POLL, THREAD_WAIT_POLL,
THREAD_JOIN, THREAD_JOIN,
/**/ /**/
@@ -612,44 +612,30 @@ chx_timer_expired (void)
chx_spin_unlock (&q_timer.lock); chx_spin_unlock (&q_timer.lock);
} }
static chopstx_intr_t *intr_top; /* Queue of threads which wait for some interrupts. */
static struct chx_spinlock intr_lock; static struct chx_queue q_intr;
void void
chx_handle_intr (void) chx_handle_intr (void)
{ {
chopstx_intr_t *intr; struct chx_pq *p;
register uint32_t irq_num; register uint32_t irq_num;
asm volatile ("mrs %0, IPSR\n\t" asm volatile ("mrs %0, IPSR\n\t"
"sub %0, #16" /* Exception # - 16 = interrupt number. */ "sub %0, #16" /* Exception # - 16 = interrupt number. */
: "=r" (irq_num) : /* no input */ : "memory"); : "=r" (irq_num) : /* no input */ : "memory");
chx_disable_intr (irq_num); chx_disable_intr (irq_num);
chx_spin_lock (&intr_lock); chx_spin_lock (&q_intr.lock);
for (intr = intr_top; intr; intr = intr->next) for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
if (intr->irq_num == irq_num) if (p->v == irq_num)
break; { /* should be one at most. */
struct chx_thread *tp = (struct chx_thread *)p;
if (intr) ll_dequeue (p);
{ chx_wakeup (tp);
intr->ready++; break;
if (intr->tp != running) }
{ chx_spin_unlock (&q_intr.lock);
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);
}
else if (intr->tp->state == THREAD_WAIT_INT)
{
chx_ready_enqueue (intr->tp);
chx_request_preemption (intr->tp->prio);
}
}
}
chx_spin_unlock (&intr_lock);
} }
void void
@@ -672,7 +658,6 @@ chopstx_t chopstx_main;
void void
chx_init (struct chx_thread *tp) chx_init (struct chx_thread *tp)
{ {
chx_spin_init (&intr_lock);
chx_prio_init (); chx_prio_init ();
memset (&tp->tc, 0, sizeof (tp->tc)); memset (&tp->tc, 0, sizeof (tp->tc));
q_ready.q.next = q_ready.q.prev = (struct chx_pq *)&q_ready.q; 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); chx_spin_init (&q_timer.lock);
q_join.q.next = q_join.q.prev = (struct chx_pq *)&q_join.q; q_join.q.next = q_join.q.prev = (struct chx_pq *)&q_join.q;
chx_spin_init (&q_join.lock); 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->next = tp->prev = (struct chx_pq *)tp;
tp->mutex_list = NULL; tp->mutex_list = NULL;
tp->clp = 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 * chopstx_claim_irq - Claim interrupt request to handle by this thread
* @intr: Pointer to INTR structure * @intr: Pointer to INTR structure
@@ -1432,101 +1432,44 @@ void
chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num) chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num)
{ {
intr->type = CHOPSTX_POLL_INTR; intr->type = CHOPSTX_POLL_INTR;
intr->irq_num = irq_num;
intr->tp = running;
intr->ready = 0; 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_cpu_sched_lock ();
chx_spin_lock (&q_intr.lock);
chx_disable_intr (irq_num); chx_disable_intr (irq_num);
chx_set_intr_prio (irq_num); chx_set_intr_prio (irq_num);
chx_spin_lock (&intr_lock); chx_spin_unlock (&q_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_cpu_sched_unlock (); chx_cpu_sched_unlock ();
} }
static void 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 (); chopstx_testcancel ();
chx_cpu_sched_lock (); chx_cpu_sched_lock ();
if (intr->ready == 0) if (intr->ready)
{ {
chx_enable_intr (intr->irq_num); chx_spin_lock (&px->lock);
if (running->flag_sched_rr) (*px->counter_p)++;
chx_timer_dequeue (running); *px->ready_p = 1;
running->state = THREAD_WAIT_INT; chx_spin_unlock (&px->lock);
running->parent = NULL;
running->v = 0;
chx_sched (CHX_SLEEP);
chx_clr_intr (intr->irq_num);
} }
else else
chx_cpu_sched_unlock (); {
intr->ready--; 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 ();
} }
@@ -1598,7 +1541,6 @@ chopstx_exit (void *retval)
chx_cpu_sched_unlock (); chx_cpu_sched_unlock ();
} }
chx_release_irq_thread (running);
chx_exit (retval); chx_exit (retval);
} }
@@ -1742,8 +1684,8 @@ chopstx_cancel (chopstx_t thd)
} }
/* Cancellation points: cond_wait, intr_wait, and usec_wait. */ /* Cancellation points: cond_wait, intr_wait, and usec_wait. */
if (tp->state == THREAD_WAIT_CND || tp->state == THREAD_WAIT_INT if (tp->state == THREAD_WAIT_CND || tp->state == THREAD_WAIT_TIME
|| tp->state == THREAD_WAIT_TIME || tp->state == THREAD_WAIT_POLL) || tp->state == THREAD_WAIT_POLL)
{ {
/* Throw away registers on stack and direct to chopstx_exit. */ /* Throw away registers on stack and direct to chopstx_exit. */
/* This is pretty much violent, but it works. */ /* 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 * chopstx_poll - wait for condition variable, thread's exit, or IRQ
* @usec_p: Pointer to usec * @usec_p: Pointer to usec for timeout. Forever if NULL.
* @n: Number of poll descriptors * @n: Number of poll descriptors
* @VARARGS: Pointers to an object which should be one of: * @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. * 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 *); pd = va_arg (ap, struct chx_poll_head *);
if (pd->type == CHOPSTX_POLL_COND) if (pd->type == CHOPSTX_POLL_COND)
chx_cond_hook (&px[i], pd); chx_cond_hook (&px[i], pd);
else if (pd->type == CHOPSTX_POLL_INTR)
chx_intr_hook (&px[i], pd);
else else
chx_join_hook (&px[i], pd); chx_join_hook (&px[i], pd);
px[i].ready_p = &pd->ready; px[i].ready_p = &pd->ready;
@@ -1864,7 +1808,7 @@ chopstx_poll (uint32_t *usec_p, int n, ...)
chx_spin_unlock (&px->lock); chx_spin_unlock (&px->lock);
chx_cpu_sched_unlock (); chx_cpu_sched_unlock ();
} }
else if (*usec_p == 0) else if (usec_p == NULL)
{ {
if (running->flag_sched_rr) if (running->flag_sched_rr)
chx_timer_dequeue (running); chx_timer_dequeue (running);
@@ -1888,14 +1832,24 @@ chopstx_poll (uint32_t *usec_p, int n, ...)
while (r == 0); while (r == 0);
} }
va_start (ap, n);
for (i = 0; i < n; i++) 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_cpu_sched_lock ();
chx_spin_lock (&px[i].lock); chx_spin_lock (&px[i].lock);
ll_dequeue ((struct chx_pq *)&px[i]); ll_dequeue ((struct chx_pq *)&px[i]);
chx_spin_unlock (&px[i].lock); chx_spin_unlock (&px[i].lock);
chx_cpu_sched_unlock (); chx_cpu_sched_unlock ();
} }
va_end (ap);
return counter; 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_signal (chopstx_cond_t *cond);
void chopstx_cond_broadcast (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. * Library provides default implementation as weak reference.
* User can replace it. * User can replace it.
@@ -125,14 +110,14 @@ void chopstx_testcancel (void);
/* NOTE: This signature is different to PTHREAD's one. */ /* NOTE: This signature is different to PTHREAD's one. */
int chopstx_setcancelstate (int); int chopstx_setcancelstate (int);
struct chx_cleanup { typedef struct chx_cleanup {
struct chx_cleanup *next; struct chx_cleanup *next;
void (*routine) (void *); void (*routine) (void *);
void *arg; void *arg;
}; } chopstx_cleanup_t;
/* NOTE: This signature is different to PTHREAD's one. */ /* 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); void chopstx_cleanup_pop (int execute);
@@ -140,8 +125,8 @@ void chopstx_wakeup_usec_wait (chopstx_t thd);
enum { enum {
CHOPSTX_POLL_COND = 0, CHOPSTX_POLL_COND = 0,
CHOPSTX_POLL_JOIN,
CHOPSTX_POLL_INTR, CHOPSTX_POLL_INTR,
CHOPSTX_POLL_JOIN,
}; };
struct chx_poll_cond { struct chx_poll_cond {
@@ -153,6 +138,7 @@ struct chx_poll_cond {
int (*check) (void *); int (*check) (void *);
void *arg; void *arg;
}; };
typedef struct chx_poll_cond chopstx_poll_cond_t;
struct chx_poll_join { struct chx_poll_join {
uint16_t type; uint16_t type;
@@ -160,6 +146,21 @@ struct chx_poll_join {
/**/ /**/
chopstx_t thd; 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 { struct chx_poll_head {
uint16_t type; uint16_t type;

View File

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

View File

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

View File

@@ -113,10 +113,6 @@ void adc3_conversion (uint32_t *result)
void adc3_stop (void) void adc3_stop (void)
{ {
#if USE_ADC3_INTR
chopstx_release_irq (&adc3_intr);
#endif
/* Power off. */ /* Power off. */
ADC3->CR1 = 0; ADC3->CR1 = 0;
ADC3->CR2 = 0; ADC3->CR2 = 0;