Removal of CHOPSTX_PRIO_INHIBIT_PREEMPTION.
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
37
ChangeLog
37
ChangeLog
@@ -1,3 +1,40 @@
|
|||||||
|
2019-11-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
|
* chopstx.h (CHOPSTX_PRIO_INHIBIT_PREEMPTION): Remove.
|
||||||
|
* chopstx.c (chx_init): Remove support of
|
||||||
|
CHOPSTX_PRIO_INHIBIT_PREEMPTION.
|
||||||
|
(chopstx_setpriority): Likewise.
|
||||||
|
|
||||||
|
* chopstx-cortex-m.c (CPU_EXCEPTION_PRIORITY_PENDSV): Change the
|
||||||
|
value. Now PendSV exception runs at same priority level of
|
||||||
|
all other exceptions (systick and interrupt exception).
|
||||||
|
(chx_cpu_sched_lock, chx_cpu_sched_unlock):
|
||||||
|
Remove support of CHOPSTX_PRIO_INHIBIT_PREEMPTION.
|
||||||
|
(chx_request_preemption): Change the argument with none.
|
||||||
|
(chx_timer_handler): New. Use common function of
|
||||||
|
chx_timer_expired, local one, chx_request_preemption.
|
||||||
|
(chx_handle_intr): Use chx_recv_irq.
|
||||||
|
(chx_sched): Remove support of CHOPSTX_PRIO_INHIBIT_PREEMPTION.
|
||||||
|
(preempt): Have an argument from tail-chaining.
|
||||||
|
Remove support of CHOPSTX_PRIO_INHIBIT_PREEMPTION.
|
||||||
|
|
||||||
|
* chopstx-gnu-linux.c (chx_idle): Rename.
|
||||||
|
(chx_init_arch): Follow the rename.
|
||||||
|
(chx_handle_intr): Use chx_recv_irq, chx_running_preempted, and
|
||||||
|
chx_preempt_into.
|
||||||
|
(sigalrm_handler): Use chx_timer_expired, chx_running_preempted,
|
||||||
|
and chx_preempt_into.
|
||||||
|
(chx_preempt_into): Rename from chx_request_preemption, changing
|
||||||
|
argument. Remove the handling of preempted thread, which should
|
||||||
|
be done by caller using chx_running_preempted, beforehand.
|
||||||
|
|
||||||
|
* entry.c (vector_table): Use chx_timer_handler.
|
||||||
|
|
||||||
|
* chopstx.c (chx_timer_expired): Pop from the ready queue and
|
||||||
|
return the next thread to switch.
|
||||||
|
(chx_recv_irq): New.
|
||||||
|
(chx_running_preempted): New.
|
||||||
|
|
||||||
2019-11-21 NIIBE Yutaka <gniibe@fsij.org>
|
2019-11-21 NIIBE Yutaka <gniibe@fsij.org>
|
||||||
|
|
||||||
* chopstx-cortex-m.c (chx_set_running): New.
|
* chopstx-cortex-m.c (chx_set_running): New.
|
||||||
|
|||||||
13
NEWS
13
NEWS
@@ -1,6 +1,19 @@
|
|||||||
NEWS - Noteworthy changes
|
NEWS - Noteworthy changes
|
||||||
|
|
||||||
|
|
||||||
|
* Major changes in Chopstx 2.0
|
||||||
|
|
||||||
|
** Remove support of CHOPSTX_PRIO_INHIBIT_PREEMPTION
|
||||||
|
We used to have (an experimental) feature of higher priority of thread
|
||||||
|
(>= CHOPSTX_PRIO_INHIBIT_PREEMPTION). The feature offered: When a
|
||||||
|
thread has such a priority, Chostx guarantees that it keeps running
|
||||||
|
and no other threads can preempt the thread until the thread
|
||||||
|
voluntarily leaves running. I had introduced this (questionable)
|
||||||
|
feature as an excuse against no support of masking/unmasking interrupt
|
||||||
|
API. From the experience of Chopstx, it is rather consistent to
|
||||||
|
remove this feature.
|
||||||
|
|
||||||
|
|
||||||
* Major changes in Chopstx 1.17
|
* Major changes in Chopstx 1.17
|
||||||
|
|
||||||
Released 2019-11-20
|
Released 2019-11-20
|
||||||
|
|||||||
@@ -76,17 +76,15 @@ struct chx_stack_regs {
|
|||||||
* ---------------------
|
* ---------------------
|
||||||
* Prio 0x40: thread temporarily inhibiting schedule for critical region
|
* Prio 0x40: thread temporarily inhibiting schedule for critical region
|
||||||
* ...
|
* ...
|
||||||
* Prio 0xb0: systick, external interrupt
|
* Prio 0xb0: systick, external interrupt, pendsv
|
||||||
* Prio 0xc0: pendsv
|
|
||||||
* =====================================
|
* =====================================
|
||||||
*
|
*
|
||||||
* Cortex-M0
|
* Cortex-M0
|
||||||
* =====================================
|
* =====================================
|
||||||
* Prio 0x00: thread temporarily inhibiting schedule for critical region
|
* Prio 0x00: thread temporarily inhibiting schedule for critical region
|
||||||
* ...
|
* ...
|
||||||
* Prio 0x40: systick, external interrupt
|
* Prio 0x40: systick, external interrupt, pendsv
|
||||||
* Prio 0x80: pendsv
|
* Prio 0x80: svc (not used)
|
||||||
* Prio 0x80: svc
|
|
||||||
* =====================================
|
* =====================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -95,18 +93,18 @@ struct chx_stack_regs {
|
|||||||
#if defined(__ARM_ARCH_6M__)
|
#if defined(__ARM_ARCH_6M__)
|
||||||
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x00
|
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x00
|
||||||
/* ... */
|
/* ... */
|
||||||
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
|
#define CPU_EXCEPTION_PRIORITY_SYSTICK 0x40
|
||||||
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0x40
|
#define CPU_EXCEPTION_PRIORITY_INTERRUPT CPU_EXCEPTION_PRIORITY_SYSTICK
|
||||||
#define CPU_EXCEPTION_PRIORITY_PENDSV 0x80
|
#define CPU_EXCEPTION_PRIORITY_PENDSV CPU_EXCEPTION_PRIORITY_SYSTICK
|
||||||
#define CPU_EXCEPTION_PRIORITY_SVC 0x80 /* No use in this arch */
|
#define CPU_EXCEPTION_PRIORITY_SVC 0x80 /* No use in this arch */
|
||||||
#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
#elif defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||||
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
|
#define CPU_EXCEPTION_PRIORITY_SVC 0x30
|
||||||
|
|
||||||
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x40
|
#define CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED 0x40
|
||||||
/* ... */
|
/* ... */
|
||||||
#define CPU_EXCEPTION_PRIORITY_SYSTICK CPU_EXCEPTION_PRIORITY_INTERRUPT
|
#define CPU_EXCEPTION_PRIORITY_SYSTICK 0xb0
|
||||||
#define CPU_EXCEPTION_PRIORITY_INTERRUPT 0xb0
|
#define CPU_EXCEPTION_PRIORITY_INTERRUPT CPU_EXCEPTION_PRIORITY_SYSTICK
|
||||||
#define CPU_EXCEPTION_PRIORITY_PENDSV 0xc0
|
#define CPU_EXCEPTION_PRIORITY_PENDSV CPU_EXCEPTION_PRIORITY_SYSTICK
|
||||||
#else
|
#else
|
||||||
#error "no support for this arch"
|
#error "no support for this arch"
|
||||||
#endif
|
#endif
|
||||||
@@ -238,55 +236,57 @@ chx_interrupt_controller_init (void)
|
|||||||
static void
|
static void
|
||||||
chx_cpu_sched_lock (void)
|
chx_cpu_sched_lock (void)
|
||||||
{
|
{
|
||||||
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
|
||||||
{
|
|
||||||
#if defined(__ARM_ARCH_6M__)
|
#if defined(__ARM_ARCH_6M__)
|
||||||
asm volatile ("cpsid i" : : : "memory");
|
asm volatile ("cpsid i" : : : "memory");
|
||||||
#else
|
#else
|
||||||
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED;
|
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED;
|
||||||
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
|
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
chx_cpu_sched_unlock (void)
|
chx_cpu_sched_unlock (void)
|
||||||
{
|
{
|
||||||
if (running->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
|
||||||
{
|
|
||||||
#if defined(__ARM_ARCH_6M__)
|
#if defined(__ARM_ARCH_6M__)
|
||||||
asm volatile ("cpsie i" : : : "memory");
|
asm volatile ("cpsie i" : : : "memory");
|
||||||
#else
|
#else
|
||||||
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_CLEAR;
|
register uint32_t tmp = CPU_EXCEPTION_PRIORITY_CLEAR;
|
||||||
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
|
asm volatile ("msr BASEPRI, %0" : : "r" (tmp) : "memory");
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
static void
|
||||||
|
chx_request_preemption (void)
|
||||||
|
{
|
||||||
|
*ICSR = (1 << 28);
|
||||||
|
asm volatile ("" : : : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct chx_thread *
|
||||||
|
chx_timer_handler (void)
|
||||||
|
{
|
||||||
|
struct chx_thread *tp_next;
|
||||||
|
tp_next = chx_timer_expired ();
|
||||||
|
if (tp_next)
|
||||||
|
chx_request_preemption ();
|
||||||
|
return tp_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct chx_thread *
|
||||||
chx_handle_intr (void)
|
chx_handle_intr (void)
|
||||||
{
|
{
|
||||||
struct chx_pq *p;
|
|
||||||
register uint32_t irq_num;
|
register uint32_t irq_num;
|
||||||
|
struct chx_thread *tp_next;
|
||||||
|
|
||||||
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);
|
tp_next = chx_recv_irq (irq_num);
|
||||||
chx_spin_lock (&q_intr.lock);
|
if (tp_next)
|
||||||
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
|
chx_request_preemption ();
|
||||||
if (p->v == irq_num)
|
return tp_next;
|
||||||
{ /* should be one at most. */
|
|
||||||
struct chx_px *px = (struct chx_px *)p;
|
|
||||||
|
|
||||||
ll_dequeue (p);
|
|
||||||
chx_wakeup (p);
|
|
||||||
chx_request_preemption (px->master->prio);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
chx_spin_unlock (&q_intr.lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -296,16 +296,6 @@ chx_init_arch (struct chx_thread *tp)
|
|||||||
chx_set_running (tp);
|
chx_set_running (tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
chx_request_preemption (uint16_t prio)
|
|
||||||
{
|
|
||||||
if (running == NULL || (uint16_t)running->prio < prio)
|
|
||||||
{
|
|
||||||
*ICSR = (1 << 28);
|
|
||||||
asm volatile ("" : : : "memory");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* chx_sched: switch to another thread.
|
* chx_sched: switch to another thread.
|
||||||
@@ -417,15 +407,9 @@ chx_sched (uint32_t yield)
|
|||||||
"ldm r0!, {r1, r2}\n\t"
|
"ldm r0!, {r1, r2}\n\t"
|
||||||
"mov r11, r1\n\t"
|
"mov r11, r1\n\t"
|
||||||
"mov sp, r2\n\t"
|
"mov sp, r2\n\t"
|
||||||
"sub r0, #45\n\t"
|
|
||||||
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
|
|
||||||
"cmp r1, #247\n\t"
|
|
||||||
"bhi 1f\n\t" /* Leave interrupt disabled if >= 248 */
|
|
||||||
/**/
|
/**/
|
||||||
/* Unmask interrupts. */
|
/* Unmask interrupts. */
|
||||||
"cpsie i\n"
|
"cpsie i\n\t"
|
||||||
/**/
|
|
||||||
"1:\n\t"
|
|
||||||
/*
|
/*
|
||||||
0: r0
|
0: r0
|
||||||
4: r1
|
4: r1
|
||||||
@@ -520,26 +504,18 @@ chopstx_create_arch (uintptr_t stack_addr, size_t stack_size,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void __attribute__ ((naked))
|
void __attribute__ ((naked))
|
||||||
preempt (void)
|
preempt (struct chx_thread * tp_next)
|
||||||
{
|
{
|
||||||
register struct chx_thread *tp asm ("r0");
|
register struct chx_thread *tp_current asm ("r1");
|
||||||
register struct chx_thread *cur asm ("r1");
|
|
||||||
|
|
||||||
asm volatile (
|
asm ( "ldr r2, =running\n\t"
|
||||||
#if defined(__ARM_ARCH_6M__)
|
"ldr r1, [r2]"
|
||||||
"cpsid i\n\t"
|
: "=r" (tp_current)
|
||||||
#else
|
: /* no input */
|
||||||
"msr BASEPRI, r0\n\t"
|
|
||||||
#endif
|
|
||||||
"ldr r2, =running\n\t"
|
|
||||||
"ldr r0, [r2]\n\t"
|
|
||||||
"mov r1, r0"
|
|
||||||
: "=r" (tp), "=r" (cur)
|
|
||||||
: "0" (CPU_EXCEPTION_PRIORITY_INHIBIT_SCHED)
|
|
||||||
: "r2");
|
: "r2");
|
||||||
|
|
||||||
if (!cur)
|
if (!tp_current)
|
||||||
/* It's idle thread. It's ok to clobber registers. */
|
/* It's idle thread. No need to save registers. */
|
||||||
;
|
;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -553,38 +529,20 @@ preempt (void)
|
|||||||
"mov r5, r11\n\t"
|
"mov r5, r11\n\t"
|
||||||
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
|
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
|
||||||
"stm %0!, {r2, r3, r4, r5, r6}"
|
"stm %0!, {r2, r3, r4, r5, r6}"
|
||||||
: "=r" (cur)
|
: "=r" (tp_current)
|
||||||
: "0" (cur)
|
: "0" (tp_current)
|
||||||
/*
|
/*
|
||||||
* Memory clobber constraint here is not accurate, but this
|
* Memory clobber constraint here is not accurate, but this
|
||||||
* works. R7 keeps its value, but having "r7" here prevents
|
* works. R7 keeps its value, but having "r7" here prevents
|
||||||
* use of R7 before this asm statement.
|
* use of R7 before this asm statement.
|
||||||
*/
|
*/
|
||||||
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
|
||||||
|
|
||||||
if (tp)
|
tp_next = chx_running_preempted (tp_next);
|
||||||
{
|
|
||||||
if (tp->flag_sched_rr)
|
|
||||||
{
|
|
||||||
if (tp->state == THREAD_RUNNING)
|
|
||||||
{
|
|
||||||
chx_timer_dequeue (tp);
|
|
||||||
chx_ready_enqueue (tp);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* It may be THREAD_READY after chx_timer_expired.
|
|
||||||
* Then, do nothing.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
else
|
|
||||||
chx_ready_push (tp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */
|
/* Registers on stack (PSP): r0, r1, r2, r3, r12, lr, pc, xpsr */
|
||||||
|
|
||||||
tp = chx_ready_pop ();
|
|
||||||
|
|
||||||
asm volatile (
|
asm volatile (
|
||||||
".L_CONTEXT_SWITCH:\n\t"
|
".L_CONTEXT_SWITCH:\n\t"
|
||||||
/* Now, r0 points to the thread to be switched. */
|
/* Now, r0 points to the thread to be switched. */
|
||||||
@@ -617,20 +575,13 @@ preempt (void)
|
|||||||
"ldr r1, [r0], #4\n\t"
|
"ldr r1, [r0], #4\n\t"
|
||||||
"msr PSP, r1\n\t"
|
"msr PSP, r1\n\t"
|
||||||
#endif
|
#endif
|
||||||
"sub r0, #45\n\t"
|
|
||||||
"ldrb r1, [r0]\n\t" /* ->PRIO field. */
|
|
||||||
"mov r0, #0\n\t"
|
|
||||||
"cmp r1, #247\n\t"
|
|
||||||
"bhi 0f\n\t" /* Leave interrupt disabled if >= 248 */
|
|
||||||
/**/
|
|
||||||
/* Unmask interrupts. */
|
/* Unmask interrupts. */
|
||||||
#if defined(__ARM_ARCH_6M__)
|
#if defined(__ARM_ARCH_6M__)
|
||||||
"cpsie i\n"
|
"cpsie i\n\t"
|
||||||
#else
|
#else
|
||||||
"msr BASEPRI, r0\n"
|
"msr BASEPRI, r0\n\t"
|
||||||
#endif
|
#endif
|
||||||
/**/
|
/**/
|
||||||
"0:\n\t"
|
|
||||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||||
"bx r0\n"
|
"bx r0\n"
|
||||||
"1:\n\t"
|
"1:\n\t"
|
||||||
@@ -657,7 +608,7 @@ preempt (void)
|
|||||||
/**/
|
/**/
|
||||||
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
"sub r0, #3\n\t" /* EXC_RETURN to a thread with PSP */
|
||||||
"bx r0"
|
"bx r0"
|
||||||
: /* no output */ : "r" (tp) : "memory");
|
: /* no output */ : "r" (tp_next) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ chx_dmb (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void chx_preempt_into (struct chx_thread *tp_next);
|
||||||
|
|
||||||
static sigset_t ss_cur;
|
static sigset_t ss_cur;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -145,7 +147,7 @@ chx_cpu_sched_unlock (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
idle (void)
|
chx_idle (void)
|
||||||
{
|
{
|
||||||
for (;;)
|
for (;;)
|
||||||
pause ();
|
pause ();
|
||||||
@@ -154,22 +156,14 @@ idle (void)
|
|||||||
void
|
void
|
||||||
chx_handle_intr (uint32_t irq_num)
|
chx_handle_intr (uint32_t irq_num)
|
||||||
{
|
{
|
||||||
struct chx_pq *p;
|
struct chx_thread *tp_next;
|
||||||
|
|
||||||
chx_disable_intr (irq_num);
|
tp_next = chx_recv_irq (irq_num);
|
||||||
chx_spin_lock (&q_intr.lock);
|
if (!tp_next)
|
||||||
for (p = q_intr.q.next; p != (struct chx_pq *)&q_intr.q; p = p->next)
|
return;
|
||||||
if (p->v == irq_num)
|
|
||||||
{ /* should be one at most. */
|
|
||||||
struct chx_px *px = (struct chx_px *)p;
|
|
||||||
|
|
||||||
ll_dequeue (p);
|
tp_next = chx_running_preempted (tp_next);
|
||||||
chx_wakeup (p);
|
chx_preempt_into (tp_next);
|
||||||
chx_spin_unlock (&q_intr.lock);
|
|
||||||
chx_request_preemption (px->master->prio);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
chx_spin_unlock (&q_intr.lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -193,11 +187,17 @@ chx_sigmask (ucontext_t *uc)
|
|||||||
static void
|
static void
|
||||||
sigalrm_handler (int sig, siginfo_t *siginfo, void *arg)
|
sigalrm_handler (int sig, siginfo_t *siginfo, void *arg)
|
||||||
{
|
{
|
||||||
extern void chx_timer_expired (void);
|
struct chx_thread *tp_next;
|
||||||
ucontext_t *uc = arg;
|
ucontext_t *uc = arg;
|
||||||
(void)sig;
|
(void)sig;
|
||||||
(void)siginfo;
|
(void)siginfo;
|
||||||
chx_timer_expired ();
|
|
||||||
|
tp_next = chx_timer_expired ();
|
||||||
|
if (tp_next)
|
||||||
|
{
|
||||||
|
tp_next = chx_running_preempted (tp_next);
|
||||||
|
chx_preempt_into (tp_next);
|
||||||
|
}
|
||||||
chx_sigmask (uc);
|
chx_sigmask (uc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,46 +217,17 @@ chx_init_arch (struct chx_thread *tp)
|
|||||||
idle_tc.uc_stack.ss_sp = idle_stack;
|
idle_tc.uc_stack.ss_sp = idle_stack;
|
||||||
idle_tc.uc_stack.ss_size = sizeof (idle_stack);
|
idle_tc.uc_stack.ss_size = sizeof (idle_stack);
|
||||||
idle_tc.uc_link = NULL;
|
idle_tc.uc_link = NULL;
|
||||||
makecontext (&idle_tc, idle, 0);
|
makecontext (&idle_tc, chx_idle, 0);
|
||||||
|
|
||||||
getcontext (&tp->tc);
|
getcontext (&tp->tc);
|
||||||
|
|
||||||
chx_set_running (tp);
|
chx_set_running (tp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
chx_request_preemption (uint16_t prio)
|
chx_preempt_into (struct chx_thread *tp_next)
|
||||||
{
|
{
|
||||||
ucontext_t *tcp;
|
struct chx_thread *tp_prev = chx_running ();
|
||||||
struct chx_thread *tp_prev;
|
chx_set_running (tp_next);
|
||||||
struct chx_thread *tp = chx_running ();
|
|
||||||
|
|
||||||
if (tp && (uint16_t)tp->prio >= prio)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Change the context to another thread with higher priority. */
|
|
||||||
tp_prev = tp;
|
|
||||||
if (tp)
|
|
||||||
{
|
|
||||||
if (tp->flag_sched_rr)
|
|
||||||
{
|
|
||||||
if (tp->state == THREAD_RUNNING)
|
|
||||||
{
|
|
||||||
chx_timer_dequeue (tp);
|
|
||||||
chx_ready_enqueue (tp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
chx_ready_push (tp);
|
|
||||||
}
|
|
||||||
|
|
||||||
tp = chx_ready_pop ();
|
|
||||||
if (tp)
|
|
||||||
tcp = &tp->tc;
|
|
||||||
else
|
|
||||||
tcp = &idle_tc;
|
|
||||||
|
|
||||||
chx_set_running (tp);
|
|
||||||
if (tp_prev)
|
if (tp_prev)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@@ -275,11 +246,11 @@ chx_request_preemption (uint16_t prio)
|
|||||||
* of the thread, and the condition of chx_sched function which
|
* of the thread, and the condition of chx_sched function which
|
||||||
* mandates holding cpu_sched_lock.
|
* mandates holding cpu_sched_lock.
|
||||||
*/
|
*/
|
||||||
swapcontext (&tp_prev->tc, tcp);
|
swapcontext (&tp_prev->tc, &tp_next->tc);
|
||||||
}
|
}
|
||||||
else if (tp)
|
else
|
||||||
{
|
{
|
||||||
setcontext (tcp);
|
setcontext (&tp_next->tc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
83
chopstx.c
83
chopstx.c
@@ -101,9 +101,8 @@ static struct chx_queue q_join;
|
|||||||
static struct chx_queue q_intr;
|
static struct chx_queue q_intr;
|
||||||
|
|
||||||
/* Forward declaration(s). */
|
/* Forward declaration(s). */
|
||||||
static void chx_request_preemption (uint16_t prio);
|
|
||||||
static int chx_wakeup (struct chx_pq *p);
|
static int chx_wakeup (struct chx_pq *p);
|
||||||
static struct chx_thread * chx_timer_insert (struct chx_thread *tp, uint32_t usec);
|
static struct chx_thread *chx_timer_insert (struct chx_thread *tp, uint32_t usec);
|
||||||
static uint32_t chx_timer_dequeue (struct chx_thread *tp);
|
static uint32_t chx_timer_dequeue (struct chx_thread *tp);
|
||||||
|
|
||||||
|
|
||||||
@@ -297,6 +296,10 @@ chx_ready_enqueue (struct chx_thread *tp)
|
|||||||
chx_spin_unlock (&q_ready.lock);
|
chx_spin_unlock (&q_ready.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct chx_thread *chx_timer_expired (void);
|
||||||
|
static struct chx_thread *chx_recv_irq (uint32_t irq_num);
|
||||||
|
static struct chx_thread *chx_running_preempted (struct chx_thread *tp_next);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here comes architecture specific code.
|
* Here comes architecture specific code.
|
||||||
*/
|
*/
|
||||||
@@ -384,7 +387,7 @@ chx_timer_dequeue (struct chx_thread *tp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
static struct chx_thread *
|
||||||
chx_timer_expired (void)
|
chx_timer_expired (void)
|
||||||
{
|
{
|
||||||
struct chx_thread *tp;
|
struct chx_thread *tp;
|
||||||
@@ -430,7 +433,74 @@ chx_timer_expired (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
chx_spin_unlock (&q_timer.lock);
|
chx_spin_unlock (&q_timer.lock);
|
||||||
chx_request_preemption (prio);
|
|
||||||
|
if (running == NULL || (uint16_t)running->prio < prio)
|
||||||
|
{
|
||||||
|
tp = chx_ready_pop ();
|
||||||
|
if (tp != running)
|
||||||
|
return tp;
|
||||||
|
else
|
||||||
|
/* When tp->flag_sched_rr == 1, it's possible. No context switch. */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct chx_thread *
|
||||||
|
chx_recv_irq (uint32_t irq_num)
|
||||||
|
{
|
||||||
|
struct chx_pq *p;
|
||||||
|
struct chx_thread *r = chx_running ();
|
||||||
|
|
||||||
|
chx_disable_intr (irq_num);
|
||||||
|
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. */
|
||||||
|
break;
|
||||||
|
chx_spin_unlock (&q_intr.lock);
|
||||||
|
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
struct chx_px *px = (struct chx_px *)p;
|
||||||
|
|
||||||
|
ll_dequeue (p);
|
||||||
|
chx_wakeup (p);
|
||||||
|
|
||||||
|
if (r == NULL || (uint16_t)r->prio < px->master->prio)
|
||||||
|
return chx_ready_pop ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct chx_thread * __attribute__ ((noinline))
|
||||||
|
chx_running_preempted (struct chx_thread *tp_next)
|
||||||
|
{
|
||||||
|
struct chx_thread *r = chx_running ();
|
||||||
|
|
||||||
|
if (r == NULL)
|
||||||
|
return tp_next;
|
||||||
|
|
||||||
|
if (r->flag_sched_rr)
|
||||||
|
{
|
||||||
|
if (r->state == THREAD_RUNNING)
|
||||||
|
{
|
||||||
|
chx_timer_dequeue (r);
|
||||||
|
chx_ready_enqueue (r);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* It may be THREAD_READY after chx_timer_expired.
|
||||||
|
* Then, do nothing. It's in the ready queue.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
else
|
||||||
|
chx_ready_push (r);
|
||||||
|
|
||||||
|
return tp_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -482,9 +552,6 @@ chx_init (struct chx_thread *tp)
|
|||||||
tp->parent = NULL;
|
tp->parent = NULL;
|
||||||
tp->v = 0;
|
tp->v = 0;
|
||||||
|
|
||||||
if (CHX_PRIO_MAIN_INIT >= CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
|
||||||
chx_cpu_sched_lock ();
|
|
||||||
|
|
||||||
tp->prio = CHX_PRIO_MAIN_INIT;
|
tp->prio = CHX_PRIO_MAIN_INIT;
|
||||||
|
|
||||||
chopstx_main = (chopstx_t)tp;
|
chopstx_main = (chopstx_t)tp;
|
||||||
@@ -1544,7 +1611,7 @@ chopstx_setpriority (chopstx_prio_t prio_new)
|
|||||||
|
|
||||||
if (tp->prio < prio_cur)
|
if (tp->prio < prio_cur)
|
||||||
chx_sched (CHX_YIELD);
|
chx_sched (CHX_YIELD);
|
||||||
else if (tp->prio < CHOPSTX_PRIO_INHIBIT_PREEMPTION)
|
else
|
||||||
chx_cpu_sched_unlock ();
|
chx_cpu_sched_unlock ();
|
||||||
|
|
||||||
return prio_orig;
|
return prio_orig;
|
||||||
|
|||||||
@@ -45,8 +45,6 @@ chopstx_create (uint32_t flags_and_prio,
|
|||||||
#define CHOPSTX_DETACHED 0x10000
|
#define CHOPSTX_DETACHED 0x10000
|
||||||
#define CHOPSTX_SCHED_RR 0x20000
|
#define CHOPSTX_SCHED_RR 0x20000
|
||||||
|
|
||||||
#define CHOPSTX_PRIO_INHIBIT_PREEMPTION 248
|
|
||||||
|
|
||||||
void chopstx_usec_wait (uint32_t usec);
|
void chopstx_usec_wait (uint32_t usec);
|
||||||
|
|
||||||
struct chx_spinlock {
|
struct chx_spinlock {
|
||||||
|
|||||||
20
entry.c
20
entry.c
@@ -64,8 +64,24 @@ extern uint8_t __main_stack_end__;
|
|||||||
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
|
||||||
extern void svc (void);
|
extern void svc (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In ARMv6-M Architecture Reference Manual and ARM v7-M Architecture
|
||||||
|
* Reference Manual, you can find a section B1.5.12 for tail-chaining.
|
||||||
|
*
|
||||||
|
* B1.5.12 Exceptions on exception return, and tail-chaining exceptions
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Because it is tail-chained, the preempt function has an argument
|
||||||
|
* with type of (struct chx_thread *), in fact.
|
||||||
|
*/
|
||||||
extern void preempt (void);
|
extern void preempt (void);
|
||||||
extern void chx_timer_expired (void);
|
|
||||||
|
/*
|
||||||
|
* Following functions return type of (struct chx_thread *) for
|
||||||
|
* tail-chained function (the preempt function), for its argument.
|
||||||
|
*/
|
||||||
|
extern void chx_timer_handler (void);
|
||||||
extern void chx_handle_intr (void);
|
extern void chx_handle_intr (void);
|
||||||
|
|
||||||
static void nmi (void)
|
static void nmi (void)
|
||||||
@@ -193,7 +209,7 @@ handler vector_table[] __attribute__ ((section(".startup.vectors"))) = {
|
|||||||
none, /* Debug */
|
none, /* Debug */
|
||||||
none, /* reserved */
|
none, /* reserved */
|
||||||
preempt, /* PendSV */
|
preempt, /* PendSV */
|
||||||
chx_timer_expired, /* SysTick */
|
chx_timer_handler, /* SysTick */
|
||||||
/* 0x40 */
|
/* 0x40 */
|
||||||
chx_handle_intr /* WWDG */, chx_handle_intr /* PVD */,
|
chx_handle_intr /* WWDG */, chx_handle_intr /* PVD */,
|
||||||
chx_handle_intr /* TAMPER */, chx_handle_intr /* RTC */,
|
chx_handle_intr /* TAMPER */, chx_handle_intr /* RTC */,
|
||||||
|
|||||||
Reference in New Issue
Block a user