Common chx_sched and arch specific voluntary_context_switch.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
NIIBE Yutaka
2019-11-21 12:37:02 +09:00
parent bbb952429a
commit 86c21fbf5c
4 changed files with 84 additions and 108 deletions

View File

@@ -1,3 +1,11 @@
2019-11-21 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.c (chx_sched): New common function.
* chopstx-cortex-m.c (svc): Simply context switch.
(voluntary_context_switch): New, replacing chx_sched.
* chopstx-gnu-linux.c (voluntary_context_switch): Likewise.
2019-11-21 NIIBE Yutaka <gniibe@fsij.org>
* chopstx.h (CHOPSTX_PRIO_INHIBIT_PREEMPTION): Remove.

View File

@@ -297,36 +297,19 @@ chx_init_arch (struct chx_thread *tp)
}
/*
* chx_sched: switch to another thread.
*
* There are two cases:
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* YIELD=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*
* For Cortex-M0, this should be AAPCS-compliant function entry, so we
* put "noinline" attribute.
*
* AAPCS: ARM Architecture Procedure Call Standard
*
* Returns:
* >= 1 on wakeup by others, value means ticks remained for sleep.
* 0 on normal wakeup (timer expiration, lock acquirement).
* -1 on cancellation.
*/
static uintptr_t __attribute__ ((naked, noinline))
chx_sched (uint32_t yield)
static uintptr_t
voluntary_context_switch (struct chx_thread *tp_next)
{
register struct chx_thread *tp asm ("r0");
register uintptr_t result asm ("r0");
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
asm volatile (
"svc #0"
: "=r" (tp) : "0" (yield): "memory");
"svc #0\n\t"
"add r1, r0, #16\n\t"
"ldr r0, [r1]" /* Get tp->v */
: "=r" (result) : "0" (tp_next): "memory");
#else
register uint32_t arg_yield asm ("r1");
register struct chx_thread *tp asm ("r1");
/* Build stack data as if it were an exception entry. */
/*
@@ -339,46 +322,36 @@ chx_sched (uint32_t yield)
* pc: return address (= .L_CONTEXT_SWITCH_FINISH)
* psr: INITIAL_XPSR scratch
*/
asm ("mov r1, lr\n\t"
asm ("mov %0, lr\n\t"
"ldr r2, =.L_CONTEXT_SWITCH_FINISH\n\t"
"mov r3, #128\n\t"
"lsl r3, #17\n\t"
"push {r1, r2, r3}\n\t"
"mov r1, #0\n\t"
"mov r2, r1\n\t"
"mov r3, r1\n\t"
"push {r1, r2, r3}\n\t"
"mov r1, r0\n\t"
"push {%0, r2, r3}\n\t"
"mov %0, #0\n\t"
"mov r2, %0\n\t"
"mov r3, %0\n\t"
"push {%0, r2, r3}\n\t"
"ldr r2, =running\n\t"
"ldr r0, [r2]\n\t"
"push {r0, r3}"
: "=r" (tp), "=r" (arg_yield)
: "0" (yield)
"ldr %0, [r2]"
"push {%0, r3}\n\t"
: "=r" (tp)
: /* no input */
: "r2", "r3", "memory");
/* Save registers onto CHX_THREAD struct. */
asm ("add r0, #20\n\t"
"stm r0!, {r4, r5, r6, r7}\n\t"
asm ("add r1, #20\n\t"
"stm r1!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
"mov r3, r9\n\t"
"mov r4, r10\n\t"
"mov r5, r11\n\t"
"mov r6, sp\n\t"
"stm r0!, {r2, r3, r4, r5, r6}\n\t"
"sub r0, #56"
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
"sub r1, #56"
: /* no output */
: "r" (tp)
: "r2", "r3", "r4", "r5", "r6", "r7", "memory");
if (arg_yield)
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
tp = chx_ready_pop ();
asm volatile (/* Now, r0 points to the thread to be switched. */
/* Put it to *running. */
"ldr r1, =running\n\t"
@@ -453,17 +426,14 @@ chx_sched (uint32_t yield)
"pop {r0, r1, r2, r3}\n\t"
"add sp, #12\n\t"
"pop {pc}\n\t"
".L_CONTEXT_SWITCH_FINISH:"
: "=r" (tp) /* Return value in R0 */
: "0" (tp)
".L_CONTEXT_SWITCH_FINISH:\n\t"
"add r1, r0, #16\n\t"
"ldr r0, [r1]" /* Get tp->v */
: "=r" (result) /* Return value in R0 */
: "0" (tp_next)
: "memory");
#endif
asm volatile ("bx lr"
: "=r" (tp)
: "0" (tp->v)
: "memory");
return (uintptr_t)tp;
return (uintptr_t)result;
}
extern void cause_link_time_error_unexpected_size_of_struct_chx_thread (void);
@@ -615,21 +585,15 @@ preempt (struct chx_thread * tp_next)
#if defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__)
/*
* System call: switch to another thread.
* There are two cases:
* ORIG_R0=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* ORIG_R0=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*/
void __attribute__ ((naked))
svc (void)
{
register struct chx_thread *tp asm ("r0");
register uint32_t orig_r0 asm ("r1");
register uint32_t tp_next asm ("r0");
asm ("ldr r1, =running\n\t"
"ldr r0, [r1]\n\t"
"add r1, r0, #20\n\t"
"ldr r1, [r1]\n\t"
"add r1, #20\n\t"
/* Save registers onto CHX_THREAD struct. */
"stm r1!, {r4, r5, r6, r7}\n\t"
"mov r2, r8\n\t"
@@ -638,23 +602,15 @@ svc (void)
"mov r5, r11\n\t"
"mrs r6, PSP\n\t" /* r13(=SP) in user space. */
"stm r1!, {r2, r3, r4, r5, r6}\n\t"
"ldr r1, [r6]\n\t"
"str r0, [r6]"
: "=r" (tp), "=r" (orig_r0)
"ldr r0, [r6]\n\t"
"sub r1, #56\n\t"
"str r1, [r6]"
: "=r" (tp_next)
: /* no input */
: "r2", "r3", "r4", "r5", "r6", "memory");
if (orig_r0) /* yield */
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
tp = chx_ready_pop ();
: "r1", "r2", "r3", "r4", "r5", "r6", "memory");
asm volatile (
"b .L_CONTEXT_SWITCH"
: /* no output */ : "r" (tp) : "memory");
: /* no output */ : "r" (tp_next) : "memory");
}
#endif

