diff options
author | NIIBE Yutaka <gniibe@fsij.org> | 2013-05-29 12:08:21 +0900 |
---|---|---|
committer | NIIBE Yutaka <gniibe@fsij.org> | 2013-05-29 12:08:21 +0900 |
commit | 1d535e3be811c670fcc94d6e44172d617491c383 (patch) | |
tree | 02dd2bafec5ea18b8986a797f4ec8d49dac6498f | |
parent | b5cdd769ee79395690582d42cb5857df15b545c9 (diff) |
fix race condition of handle_intr.
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | board/board-olimex-stm32-h103.h | 8 | ||||
-rw-r--r-- | chopstx.c | 55 | ||||
-rw-r--r-- | chopstx.h | 2 |
4 files changed, 56 insertions, 18 deletions
@@ -1,5 +1,14 @@ 2013-05-29 Niibe Yutaka <gniibe@fsij.org> + * chopstx.c (svc): Implement race avoidance between + chx_handle_intr. + (chx_handle_intr): Increment ->ready. Put to ready queue + only when it's not running. + (chx_sched): Add an argument for race avoidance. + (chopstx_intr_wait): Fix the race condition. + + * board/board-olimex-stm32-h103.h (NEUG_ADC_SETTING2_*): Add. + * chopstx.c (chx_mutex_unlock, chopstx_exit): New. (chopstx_mutex_unlock): Use chx_mutex_unlock. (chopstx_cond_wait): Fix race condition. diff --git a/board/board-olimex-stm32-h103.h b/board/board-olimex-stm32-h103.h index 69fdaaa..7063ab3 100644 --- a/board/board-olimex-stm32-h103.h +++ b/board/board-olimex-stm32-h103.h @@ -22,3 +22,11 @@ #define RCC_APB2ENR_IOP_EN RCC_APB2ENR_IOPCEN #define RCC_APB2RSTR_IOP_RST RCC_APB2RSTR_IOPCRST + +/* NeuG settings for ADC2. */ +#define NEUG_ADC_SETTING2_SMPR1 ADC_SMPR1_SMP_AN10(ADC_SAMPLE_1P5) \ + | ADC_SMPR1_SMP_AN11(ADC_SAMPLE_1P5) +#define NEUG_ADC_SETTING2_SMPR2 0 +#define NEUG_ADC_SETTING2_SQR3 ADC_SQR3_SQ1_N(ADC_CHANNEL_IN10) \ + | ADC_SQR3_SQ2_N(ADC_CHANNEL_IN11) +#define NEUG_ADC_SETTING2_NUM_CHANNELS 2 @@ -402,6 +402,7 @@ svc (void) { register uint32_t r0 asm ("r0"); register uint32_t orig_r0 asm ("r2"); + register uint32_t *orig_r1 asm ("r3"); asm volatile ("ldr r1, =running\n\t" "ldr r0, [r1]\n\t" @@ -414,8 +415,10 @@ svc (void) "mov r6, r11\n\t" "mrs r7, PSP\n\t" /* r13(=SP) in user space. */ "stm r2, {r3, r4, r5, r6, r7}\n\t" - "ldr r2, [r7]" - : "=r" (r0), "=r" (orig_r0) : /* no input */ : "memory"); + "ldr r2, [r7]\n\t" + "ldr r3, [r7, #4]\n\t" + : "=r" (r0), "=r" (orig_r0), "=r" (orig_r1) + : /* no input */ : "memory"); if (orig_r0) { @@ -427,6 +430,17 @@ svc (void) "cpsie i" /* Unmask interrupts. */ : /* no output */ : /* no input */ : "memory"); } + else if (orig_r1) + { + asm volatile ("cpsid i" : : : "memory"); + if (*orig_r1) + { + running->state = THREAD_RUNNING; + asm volatile ("cpsie i" : : : "memory"); + return; + } + /* call sched with keeping interrupt disabled. */ + } asm volatile ("b sched" : /* no output */: /* no input */ : "memory"); @@ -581,6 +595,7 @@ chx_set_intr_prio (uint8_t n) } static chopstx_intr_t *intr_top; +static volatile uint32_t *const ICSR = (uint32_t *const)0xE000ED04; void chx_handle_intr (void) @@ -597,12 +612,15 @@ chx_handle_intr (void) if (intr->irq_num == irq_num) break; - if (intr && intr->tp && intr->tp->state == THREAD_WAIT_INT) + if (intr) { intr->ready++; - chx_ready_enqueue (intr->tp); - if (running == NULL || running->prio < intr->tp->prio) - chx_request_preemption (); + if (intr->tp != running && intr->tp->state == THREAD_WAIT_INT) + { + chx_ready_enqueue (intr->tp); + if (running == NULL || running->prio < intr->tp->prio) + chx_request_preemption (); + } } asm volatile ("cpsie i" : : : "memory"); } @@ -643,18 +661,17 @@ chx_init (struct chx_thread *tp) static void chx_request_preemption (void) { - static volatile uint32_t *const ICSR = (uint32_t *const)0xE000ED04; - *ICSR = (1 << 28); asm volatile ("" : : : "memory"); } static void -chx_sched (void) +chx_sched (uint32_t *ptr) { register uint32_t r0 asm ("r0") = 0; + register uint32_t r1 asm ("r1") = (uint32_t)ptr; - asm volatile ("svc #0" : : "r" (r0) : "memory"); + asm volatile ("svc #0" : : "r" (r0), "r" (r1) : "memory"); } static void @@ -696,7 +713,7 @@ chx_exit (void *retval) running->state = THREAD_FINISHED; chx_UNLOCK (&q_exit.lock); asm volatile ("cpsie i" : : "r" (r4) : "memory"); - chx_sched (); + chx_sched (NULL); /* never comes here. */ for (;;); } @@ -804,7 +821,7 @@ chopstx_usec_wait (uint32_t usec) uint32_t usec0 = (usec > 200*1000) ? 200*1000: usec; chx_timer_insert (running, usec0); - chx_sched (); + chx_sched (NULL); usec -= usec0; } @@ -876,7 +893,7 @@ chopstx_mutex_lock (chopstx_mutex_t *mutex) tp->v = (uint32_t)mutex; chx_UNLOCK (&mutex->lock); asm volatile ("cpsie i" : : : "memory"); - chx_sched (); + chx_sched (NULL); } } @@ -925,7 +942,7 @@ chopstx_cond_wait (chopstx_cond_t *cond, chopstx_mutex_t *mutex) chx_UNLOCK (&cond->lock); asm volatile ("cpsie i" : : : "memory"); - chx_sched (); + chx_sched (NULL); if (mutex) chopstx_mutex_lock (mutex); @@ -1039,12 +1056,16 @@ chopstx_intr_wait (chopstx_intr_t *intr) { asm volatile ("cpsid i" : : : "memory"); chx_enable_intr (intr->irq_num); - while (intr->ready == 0) + if (intr->ready == 0) { running->state = THREAD_WAIT_INT; running->v = 0; asm volatile ("cpsie i" : : : "memory"); - chx_sched (); + /* + * Here is the race with chx_handle_intr. + * Bring a pointer to intr->ready, so that it won't sleep when ready. + */ + chx_sched (&intr->ready); asm volatile ("cpsid i" : : : "memory"); } intr->ready--; @@ -1103,7 +1124,7 @@ chopstx_join (chopstx_t thd, void **ret) if (tp->prio < running->prio) tp->prio = running->prio; asm volatile ("cpsie i" : : : "memory"); - chx_sched (); + chx_sched (NULL); asm volatile ("cpsid i" : : : "memory"); } @@ -82,8 +82,8 @@ typedef struct chx_intr { struct chx_intr *next; struct chx_spinlock lock; struct chx_thread *tp; + uint32_t ready; uint8_t irq_num; - uint8_t ready; } chopstx_intr_t; void chopstx_claim_irq (chopstx_intr_t *intr, uint8_t irq_num); |