diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-13 16:35:35 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2016-05-13 16:35:35 +0900 |
commit | 5046dd45f2e675c37e505d42ecce746cb64b64f9 (patch) | |
tree | 3c1f7d860705d6e99984b571c15e76c2ded2b896 | |
parent | db6e66852440a50e607c1df4cdf309c52a861430 (diff) |
IRQ handling is now merged into polling
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | NEWS | 10 | ||||
-rw-r--r-- | chopstx.c | 184 | ||||
-rw-r--r-- | chopstx.h | 39 | ||||
-rw-r--r-- | example-cdc/sample.c | 1 | ||||
-rw-r--r-- | example-fs-bb48/sample.c | 1 | ||||
-rw-r--r-- | example-primer2/primer2-ts.c | 4 |
7 files changed, 112 insertions, 142 deletions
@@ -1,5 +1,20 @@ 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. (chx_handle_intr, chx_wakeup, chopstx_cancel): Fix for polling with no timeout. @@ -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 @@ -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; - - 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); - } - 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_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; + + ll_dequeue (p); + chx_wakeup (tp); + break; + } + 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,105 +1432,48 @@ 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; + chopstx_testcancel (); chx_cpu_sched_lock (); - chx_spin_lock (&intr_lock); - intr_prev = intr_top; - for (intr = intr_top; intr; intr = intr->next) + if (intr->ready) { - if (intr->tp == tp) - break; - intr_prev = intr; + chx_spin_lock (&px->lock); + (*px->counter_p)++; + *px->ready_p = 1; + chx_spin_unlock (&px->lock); } - - if (intr) + else { + px->v = intr->irq_num; + chx_spin_lock (&q_intr.lock); chx_enable_intr (intr->irq_num); - if (intr == intr_top) - intr_top = intr_top->next; - else - intr_prev->next = intr->next; + ll_prio_enqueue ((struct chx_pq *)px, &q_intr.q); + chx_spin_unlock (&q_intr.lock); } - 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) - { - 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); - } - else - chx_cpu_sched_unlock (); - intr->ready--; -} - - -/** * chopstx_cleanup_push - Register a clean-up * @clp: Pointer to clean-up structure * @@ -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; } @@ -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; diff --git a/example-cdc/sample.c b/example-cdc/sample.c index d2951fc..ee6d23f 100644 --- a/example-cdc/sample.c +++ b/example-cdc/sample.c @@ -92,7 +92,6 @@ usb_intr (void *arg) usb_interrupt_handler (); } - chopstx_release_irq (&interrupt); return NULL; } diff --git a/example-fs-bb48/sample.c b/example-fs-bb48/sample.c index 39864d4..9250700 100644 --- a/example-fs-bb48/sample.c +++ b/example-fs-bb48/sample.c @@ -115,7 +115,6 @@ usb_intr (void *arg) usb_interrupt_handler (); } - chopstx_release_irq (&interrupt); return NULL; } diff --git a/example-primer2/primer2-ts.c b/example-primer2/primer2-ts.c index eb1c4ec..c6952f1 100644 --- a/example-primer2/primer2-ts.c +++ b/example-primer2/primer2-ts.c @@ -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; |