View File

@@ -254,41 +254,20 @@ chx_preempt_into (struct chx_thread *tp_next)
}
}
/*
* chx_sched: switch to another thread.
*
* There are two cases:
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* YIELD=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*
* Returns:
* 1 on wakeup by others.
* 0 on normal wakeup.
* -1 on cancellation.
*/
static uintptr_t
chx_sched (uint32_t yield)
voluntary_context_switch (struct chx_thread *tp_next)
{
struct chx_thread *tp, *tp_prev;
ucontext_t *tcp;
tp = tp_prev = chx_running ();
if (yield)
{
if (tp->flag_sched_rr)
chx_timer_dequeue (tp);
chx_ready_enqueue (tp);
}
tp = chx_ready_pop ();
if (tp)
tcp = &tp->tc;
tp_prev = chx_running ();
if (tp_next)
tcp = &tp_next->tc;
else
tcp = &idle_tc;
chx_set_running (tp);
chx_set_running (tp_next);
swapcontext (&tp_prev->tc, tcp);
chx_cpu_sched_unlock ();

View File

@@ -504,6 +504,39 @@ chx_running_preempted (struct chx_thread *tp_next)
}
/*
* chx_sched: switch to another thread.
*
* There are two cases:
* YIELD=0 (SLEEP): Current RUNNING thread is already connected to
* something (mutex, cond, intr, etc.)
* YIELD=1 (YIELD): Current RUNNING thread is active,
* it is needed to be enqueued to READY queue.
*
* Returns:
* >= 1 on wakeup by others, value means ticks remained for sleep.
* 0 on normal wakeup (timer expiration, lock acquirement).
* -1 on cancellation.
*/
static uintptr_t __attribute__ ((noinline))
chx_sched (uint32_t yield)
{
struct chx_thread *tp;
if (yield)
{
struct chx_thread *r = chx_running ();
if (r->flag_sched_rr)
chx_timer_dequeue (r);
chx_ready_enqueue (r);
}
tp = chx_ready_pop ();
return voluntary_context_switch (tp);
}
void
chx_systick_init (void)
{