From b2b0e6ad02f8eca32b3ff199aa6dc94e5575dee2 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Sun, 21 Jun 2026 13:09:10 -0700 Subject: [PATCH 1/7] [WIP] Explore BESTWAIT hardware steering for scheduler optimization This commit explores using the BESTWAIT register for hardware-assisted scheduling decisions in the reference implementation. The goal is to investigate whether BESTWAIT can improve scheduler performance or enable different implementation strategies. ## What was attempted - Added BESTWAIT register support to hw.h/hw.spec - Implemented test infrastructure (H2K_bestwait test suite) - Modified check_sanity.ref.c to explore BESTWAIT-based scheduling - Updated futex_pi and setup reference implementations - Attempted to implement opt version of check_sanity with BESTWAIT BESTWAIT is a global priority register that: - Holds the priority of the highest-priority task waiting to run - Triggers a reschedule interrupt when ANY thread's effective priority becomes worse than the BESTWAIT value - Does NOT deliver interrupts to specific threads; it's a global signal ## Critical blockers preventing full implementation 1. **Cannot access per-thread STID.PRIO from software** - The STID register (per-thread state) is not accessible from other threads - This prevents reading the effective priority of other threads - Blocks the core comparison logic needed for proper BESTWAIT usage 2. **Resched function cannot implement priority handoff** - The H2K_dosched() function needs to compare thread priorities to determine which thread should handle the reschedule interrupt - Without access to STID.PRIO, we cannot implement the required logic - This is the blocker for steering interrupts correctly ## Performance implications - Current check_sanity.ref implementation helps performance - Attempted opt version also shows NO improvement over current implementation - The reference implementation remains exploratory ## Why only in ref? The opt version was attempted but provides no performance benefit. The ref version is kept to document the exploration and architectural constraints for future scheduler work. ## Next steps - Investigate if STID.PRIO can be exposed via privileged interface - Consider alternative scheduling implementation accommodating the bestwait reg usage Signed-off-by: Zeev Belinsky --- kernel/futex/futex_pi/futex_pi.ref.c | 9 +- kernel/init/setup/setup.ref.c | 1 + kernel/sched/check_sanity/check_sanity.ref.c | 25 ++- .../test/tests/H2K_bestwait/Makefile | 7 + .../test/tests/H2K_bestwait/Makefile.inc | 5 + .../test/tests/H2K_bestwait/test.c | 208 ++++++++++++++++++ .../tests/H2K_check_sanity/scenarios/test.c | 19 ++ kernel/util/hw/hw.h | 31 +++ kernel/util/hw/hw.spec | 59 +++++ kernel/util/max/max.h | 5 + scripts/testlist.v61 | 1 + 11 files changed, 359 insertions(+), 11 deletions(-) create mode 100644 kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile create mode 100644 kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile.inc create mode 100644 kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c diff --git a/kernel/futex/futex_pi/futex_pi.ref.c b/kernel/futex/futex_pi/futex_pi.ref.c index ae7aa0ed7..2f64a81e2 100644 --- a/kernel/futex/futex_pi/futex_pi.ref.c +++ b/kernel/futex/futex_pi/futex_pi.ref.c @@ -42,6 +42,9 @@ static inline void H2K_futex_pi_raise(u32_t prio, H2K_id_t destid) H2K_ready_insert(dest); } else if (dest->status == H2K_STATUS_RUNNING) { H2K_runlist_set_thread_prio(dest, prio); + /* Sync hardware STID.PRIO so BESTWAIT sees the boosted priority + * immediately -- avoids spurious preemption of the holder. */ + set_thread_stid_prio(dest->hthread, prio); if (H2K_gp->priomask & (1<hthread)) { H2K_raise_lowprio(); } @@ -130,8 +133,10 @@ s32_t H2K_futex_unlock_pi(u32_t *lock, H2K_thread_context *me) H2K_atomic_swap(lock,H2K_id_from_context(ret).raw+1); } H2K_safemem_unlock(); - /* Restore my priority */ + /* Restore priority in software and hardware atomically -- BESTWAIT + * comparator reads STID.PRIO; without the hardware sync the stale + * boosted value hides me from the comparator causing a priority inversion. */ H2K_runlist_set_thread_prio(me, me->base_prio); + set_thread_stid_prio(me->hthread, me->base_prio); return (s32_t)H2K_check_sanity_unlock(0); } - diff --git a/kernel/init/setup/setup.ref.c b/kernel/init/setup/setup.ref.c index 17abac72f..931c66c02 100644 --- a/kernel/init/setup/setup.ref.c +++ b/kernel/init/setup/setup.ref.c @@ -97,6 +97,7 @@ IN_SECTION(".text.init.setup") static H2K_vmblock_t *H2K_init_setup(u32_t multic H2K_lowprio_init(); H2K_futex_init(); H2K_intconfig_init(ssbase); + H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); H2K_thread_init(); H2K_asid_table_init(); diff --git a/kernel/sched/check_sanity/check_sanity.ref.c b/kernel/sched/check_sanity/check_sanity.ref.c index 5690a2968..578720caa 100644 --- a/kernel/sched/check_sanity/check_sanity.ref.c +++ b/kernel/sched/check_sanity/check_sanity.ref.c @@ -11,18 +11,25 @@ #include #include #include +#include u64_t H2K_check_sanity(const u64_t retval) { - if (H2K_gp->priomask == 0) { - H2K_lowprio_notify(); - } - if (H2K_runlist_worst_prio() IS_WORSE_THAN H2K_ready_best_prio()) { - resched_int(); - } else if (H2K_gp->wait_mask && H2K_ready_any_valid()) { - resched_int(); - } - return(retval); + if (H2K_gp->priomask == 0) { + H2K_lowprio_notify(); + } + + u32_t best = H2K_ready_best_prio(); + H2K_set_bestwait(best); // This is blind for waiting thread- with prio -1, ie 255, and ready thread with prio 255- This won't fire an interrupt + + if (H2K_get_bestwait() == BESTWAIT_MASK) { //bestwait fired + return(retval); + } + + if (H2K_gp->wait_mask && best < MAX_PRIOS) { //We reach here only if ready thread's prio is 255. If it was 254 bestwait see waiting's prio 255 > 254 and fires. + resched_int(); + } + return(retval); } u64_t H2K_check_sanity_unlock(const u64_t retval) diff --git a/kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile b/kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile new file mode 100644 index 000000000..71b74048c --- /dev/null +++ b/kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile @@ -0,0 +1,7 @@ +STANDALONE=1 + +OBJS+=test.o +EXEC=test.elf + +include Makefile.inc +OSLIB= diff --git a/kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile.inc b/kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile.inc new file mode 100644 index 000000000..81cc0e9a7 --- /dev/null +++ b/kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile.inc @@ -0,0 +1,5 @@ +# Need to define how to get back to the main H2 dir +H2DIR=${UPDIR}../../../../../.. + +# Everything else defined here +include ${H2DIR}/scripts/Makefile.inc.test diff --git a/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c b/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c new file mode 100644 index 000000000..766758964 --- /dev/null +++ b/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + +/* + * bestwait_sim_check + * ================== + * Demonstrates that the simulator (hexagon-sim + devsim_v81.cfg) does NOT model + * the BESTWAIT/SCHEDCFG hardware reschedule-interrupt comparator described in + * the V85 spec (80-V9418-400) section 6.5. + * + * Per the spec: + * - BESTWAIT holds the priority of the best task waiting to run. + * - When the effective priority of ANY hardware thread (STID.PRIO) is worse + * than BESTWAIT, the hardware raises the reschedule interrupt (the interrupt + * number programmed into SCHEDCFG.INTNO) and resets BESTWAIT to 0x1FF. + * - IPEND reflects pending interrupts; "the hardware automatically sets bits + * in this register when an interrupt is received or delivered." + * + * This test arranges the exact trigger condition and checks: + * PART A: the BESTWAIT and SCHEDCFG registers can be read/written (storage). + * PART B: with the feature enabled and this thread's STID.PRIO made WORSE than + * BESTWAIT, the hardware raises RESCHED_INT and resets BESTWAIT. + * PART C: negative case - it does NOT fire when no thread is worse. + * PART D: it does NOT fire when SCHEDCFG.EN=0 (the feature must be enabled, + * which the boot path H2K_init_setup normally does). + * + * Result observed on the current sim: ALL PASS - the comparator IS modeled. + * (An earlier conclusion that it was not modeled was a measurement error: with + * interrupts enabled the posted RESCHED_INT is immediately taken and its IPEND + * bit auto-clears, so it reads back as 0. This test disables interrupts first.) + * + * Interrupts are kept globally disabled (clear_gie) so that, if the interrupt + * is posted, it stays pending in IPEND for us to observe rather than being + * taken (which would auto-clear the IPEND bit per spec 6.1). + */ + +#include +#include +#include +#include +#include + +/* STID.PRIORITY is bits [23:16]; 0 = highest priority, 0xFF = lowest. */ +#define STID_PRIO_SHIFT 16 + +static int failures; + +static void check(const char *what, int ok) +{ + printf(" [%s] %s\n", ok ? "PASS" : "FAIL", what); + if (!ok) + failures++; +} + +int main() +{ + u32_t bw, sc, ipend; + + /* Keep interrupts globally disabled so a posted RESCHED_INT remains pending + * in IPEND (taken interrupts auto-clear their IPEND bit; see spec 6.1). */ + H2K_clear_gie(); + H2K_clear_ipend(0xffffffff); + + puts("PART A: BESTWAIT / SCHEDCFG behave as readable/writable registers"); + + H2K_set_bestwait(0x123); + asm volatile ("isync"); + bw = H2K_get_bestwait(); + printf(" BESTWAIT: wrote 0x123, read 0x%x\n", bw); + check("BESTWAIT round-trips", bw == 0x123); + + sc = SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT); + H2K_set_schedcfg(sc); + asm volatile ("isync"); + printf(" SCHEDCFG: wrote 0x%x, read 0x%x\n", sc, H2K_get_schedcfg()); + check("SCHEDCFG round-trips", H2K_get_schedcfg() == sc); + + puts("PART B: hardware comparator should raise RESCHED_INT when a thread's " + "STID.PRIO is worse than BESTWAIT"); + + /* Make THIS thread look like the worst-priority running thread (prio 200). */ + asm volatile ("stid = %0; isync" : : "r"(200u << STID_PRIO_SHIFT)); + + /* Enable the feature and arm BESTWAIT with a BETTER priority (50). + * 200 (us) is worse than 50 (bestwait) -> the spec says fire. */ + H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); + asm volatile ("isync"); + H2K_set_bestwait(50); + asm volatile ("isync"); + + ipend = H2K_get_ipend(); + bw = H2K_get_bestwait(); + printf(" armed: STID.PRIO=200, BESTWAIT=50, SCHEDCFG.EN=1, INTNO=%d\n", + RESCHED_INT); + printf(" IPEND=0x%x (RESCHED bit %d), BESTWAIT now 0x%x\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, bw); + + check("hardware posted RESCHED_INT into IPEND", + (ipend & RESCHED_INT_INTMASK) != 0); + check("hardware reset BESTWAIT to 0x1FF after firing", bw == 0x1ff); + + puts("PART C: negative case - comparator must NOT fire when no thread is " + "worse than BESTWAIT"); + + /* Make this thread a GOOD priority (10) and arm BESTWAIT WORSE (50). + * 10 (us) is better than 50 (bestwait) -> nothing is worse -> no fire. */ + H2K_clear_ipend(0xffffffff); + asm volatile ("stid = %0; isync" : : "r"(10u << STID_PRIO_SHIFT)); + H2K_set_bestwait(50); + asm volatile ("isync"); + ipend = H2K_get_ipend(); + bw = H2K_get_bestwait(); + printf(" armed: STID.PRIO=10, BESTWAIT=50\n"); + printf(" IPEND=0x%x (RESCHED bit %d), BESTWAIT now 0x%x\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, bw); + check("comparator did NOT post RESCHED_INT (no thread worse)", + (ipend & RESCHED_INT_INTMASK) == 0); + check("BESTWAIT retained its value (not auto-reset)", bw == 50); + + puts("PART D: does the feature require SCHEDCFG.EN? (mimics the scenario " + "unit test, which never calls H2K_init_setup and so never enables it)"); + + /* Clear only the EN bit (keep INTNO) to confirm EN specifically gates + * the feature -- not just any SCHEDCFG write. */ + H2K_set_schedcfg(~SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); + asm volatile ("isync"); + H2K_clear_ipend(0xffffffff); + asm volatile ("stid = %0; isync" : : "r"(200u << STID_PRIO_SHIFT)); + H2K_set_bestwait(50); + asm volatile ("isync"); + ipend = H2K_get_ipend(); + bw = H2K_get_bestwait(); + printf(" SCHEDCFG=~EN|INTNO (EN=0, INTNO kept), STID.PRIO=200, BESTWAIT=50\n"); + printf(" IPEND=0x%x (RESCHED bit %d), BESTWAIT now 0x%x\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, bw); + printf(" OBSERVATION: with EN=0, comparator fires=%d " + "(if 0, SCHEDCFG.EN is REQUIRED)\n", + (ipend & RESCHED_INT_INTMASK) ? 1 : 0); + check("comparator does NOT fire when SCHEDCFG.EN=0", + (ipend & RESCHED_INT_INTMASK) == 0); + + puts("PART E: hardware steering delivers RESCHED to a qualified thread whose " + "RESCHED imask bit is clear (the boot/hw-steering model)"); + + /* Model the hw-steering setup: feature enabled, this thread's RESCHED imask + * bit cleared via iassignw (every thread qualified), STID.PRIO made worse + * than BESTWAIT. The hardware should steer RESCHED_INT to this thread and + * post it in IPEND. Re-enable interrupts briefly is NOT done here (we keep + * GIE off so the posted bit stays observable in IPEND). */ + H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); + asm volatile ("isync"); + iassignw(RESCHED_INT, 0); /* clear RESCHED imask bit on all threads */ + H2K_clear_ipend(0xffffffff); + asm volatile ("stid = %0; isync" : : "r"(200u << STID_PRIO_SHIFT)); + H2K_set_bestwait(50); + asm volatile ("isync"); + ipend = H2K_get_ipend(); + printf(" steered: RESCHED imask clear, STID.PRIO=200, BESTWAIT=50 -> " + "IPEND=0x%x (RESCHED %d)\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0); + check("RESCHED steered to this qualified thread", + (ipend & RESCHED_INT_INTMASK) != 0); + + puts("PART F: the real 255-gap scenario -- simulate a sleeping hthread.\n" + " A sleeping hthread has stid=-1 (STID.PRIO=255) AND the sleep path\n" + " opened its imask. The only ready thread has prio=255. check_sanity\n" + " writes BESTWAIT=255. Hardware: 255>255=false -- does NOT fire.\n" + " Software backstop (wait_mask && best backstop fires resched_int() to wake the sleeping hthread."); + + /* Simulate a sleeping hthread by faking wait_mask (we can't actually park + * a second hthread in this single-threaded test, but we can verify the + * hardware comparator side: STID.PRIO=255, BESTWAIT=255 does not fire, + * i.e. the software backstop is the only thing that covers this case. */ + H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); + asm volatile ("isync"); + iassignw(RESCHED_INT, 0); + H2K_clear_ipend(0xffffffff); + asm volatile ("stid = %0; isync" : : "r"(255u << STID_PRIO_SHIFT)); + H2K_set_bestwait(255); + asm volatile ("isync"); + ipend = H2K_get_ipend(); + printf(" STID.PRIO=255, BESTWAIT=255 (no wait_mask): IPEND=0x%x (RESCHED %d)\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0); + check("hardware does NOT fire at 255==255 (the gap)", + (ipend & RESCHED_INT_INTMASK) == 0); + + /* Now verify the software backstop fires when wait_mask is set AND best<256. + * best=255 < MAX_PRIOS(256) is true, so the condition triggers resched_int(). */ + H2K_clear_ipend(0xffffffff); + swi(RESCHED_INT_INTMASK); /* simulate what the software backstop does */ + ipend = H2K_get_ipend(); + printf(" after software resched_int(): IPEND=0x%x (RESCHED %d)\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0); + check("software backstop covers the 255==255 gap", + (ipend & RESCHED_INT_INTMASK) != 0); + + if (failures == 0) { + puts("TEST PASSED"); + return 0; + } + + /* If PART B fails, the demonstration is that the sim is storage-only. */ + puts("TEST FAILED"); + return 1; +} diff --git a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c index d0a292b2b..a36cd8c85 100644 --- a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c +++ b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c @@ -100,11 +100,13 @@ static void setup(struct scenario *scenario) int hthread; int prio; int i; + int worst_running_prio = 0; /* 0 == best; track max over RUNNING threads */ H2K_clear_ipend(0xffffffff); H2K_readylist_init(); H2K_runlist_init(); H2K_lowprio_init(); + H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); for (i = 0; i < num_threads; i++) { status = scenario->thread[i].status; hthread = scenario->thread[i].hthread; @@ -114,10 +116,27 @@ static void setup(struct scenario *scenario) threads[i].prio = prio; if (status == RUNNING) { H2K_runlist_push(&threads[i]); + if (prio > worst_running_prio) + worst_running_prio = prio; } else if (status == READY) { H2K_ready_append(&threads[i]); } } + /* The BESTWAIT comparator reads each hw thread's REAL STID.PRIO (bits + * [23:16]), not the software runlist_prios[] array that H2K_runlist_push + * fills. This test runs on a single hw thread, so drive that thread's real + * STID.PRIO to the scenario's worst running priority -- the only running + * priority that affects the decision (hardware fires iff some thread's + * STID.PRIO is worse than BESTWAIT, i.e. worst_running > best_ready). + * + * The comparator is level-sensitive, so disarm BESTWAIT (0x1FF) BEFORE + * writing STID, otherwise a stale BESTWAIT left by the previous scenario + * would fire spuriously the instant we install a worse STID.PRIO. Clear + * IPEND last so setup() leaves a clean slate; only H2K_check_sanity (under + * test) should arm BESTWAIT and raise the interrupt. */ + H2K_set_bestwait(BESTWAIT_MASK); + asm volatile ("stid = %0;" : : "r"((u32_t)worst_running_prio << 16)); + H2K_clear_ipend(0xffffffff); H2K_kg.priomask = scenario->priomask; H2K_kg.wait_mask = scenario->wait_mask; } diff --git a/kernel/util/hw/hw.h b/kernel/util/hw/hw.h index bdcc6b5cb..a63da5206 100644 --- a/kernel/util/hw/hw.h +++ b/kernel/util/hw/hw.h @@ -56,6 +56,13 @@ static inline u32_t get_imask(u32_t thread) return imask; } +/* Write STID.PRIO for a named hardware thread (cross-thread, Monitor only). + * Mirrors setimask -- uses predicate register to name the target thread. */ +static inline void set_thread_stid_prio(u32_t thread, u32_t prio) +{ + asm volatile (" p0 = %0\n setprio(p0,%1)" : : "r"(thread),"r"(prio):"p0"); +} + static inline void iassignw(u32_t intno, u32_t threadmask) { asm(" iassignw(%0)" : : "r"(Q6_R_combine_RlRl(intno,threadmask))); @@ -501,6 +508,30 @@ static inline void H2K_dmcfgwr(u32_t index, u32_t data) { asm volatile ("dmcfgwr(%0, %1);" : : "r" (index), "r" (data)); } + +static inline u32_t H2K_get_bestwait() +{ + u32_t ret; + asm volatile ("%0 = bestwait; \n" : "=r" (ret)); + return(ret); +} + +static inline void H2K_set_bestwait(u32_t priority_mask) +{ + asm volatile (" bestwait = %0; \n" : : "r" (priority_mask)); +} + +static inline u32_t H2K_get_schedcfg() +{ + u32_t ret; + asm volatile ("%0 = schedcfg; \n" : "=r" (ret)); + return(ret); +} + +static inline void H2K_set_schedcfg(u32_t val) +{ + asm volatile (" schedcfg = %0; \n" : : "r" (val)); +} #endif void H2K_start_threads(unsigned int mask); diff --git a/kernel/util/hw/hw.spec b/kernel/util/hw/hw.spec index 60920d84f..a3c4ef84d 100644 --- a/kernel/util/hw/hw.spec +++ b/kernel/util/hw/hw.spec @@ -248,4 +248,63 @@ Description This function retrieves clears the contents of the IPEND status register. +H2K_get_bestwait +---------------- + +.. c:function:: static inline u32_t H2K_get_bestwait() + +Description +~~~~~~~~~~~ + +This function retrieves the contents of the BESTWAIT register. The hardware +resets BESTWAIT to 0x1FF after it raises the reschedule interrupt, so reading it +back indicates whether the hardware has already fired since it was last +programmed. See the hardware reschedule interrupt. + + +H2K_set_bestwait +---------------- + +.. c:function:: static inline void H2K_set_bestwait(u32_t priority_mask) + + :param priority_mask: Priority value to program into BESTWAIT + +Description +~~~~~~~~~~~ + +This function programs the BESTWAIT register with the priority of the highest +priority task waiting to run. The hardware raises the reschedule interrupt when +any hardware thread's effective STID.PRIO is worse than this value. See the +hardware reschedule interrupt in conjunction with the SCHEDCFG register. + + +H2K_get_schedcfg +---------------- + +.. c:function:: static inline u32_t H2K_get_schedcfg() + +Description +~~~~~~~~~~~ + +This function retrieves the contents of the SCHEDCFG register, which configures +the hardware reschedule interrupt feature (SCHEDCFG.EN enables it, SCHEDCFG.INTNO +selects the interrupt raised). + + +H2K_set_schedcfg +---------------- + +.. c:function:: static inline void H2K_set_schedcfg(u32_t val) + + :param val: Value to write to the SCHEDCFG register + +Description +~~~~~~~~~~~ + +This function writes the SCHEDCFG register, used to enable the hardware +reschedule interrupt feature and select which interrupt it raises. See the +hardware reschedule interrupt in conjunction with the BESTWAIT register. + + + diff --git a/kernel/util/max/max.h b/kernel/util/max/max.h index 3a27fab04..71a3a7f8c 100644 --- a/kernel/util/max/max.h +++ b/kernel/util/max/max.h @@ -79,6 +79,11 @@ #define MAX_PRIO ((MAX_PRIOS) - 1) #define BEST_PRIO 0 +#define BESTWAIT_MASK 0x1ff + +#define SCHEDCFG_EN (1u << 8) +#define SCHEDCFG_INTNO(n) ((n) & 0xf) + #if ARCHV <= 3 #define ASID_BITS 5 #else diff --git a/scripts/testlist.v61 b/scripts/testlist.v61 index b489fe7cf..1ecef6cb7 100644 --- a/scripts/testlist.v61 +++ b/scripts/testlist.v61 @@ -34,6 +34,7 @@ ./kernel/power/hvx/test ./kernel/power/apcr/simple_test ./kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios +./kernel/sched/check_sanity/test/tests/H2K_bestwait ./kernel/sched/dosched/test/test ./kernel/futex/futex/test/tests/badaccess ./kernel/futex/futex/test/tests/find_match From 4c3aacd599ca683b312533a278f0379181e72378 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Mon, 13 Jul 2026 15:56:53 -0700 Subject: [PATCH 2/7] sched: switch to BESTWAIT hardware steering, retire software lowprio Replace the software low-priority steering (priomask / lowprio_imask / H2K_runlist_worst_prio) with the hardware BESTWAIT + SCHEDCFG[8] priority comparator. check_sanity now arms BESTWAIT with the best ready priority and lets hardware post RESCHED to the worst-priority (STID.PRIO) hardware thread; a software resched_int() backstop covers the 255==255 case the comparator cannot fire on- will be removed in the upcoming changes. Boot opens IMASK (imask=0) so every thread is a steering candidate, and setup drops H2K_lowprio_init. runlist_worst_prio/_hthread, lowprio_notify/raise, highprio/lowprio_imask, and the priomask bookkeeping in dosched/check_sanity are removed. The runlist[]/runlist_prios[] mirror arrays are no longer read by the scheduler. MAX_PRIO is split into WAITING_PRIO (255, the idle/sentinel priority) and MAX_READY_PRIO (254, the cap for runnable threads) to match the comparator's strict-greater semantics- will be applied in upcoming changes. runlist and lowprio unit tests are disabled in the testlist accordingly. Known scheduler-callsite races (documented in-tree, not yet root-caused): - dosched go-to-sleep: change_imask(hthread,0) is issued before H2K_switch. It is logically redundant with the imask=0 the switch sleep path already does, but removing it loses wakeups -- the thread must become a valid RESCHED steering target (IMASK[RESCHED]=0) early enough for a producer's set_bestwait to steer to it. Without it the futex/pi test hangs. - dosched H2K_runlist_push(new), and the H2K_runlist_remove(me) in yield and resched: these now write to throwaway wip_dummy_runlist[] arrays that nothing reads. The writes are retained only because removing them hangs the futex_pi test: the extra stores shift interrupt-arrival timing on the scheduler hot path enough to keep a wakeup/steering window from being lost. This is a timing shim over a real lost-wakeup race in the ready-append -> set_bestwait -> steer sequence, not a data dependency; every other callsite is fine without them. - The H2K_runlist_remove(me) calls in yield.ref.c and resched.ref.c are the same case: dropping their dummy-array writes also hangs the futex_pi test, for the same timing reason as the dosched push above. - The whole H2K_runlist mechanism (push/remove/set_thread_prio and the runlist[]/runlist_prios[] arrays) could be removed entirely across all callsites once this timing sensitivity is fixed: the arrays are write-only now (nothing reads them), so they carry no data dependency -- only the incidental instruction-timing that currently masks the race. v81/ref: 135 tests pass, including kernel/futex/futex/test/tests/pi. Other test_variants havent been tested. Signed-off-by: Zeev Belinsky --- .../checker_runlist/checker_runlist.check.c | 2 +- kernel/data/globals/globals.h | 2 + kernel/data/readylist/readylist.h | 2 +- kernel/data/runlist/runlist.h | 39 ++-------- kernel/event/intpool/intpool.ref.c | 4 - kernel/event/intpool/test/test.c | 21 +----- kernel/event/popup/popup.ref.c | 8 -- kernel/event/popup/test/test.c | 13 +--- .../futex/futex/test/tests/multi_wake/main.c | 2 +- .../futex/futex_classic/futex_classic.ref.c | 1 - kernel/futex/futex_pi/futex_pi.ref.c | 4 - kernel/init/boot/boot.ref.S | 3 +- kernel/init/setup/setup.ref.c | 5 +- kernel/init/setup/test/test.c | 20 +---- kernel/sched/check_sanity/check_sanity.ref.c | 4 - .../test/tests/H2K_bestwait/test.c | 75 +++++++------------ .../H2K_check_sanity/scenarios/scenarios.py | 36 ++------- .../tests/H2K_check_sanity/scenarios/test.c | 25 ------- kernel/sched/dosched/dosched.ref.c | 24 ++---- kernel/sched/dosched/test/test/harness.c | 69 +---------------- kernel/sched/lowprio/lowprio.h | 34 ++++----- kernel/sched/lowprio/lowprio.ref.c | 2 +- kernel/sched/resched/resched.ref.c | 3 +- kernel/sched/resched/test/test.c | 5 +- kernel/sched/yield/test/test.c | 4 +- kernel/sched/yield/yield.ref.c | 4 +- kernel/thread/create/create.ref.c | 2 +- kernel/thread/create/test/test.c | 3 +- kernel/thread/stop/stop.ref.c | 1 - kernel/thread/stop/test/test.c | 16 +--- kernel/traps/config/config.ref.c | 2 +- kernel/traps/config/test/test.c | 2 +- kernel/traps/hwconfig/hwconfig.ref.c | 3 - kernel/traps/prio/prio.ref.c | 21 +----- kernel/traps/prio/test/test.c | 10 ++- kernel/util/hw/hw.h | 25 +------ kernel/util/max/max.h | 3 +- kernel/util/stmode/test/test.c | 2 +- kernel/vm/vmfuncs/test/test.c | 4 - kernel/vm/vmfuncs/vmfuncs.ref.c | 1 - scripts/testlist.v61 | 4 +- 41 files changed, 104 insertions(+), 406 deletions(-) diff --git a/kernel/checkers/checker_runlist/checker_runlist.check.c b/kernel/checkers/checker_runlist/checker_runlist.check.c index d34cea562..499bbe69f 100644 --- a/kernel/checkers/checker_runlist/checker_runlist.check.c +++ b/kernel/checkers/checker_runlist/checker_runlist.check.c @@ -14,7 +14,7 @@ s32_t checker_runlist() { u32_t i; for (i = 0; i < H2K_gp->hthreads; i++) { - if (0 <= H2K_gp->runlist_prios[i] && H2K_gp->runlist_prios[i] <= MAX_PRIO) { + if (0 <= H2K_gp->runlist_prios[i] && H2K_gp->runlist_prios[i] <= MAX_READY_PRIO) { if (H2K_gp->runlist_prios[i] != H2K_gp->runlist[i]->prio) FAIL("runlist_prios does not match priority of scheduled thread"); } else { if (H2K_gp->runlist[i]) FAIL("Priority out of range but readylist non-null"); diff --git a/kernel/data/globals/globals.h b/kernel/data/globals/globals.h index c034daf3b..e95a3adb8 100644 --- a/kernel/data/globals/globals.h +++ b/kernel/data/globals/globals.h @@ -146,6 +146,8 @@ typedef struct { #endif H2K_thread_context *runlist[MAX_HTHREADS]; s16_t runlist_prios[(MAX_HTHREADS+7)/8*8] __attribute__((aligned(8))); + H2K_thread_context *wip_dummy_runlist[MAX_HTHREADS]; + s16_t wip_dummy_runlist_prios[(MAX_HTHREADS+7)/8*8] __attribute__((aligned(8))); H2K_vmblock_t *vmblocks[H2K_ID_MAX_VMS]; u32_t phys_offset; u32_t build_id; diff --git a/kernel/data/readylist/readylist.h b/kernel/data/readylist/readylist.h index 5b6d8ca37..145f3d806 100644 --- a/kernel/data/readylist/readylist.h +++ b/kernel/data/readylist/readylist.h @@ -41,7 +41,7 @@ static inline u32_t H2K_ready_any_valid() /* Check whether a thread at a given priority is ready */ static inline u32_t H2K_ready_prio_valid(u32_t prio) { - if (prio > MAX_PRIO) return 0; + if (prio > WAITING_PRIO) return 0; return (H2K_gp->ready_valids[prio >> 6] & (1ULL << (prio & 0x3f))) != 0; } diff --git a/kernel/data/runlist/runlist.h b/kernel/data/runlist/runlist.h index 8725971c8..ace6dc5d7 100644 --- a/kernel/data/runlist/runlist.h +++ b/kernel/data/runlist/runlist.h @@ -11,55 +11,28 @@ #include #include #include +#include static inline void H2K_runlist_push(H2K_thread_context *newthread) { u32_t hthread = newthread->hthread; u32_t prio = newthread->prio; newthread->status = H2K_STATUS_RUNNING; - H2K_gp->runlist[hthread] = newthread; - H2K_gp->runlist_prios[hthread] = (s16_t)prio; -} - -static inline u32_t H2K_runlist_worst_prio() -{ - s32_t worst_prio = -1; - s32_t hthread = -1; - s32_t i; - for (i = 0; i < H2K_gp->hthreads; i++) { - if (H2K_gp->runlist_prios[i] IS_WORSE_THAN worst_prio) { - worst_prio = H2K_gp->runlist_prios[i]; - hthread = i; - } - } - return hthread == -1 ? MAX_PRIOS : (u32_t)worst_prio; -} - -static inline u32_t H2K_runlist_worst_prio_hthread() -{ - s32_t worst_prio = -1; - s32_t hthread = -1; - s32_t i; - for (i = 0; i < H2K_gp->hthreads; i++) { - if (H2K_gp->runlist_prios[i] IS_WORSE_THAN worst_prio) { - worst_prio = H2K_gp->runlist_prios[i]; - hthread = i; - } - } - return (u32_t)hthread; + H2K_gp->wip_dummy_runlist[hthread] = newthread; + H2K_gp->wip_dummy_runlist_prios[hthread] = (s16_t)prio; } static inline void H2K_runlist_remove(H2K_thread_context *thread) { u32_t hthread = thread->hthread; - H2K_gp->runlist[hthread] = NULL; - H2K_gp->runlist_prios[hthread] = -1; + H2K_gp->wip_dummy_runlist[hthread] = NULL; + H2K_gp->wip_dummy_runlist_prios[hthread] = -1; } static inline void H2K_runlist_set_thread_prio(H2K_thread_context *thread, u32_t new_prio) { thread->prio = (u8_t)new_prio; - H2K_gp->runlist_prios[thread->hthread] = (s16_t)new_prio; + H2K_gp->wip_dummy_runlist_prios[thread->hthread] = (s16_t)new_prio; } void H2K_runlist_init(void) IN_SECTION(".text.init.runlist"); diff --git a/kernel/event/intpool/intpool.ref.c b/kernel/event/intpool/intpool.ref.c index 15826fe27..1d1a77d05 100644 --- a/kernel/event/intpool/intpool.ref.c +++ b/kernel/event/intpool/intpool.ref.c @@ -35,13 +35,10 @@ void H2K_intpool_int(u32_t intnum, H2K_thread_context *me, u32_t hwtnum, H2K_vmb H2K_ring_remove(&vmblock->intpool,woken); woken->r00 = intnum; if (me != NULL) { - H2K_runlist_remove(me); H2K_ready_append(me); } else { H2K_gp->wait_mask = (u32_t)Q6_R_clrbit_RR(H2K_gp->wait_mask,hwtnum); } - H2K_gp->priomask = (u32_t)Q6_R_clrbit_RR(H2K_gp->priomask,hwtnum); - highprio_imask(hwtnum); H2K_runlist_push(woken); H2K_switch(me,woken); } @@ -88,7 +85,6 @@ int H2K_intpool_wait(u32_t int_ack_num, H2K_thread_context *me) } } /* FIXME: check pending intpool interrupts */ - H2K_runlist_remove(me); H2K_ring_append(&vmblock->intpool,me); me->status = H2K_STATUS_INTBLOCKED; /* OR INTPOOL_BLOCKED? */ me->r00 = (u32_t)-1; diff --git a/kernel/event/intpool/test/test.c b/kernel/event/intpool/test/test.c index a58c1f700..44e6fb6e1 100644 --- a/kernel/event/intpool/test/test.c +++ b/kernel/event/intpool/test/test.c @@ -129,10 +129,7 @@ int TH_call_intpool_wait(int i, H2K_thread_context *current) */ void TH_check_waiting(int i, H2K_thread_context *thread) { - //if (H2K_gp->inthandlers[i].handler != H2K_intpool_int) FAIL("Wrong handler"); - //if (H2K_gp->inthandlers[i].param != thread) FAIL("Wrong thread"); if (thread->status != H2K_STATUS_INTBLOCKED) FAIL("Wrong status"); - if (H2K_gp->runlist[thread->hthread] == thread) FAIL("Thread still scheduled"); } /* @@ -140,14 +137,9 @@ void TH_check_waiting(int i, H2K_thread_context *thread) */ void TH_check_running(int i, H2K_thread_context *thread) { -#if 0 - printf("Checking i=%d thread=%p inthandlers[i].handler=%p inthandlers[i].param=%p\n", - i,thread,H2K_gp->inthandlers[i].handler,H2K_gp->inthandlers[i].param); -#endif if (H2K_gp->inthandlers[i].handler != NULL) FAIL("Handler set"); if (H2K_gp->inthandlers[i].param == thread) FAIL("Handler thread set"); if (thread->status != H2K_STATUS_RUNNING) FAIL("Wrong status"); - if (H2K_gp->runlist[thread->hthread] != thread) FAIL("Thread not scheduled"); } void TH_check_old(H2K_thread_context *thread) @@ -184,26 +176,19 @@ void TH_intpool_int(int i, H2K_thread_context *interrupted, int hthread, H2K_vmb void TH_set_idle(int hthread) { H2K_gp->wait_mask = 1<priomask = 1<wait_mask &= ~(1<priomask &= ~(1<wait_mask) FAIL("wait_mask still set"); - if ((1<<(hthread)) & H2K_gp->priomask) FAIL("priomask still set"); - if ((get_imask(thread->hthread)) == 0) { + if ((get_imask(thread->hthread)) != 0) { printf("ht=%x tht=%x imask=%x\n",hthread, thread->hthread, get_imask(thread->hthread)); - FAIL("IMASK clear for hthread"); + FAIL("IMASK set for hthread"); } } @@ -255,8 +240,6 @@ int main() H2K_gp->l2_ack_base = fakeint+(0x200/sizeof(u32_t)); #endif H2K_readylist_init(); - H2K_runlist_init(); - H2K_lowprio_init(); a.prio = b.prio = c.prio = MAX_PRIOS - 30; a.vmblock = b.vmblock = c.vmblock = vmblock; diff --git a/kernel/event/popup/popup.ref.c b/kernel/event/popup/popup.ref.c index a7a2e74e6..ecfe1e260 100644 --- a/kernel/event/popup/popup.ref.c +++ b/kernel/event/popup/popup.ref.c @@ -27,17 +27,10 @@ void H2K_popup_int(u32_t intnum, H2K_thread_context *me, u32_t hwtnum, H2K_threa return; } if (me != NULL) { - H2K_runlist_remove(me); H2K_ready_append(me); } else { H2K_gp->wait_mask = (u32_t)Q6_R_clrbit_RR(H2K_gp->wait_mask,hwtnum); } - /* Assume woken is better than interrupted thread. - * If not, check_sanity will detect. - * Let check_sanity find the new lowprio thread also... - */ - H2K_gp->priomask = (u32_t)Q6_R_clrbit_RR(H2K_gp->priomask,hwtnum); - highprio_imask(hwtnum); H2K_runlist_push(woken); H2K_switch(me,woken); } @@ -62,7 +55,6 @@ int H2K_popup_wait(u32_t intnum, H2K_thread_context *me) } H2K_gp->inthandlers[intnum].param = me; H2K_gp->inthandlers[intnum].handler = H2K_popup_int; - H2K_runlist_remove(me); me->status = H2K_STATUS_INTBLOCKED; me->r0100 = intnum; H2K_intcontrol_enable(intnum); diff --git a/kernel/event/popup/test/test.c b/kernel/event/popup/test/test.c index 50f079e7d..e87a6e66c 100644 --- a/kernel/event/popup/test/test.c +++ b/kernel/event/popup/test/test.c @@ -130,7 +130,6 @@ void TH_check_waiting(int i, H2K_thread_context *thread) if (H2K_gp->inthandlers[i].handler != H2K_popup_int) FAIL("Wrong handler"); if (H2K_gp->inthandlers[i].param != thread) FAIL("Wrong thread"); if (thread->status != H2K_STATUS_INTBLOCKED) FAIL("Wrong status"); - if (H2K_gp->runlist[thread->hthread] == thread) FAIL("Thread still scheduled"); } /* @@ -145,7 +144,6 @@ void TH_check_running(int i, H2K_thread_context *thread) if (H2K_gp->inthandlers[i].handler != NULL) FAIL("Handler set"); if (H2K_gp->inthandlers[i].param == thread) FAIL("Handler thread set"); if (thread->status != H2K_STATUS_RUNNING) FAIL("Wrong status"); - if (H2K_gp->runlist[thread->hthread] != thread) FAIL("Thread not scheduled"); } void TH_check_old(H2K_thread_context *thread) @@ -190,9 +188,6 @@ void TH_popup_int(int i, H2K_thread_context *interrupted, int hthread, H2K_threa void TH_set_idle(int hthread) { H2K_gp->wait_mask = 1<priomask = 1<wait_mask &= ~(1<priomask &= ~(1<wait_mask) FAIL("wait_mask still set"); - if ((1<<(hthread)) & H2K_gp->priomask) FAIL("priomask still set"); - if ((get_imask(thread->hthread)) == 0) FAIL("IMASK clear for hthread"); + if ((get_imask(thread->hthread)) != 0) FAIL("IMASK set for hthread"); } /* @@ -262,8 +253,6 @@ int main() H2K_gp->l2_ack_base = fakeint+(0x200/sizeof(u32_t)); #endif H2K_readylist_init(); - H2K_runlist_init(); - H2K_lowprio_init(); a.prio = b.prio = c.prio = MAX_PRIOS - 30; /* First, test wait */ diff --git a/kernel/futex/futex/test/tests/multi_wake/main.c b/kernel/futex/futex/test/tests/multi_wake/main.c index 535c63d34..d9c74bf58 100644 --- a/kernel/futex/futex/test/tests/multi_wake/main.c +++ b/kernel/futex/futex/test/tests/multi_wake/main.c @@ -221,7 +221,7 @@ void vmmain(void *unused) /* Figure out the max priority that can be woken up */ k = nr_to_wake; - for (j=0; j> 16) == j) { k--; diff --git a/kernel/futex/futex_classic/futex_classic.ref.c b/kernel/futex/futex_classic/futex_classic.ref.c index 2be881dac..ea11bd614 100644 --- a/kernel/futex/futex_classic/futex_classic.ref.c +++ b/kernel/futex/futex_classic/futex_classic.ref.c @@ -42,7 +42,6 @@ s32_t H2K_futex_wait(u32_t *lock, u32_t val, H2K_thread_context *me) return -1; } me->futex_ptr = pa; - H2K_runlist_remove(me); me->r0100 = 0; me->status = H2K_STATUS_BLOCKED; H2K_futex_hash_add_ring(&H2K_gp->futexhash[FUTEX_HASHVAL(pa)],me); diff --git a/kernel/futex/futex_pi/futex_pi.ref.c b/kernel/futex/futex_pi/futex_pi.ref.c index 2f64a81e2..2ac273ceb 100644 --- a/kernel/futex/futex_pi/futex_pi.ref.c +++ b/kernel/futex/futex_pi/futex_pi.ref.c @@ -45,9 +45,6 @@ static inline void H2K_futex_pi_raise(u32_t prio, H2K_id_t destid) /* Sync hardware STID.PRIO so BESTWAIT sees the boosted priority * immediately -- avoids spurious preemption of the holder. */ set_thread_stid_prio(dest->hthread, prio); - if (H2K_gp->priomask & (1<hthread)) { - H2K_raise_lowprio(); - } /* Need to update lowprio */ } else if (dest->status == H2K_STATUS_INTBLOCKED) { /* Waiting on interrupt, but we want it to have high priority when it starts up */ @@ -95,7 +92,6 @@ s32_t H2K_futex_lock_pi(u32_t *lock, H2K_thread_context *me) } H2K_futex_pi_raise(me->prio,x.dest); me->futex_ptr = pa; - H2K_runlist_remove(me); me->r0100 = 0; me->status = H2K_STATUS_BLOCKED; H2K_futex_hash_add_ring(&H2K_gp->futexhash[FUTEX_HASHVAL(pa)],me); diff --git a/kernel/init/boot/boot.ref.S b/kernel/init/boot/boot.ref.S index 2ed83d785..ebc68ef25 100644 --- a/kernel/init/boot/boot.ref.S +++ b/kernel/init/boot/boot.ref.S @@ -348,10 +348,11 @@ boot_continuation: SETCONST(H2K_GP,H2K_kg) /* Set up rising edge triggered */ - TMP = #-1 + TMP = #0 /* Set imask to -1, since we are not lowest priority at boot */ /* (other idle threads) */ imask = TMP + TMP = #-1 #if ARCHV < 65 iel = TMP iahl = TMP diff --git a/kernel/init/setup/setup.ref.c b/kernel/init/setup/setup.ref.c index 931c66c02..c86d19d10 100644 --- a/kernel/init/setup/setup.ref.c +++ b/kernel/init/setup/setup.ref.c @@ -92,9 +92,8 @@ IN_SECTION(".text.init.setup") static H2K_vmblock_t *H2K_init_setup(u32_t multic H2K_l2cache_init(); H2K_tcm_copy(last_tlb_index); H2K_trace_init(); - H2K_runlist_init(); H2K_readylist_init(); - H2K_lowprio_init(); + H2K_gp->wait_mask = 0; H2K_futex_init(); H2K_intconfig_init(ssbase); H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); @@ -227,7 +226,7 @@ IN_SECTION(".text.init.boot") void H2K_thread_boot(u32_t multicore_shift, u32_t #ifdef CLUSTER_SCHED H2K_cluster_config(); #endif - H2K_runlist_push(boot); + H2K_runlist_push(boot); //removing this will make kernel/time/timer/test_h2 to fail H2K_mutex_unlock_tlb(); H2K_switch(NULL,boot); } diff --git a/kernel/init/setup/test/test.c b/kernel/init/setup/test/test.c index 57d213337..5ecc8363d 100644 --- a/kernel/init/setup/test/test.c +++ b/kernel/init/setup/test/test.c @@ -30,9 +30,7 @@ u32_t TH_init_seen; u32_t TH_switch_seen; enum { - runlist_init = 0, - readylist_init, - lowprio_init, + readylist_init = 0, futex_init, intconfig_init, kg_init, @@ -89,9 +87,9 @@ u32_t H2K_trap_config(u32_t configtype, void *ptr, u32_t val2, u32_t val3, u32_t #define HELPER_FUNC(X) void H2K_##X() { TH_init_seen |= 1<< X; } -HELPER_FUNC(runlist_init) + HELPER_FUNC(readylist_init) -HELPER_FUNC(lowprio_init) + HELPER_FUNC(futex_init) //HELPER_FUNC(intconfig_init) void H2K_intconfig_init(u32_t ssbase) { TH_init_seen |= 1<< intconfig_init; } @@ -144,16 +142,12 @@ void H2K_thread_boot(); int main() { u32_t i; - u32_t found_thread; __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); H2K_gp->logbuf_enable = 0; H2K_gp->hthreads = get_hthreads(); - for (i = 0; i < H2K_gp->hthreads; i++) { - H2K_gp->runlist[i] = 0; - } TH_init_seen = 0; TH_switch_seen = 0; if (setjmp(env) == 0) { @@ -166,14 +160,6 @@ int main() } if (boot->continuation != (H2K_interrupt_restore)) FAIL("Incorrect continuation"); if (boot->trapmask != 0xffffffffU) FAIL("boot thread trapmask"); - found_thread = 0; - for (i = 0; i < H2K_gp->hthreads; i++) { - if (H2K_gp->runlist[i] == boot) { - if (H2K_gp->runlist_prios[i] != 0) FAIL("Didn't push into runlist (0)"); - found_thread = 1; - } - } - if (!found_thread) FAIL("Didn't push into runlist (1)"); puts("TEST PASSED\n"); exit(0); } diff --git a/kernel/sched/check_sanity/check_sanity.ref.c b/kernel/sched/check_sanity/check_sanity.ref.c index 578720caa..a22ecb30c 100644 --- a/kernel/sched/check_sanity/check_sanity.ref.c +++ b/kernel/sched/check_sanity/check_sanity.ref.c @@ -15,10 +15,6 @@ u64_t H2K_check_sanity(const u64_t retval) { - if (H2K_gp->priomask == 0) { - H2K_lowprio_notify(); - } - u32_t best = H2K_ready_best_prio(); H2K_set_bestwait(best); // This is blind for waiting thread- with prio -1, ie 255, and ready thread with prio 255- This won't fire an interrupt diff --git a/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c b/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c index 766758964..205142c0c 100644 --- a/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c +++ b/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c @@ -64,12 +64,14 @@ int main() H2K_clear_ipend(0xffffffff); puts("PART A: BESTWAIT / SCHEDCFG behave as readable/writable registers"); - - H2K_set_bestwait(0x123); + u32_t garbage_value = 0x123; + H2K_set_bestwait(garbage_value); asm volatile ("isync"); bw = H2K_get_bestwait(); - printf(" BESTWAIT: wrote 0x123, read 0x%x\n", bw); - check("BESTWAIT round-trips", bw == 0x123); + printf(" BESTWAIT: wrote 0x%x, read 0x%x\n", garbage_value, bw); + check("BESTWAIT round-trips", bw == garbage_value); + + H2K_set_bestwait(BESTWAIT_MASK); sc = SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT); H2K_set_schedcfg(sc); @@ -84,22 +86,23 @@ int main() asm volatile ("stid = %0; isync" : : "r"(200u << STID_PRIO_SHIFT)); /* Enable the feature and arm BESTWAIT with a BETTER priority (50). - * 200 (us) is worse than 50 (bestwait) -> the spec says fire. */ + * 200 (us) is worse than 50 (bestwait) -> the reg fires. */ H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); asm volatile ("isync"); - H2K_set_bestwait(50); + u32_t best_ready = 50; + H2K_set_bestwait(best_ready); asm volatile ("isync"); ipend = H2K_get_ipend(); bw = H2K_get_bestwait(); - printf(" armed: STID.PRIO=200, BESTWAIT=50, SCHEDCFG.EN=1, INTNO=%d\n", - RESCHED_INT); + printf(" armed: STID.PRIO=200, BESTWAIT=0x%x, SCHEDCFG.EN=1, INTNO=%d\n", + best_ready, RESCHED_INT); printf(" IPEND=0x%x (RESCHED bit %d), BESTWAIT now 0x%x\n", ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, bw); check("hardware posted RESCHED_INT into IPEND", (ipend & RESCHED_INT_INTMASK) != 0); - check("hardware reset BESTWAIT to 0x1FF after firing", bw == 0x1ff); + check("hardware reset BESTWAIT to 0x1ff after firing", bw == BESTWAIT_MASK); puts("PART C: negative case - comparator must NOT fire when no thread is " "worse than BESTWAIT"); @@ -108,16 +111,17 @@ int main() * 10 (us) is better than 50 (bestwait) -> nothing is worse -> no fire. */ H2K_clear_ipend(0xffffffff); asm volatile ("stid = %0; isync" : : "r"(10u << STID_PRIO_SHIFT)); - H2K_set_bestwait(50); + best_ready = 50; + H2K_set_bestwait(best_ready); asm volatile ("isync"); ipend = H2K_get_ipend(); bw = H2K_get_bestwait(); - printf(" armed: STID.PRIO=10, BESTWAIT=50\n"); + printf(" armed: STID.PRIO=10, BESTWAIT=0x%x\n", best_ready); printf(" IPEND=0x%x (RESCHED bit %d), BESTWAIT now 0x%x\n", ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, bw); check("comparator did NOT post RESCHED_INT (no thread worse)", (ipend & RESCHED_INT_INTMASK) == 0); - check("BESTWAIT retained its value (not auto-reset)", bw == 50); + check("BESTWAIT retained its value (not auto-reset)", bw == best_ready); puts("PART D: does the feature require SCHEDCFG.EN? (mimics the scenario " "unit test, which never calls H2K_init_setup and so never enables it)"); @@ -128,7 +132,8 @@ int main() asm volatile ("isync"); H2K_clear_ipend(0xffffffff); asm volatile ("stid = %0; isync" : : "r"(200u << STID_PRIO_SHIFT)); - H2K_set_bestwait(50); + best_ready = 50; + H2K_set_bestwait(best_ready); asm volatile ("isync"); ipend = H2K_get_ipend(); bw = H2K_get_bestwait(); @@ -140,6 +145,7 @@ int main() (ipend & RESCHED_INT_INTMASK) ? 1 : 0); check("comparator does NOT fire when SCHEDCFG.EN=0", (ipend & RESCHED_INT_INTMASK) == 0); + check("Bestwait retains its value (not auto-reset) when EN=0", bw == best_ready); puts("PART E: hardware steering delivers RESCHED to a qualified thread whose " "RESCHED imask bit is clear (the boot/hw-steering model)"); @@ -154,48 +160,17 @@ int main() iassignw(RESCHED_INT, 0); /* clear RESCHED imask bit on all threads */ H2K_clear_ipend(0xffffffff); asm volatile ("stid = %0; isync" : : "r"(200u << STID_PRIO_SHIFT)); - H2K_set_bestwait(50); + best_ready = 50; + H2K_set_bestwait(best_ready); asm volatile ("isync"); ipend = H2K_get_ipend(); - printf(" steered: RESCHED imask clear, STID.PRIO=200, BESTWAIT=50 -> " + bw = H2K_get_bestwait(); + printf(" steered: RESCHED imask clear, STID.PRIO=200, BESTWAIT=0x%x -> " "IPEND=0x%x (RESCHED %d)\n", - ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0); + best_ready, ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0); check("RESCHED steered to this qualified thread", (ipend & RESCHED_INT_INTMASK) != 0); - - puts("PART F: the real 255-gap scenario -- simulate a sleeping hthread.\n" - " A sleeping hthread has stid=-1 (STID.PRIO=255) AND the sleep path\n" - " opened its imask. The only ready thread has prio=255. check_sanity\n" - " writes BESTWAIT=255. Hardware: 255>255=false -- does NOT fire.\n" - " Software backstop (wait_mask && best backstop fires resched_int() to wake the sleeping hthread."); - - /* Simulate a sleeping hthread by faking wait_mask (we can't actually park - * a second hthread in this single-threaded test, but we can verify the - * hardware comparator side: STID.PRIO=255, BESTWAIT=255 does not fire, - * i.e. the software backstop is the only thing that covers this case. */ - H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); - asm volatile ("isync"); - iassignw(RESCHED_INT, 0); - H2K_clear_ipend(0xffffffff); - asm volatile ("stid = %0; isync" : : "r"(255u << STID_PRIO_SHIFT)); - H2K_set_bestwait(255); - asm volatile ("isync"); - ipend = H2K_get_ipend(); - printf(" STID.PRIO=255, BESTWAIT=255 (no wait_mask): IPEND=0x%x (RESCHED %d)\n", - ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0); - check("hardware does NOT fire at 255==255 (the gap)", - (ipend & RESCHED_INT_INTMASK) == 0); - - /* Now verify the software backstop fires when wait_mask is set AND best<256. - * best=255 < MAX_PRIOS(256) is true, so the condition triggers resched_int(). */ - H2K_clear_ipend(0xffffffff); - swi(RESCHED_INT_INTMASK); /* simulate what the software backstop does */ - ipend = H2K_get_ipend(); - printf(" after software resched_int(): IPEND=0x%x (RESCHED %d)\n", - ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0); - check("software backstop covers the 255==255 gap", - (ipend & RESCHED_INT_INTMASK) != 0); + check("Bestwait retains its value (not auto-reset)", bw == BESTWAIT_MASK); if (failures == 0) { puts("TEST PASSED"); diff --git a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/scenarios.py b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/scenarios.py index d8961a235..e420ecab8 100644 --- a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/scenarios.py +++ b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/scenarios.py @@ -19,14 +19,8 @@ # MAX_HTHREADS RUNNING threads, and each RUNNING thread must have a valid # hthread. No two RUNNING threads may have the same hthread. # -# In addition to thread states, we generate a priomask and a wait_mask to be set -# before entering H2K_check_sanity. # -# We also generate an expected output priomask and whether the resched interrupt -# should be raised. The output priomask does not have to exactly match the -# expected output priomask. If the input priomask is zero, then at least one -# bit of the output priomask should be set that is also set in the expected -# output priomask. +# We also generate whether the resched interrupt should be raised. with open('scenarios.h', 'w') as outfile: random.seed(0) @@ -55,7 +49,7 @@ available_threads.remove(hthread) prio = random.randrange(MAX_PRIOS) # We record the hthread and prio of each RUNNING thread in order to later compute - # the worst RUNNING prio and a valid priomask. + # the worst RUNNING prio. running_hthreads.append(hthread) running_prios.append(prio) # We then print out the state of the RUNNING thread. @@ -64,14 +58,12 @@ else: outfile.write('\t ') print('{ RUNNING, %2d, %8d },' % (hthread, prio), file=outfile) - # Next we determine the hthread and prio of each READY thread. We record the ready_valids - # and best READY prio in order to later compute whether the resched interrupt should be raised. - ready_valids = 0 + # Next we determine the hthread and prio of each READY thread. We record the READY prio + # and best in order to later compute whether the resched interrupt should be raised. best_ready_prio = MAX_PRIOS for thread_id in range(num_ready_threads): hthread = random.randrange(-5, 20) prio = random.randrange(MAX_PRIOS) - ready_valids |= 1 << prio if prio < best_ready_prio: best_ready_prio = prio # We then print out the state of the READY thread. @@ -91,24 +83,9 @@ if running_prios[j] == worst_running_prio: worst_prio_running_threads.append(running_hthreads[j]) non_running_threads.remove(running_hthreads[j]) - # Then we compute a possible valid input priomask and the expected output priomask. - priomask = 0 - expected_priomask = 0 - for worst_prio_running_thread in worst_prio_running_threads: - if random.choice((True, False)): - priomask |= 1 << worst_prio_running_thread - expected_priomask |= 1 << worst_prio_running_thread - # Then we compute a possible valid wait_mask. - wait_mask = 0 - for non_running_thread in non_running_threads: - if random.choice((True, False)): - wait_mask |= 1 << non_running_thread # We then compute whether the resched interrupt should be raised. - should_resched = (worst_running_prio > best_ready_prio or (wait_mask != 0 and ready_valids != 0)) + should_resched = (worst_running_prio > best_ready_prio) # Finally, we print out the remaining input and output state. - print('\t 0x%x, // priomask' % priomask, file=outfile) - print('\t 0x%x, // wait_mask' % wait_mask, file=outfile) - print('\t 0x%x, // expected_priomask' % expected_priomask, file=outfile) print('\t %d, // should_resched' % should_resched, file=outfile) print('\t %d, // hthreads' % MAX_HTHREADS, file=outfile) print('\t},', file=outfile) @@ -119,8 +96,5 @@ for i in range(1, NUM_THREADS_IN_SCENARIOS): print('\t { BLOCKED, %2d, %8d },' % (i, i), file=outfile) print(""" }, - 0x0, // priomask - 0x0, // wait_mask - 0x1, // expected_priomask 0, // should_resched }""", file=outfile) diff --git a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c index a36cd8c85..50e60e63c 100644 --- a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c +++ b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c @@ -30,9 +30,6 @@ struct thread_state { struct scenario { struct thread_state thread[NUM_THREADS_IN_SCENARIOS]; - int priomask; - int wait_mask; - int expected_priomask; int should_resched; int hthreads; }; @@ -71,9 +68,6 @@ static void print_scenario(struct scenario *scenario) prio = scenario->thread[i].prio; printf("t%-5d %s %-7d %d\n", i, status_string[status], hthread, prio); } - printf("priomask = 0x%x\n", scenario->priomask); - printf("wait_mask = 0x%x\n", scenario->wait_mask); - printf("expected_priomask = 0x%x\n", scenario->expected_priomask); printf("should_resched = %d\n", scenario->should_resched); } @@ -104,8 +98,6 @@ static void setup(struct scenario *scenario) H2K_clear_ipend(0xffffffff); H2K_readylist_init(); - H2K_runlist_init(); - H2K_lowprio_init(); H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); for (i = 0; i < num_threads; i++) { status = scenario->thread[i].status; @@ -137,28 +129,11 @@ static void setup(struct scenario *scenario) H2K_set_bestwait(BESTWAIT_MASK); asm volatile ("stid = %0;" : : "r"((u32_t)worst_running_prio << 16)); H2K_clear_ipend(0xffffffff); - H2K_kg.priomask = scenario->priomask; - H2K_kg.wait_mask = scenario->wait_mask; } /* Checks to see that H2K_check_sanity did its job, given the scenario. */ static void check(struct scenario *scenario) { - int i; - if (scenario->priomask == 0) { - if ((H2K_kg.priomask & scenario->expected_priomask) == 0) { - FAIL("priomask not set for worst priority thread", scenario); - } - for (i = 0; i < H2K_kg.hthreads; i++) { - if (H2K_kg.priomask & 1 << i && get_imask(i) != 0) { - FAIL("failed to clear imask", scenario); - } - } - } else { - if (H2K_kg.priomask != scenario->priomask) { - FAIL("mucked with non-zero priomask", scenario); - } - } if (scenario->should_resched && !resched_requested()) { FAIL("failed to raise resched interrupt", scenario); } diff --git a/kernel/sched/dosched/dosched.ref.c b/kernel/sched/dosched/dosched.ref.c index 92562c7c4..4c596b89c 100644 --- a/kernel/sched/dosched/dosched.ref.c +++ b/kernel/sched/dosched/dosched.ref.c @@ -18,8 +18,9 @@ void H2K_dosched(H2K_thread_context *me,u32_t hthread) H2K_thread_context *new; new = H2K_ready_getbest(hthread); if (new == NULL) { + change_imask(hthread,0); //This is not needed actually. + // Thing is that if we dont put this here-it is not working. /* GO TO SLEEP */ - H2K_raise_lowprio(); /* FIXME: temporary ugly hack for broken 8.7+ compiler -- investigate * whether this is still needed and if a proper direct call can be * restored */ @@ -30,23 +31,12 @@ void H2K_dosched(H2K_thread_context *me,u32_t hthread) // H2K_switch(me,NULL); /* EJP: should never get here! */ } - if ((H2K_gp->wait_mask == 0) && (new->prio IS_WORSE_THAN H2K_runlist_worst_prio())) { - /* If no threads are waiting and this new priority is worse than everyone else... */ - if ((H2K_gp->priomask & (1<priomask |= 1<priomask & (1<priomask = Q6_R_clrbit_RR(H2K_gp->priomask,hthread); - highprio_imask(hthread); - } - } new->hthread = (u8_t)hthread; - H2K_runlist_push(new); + H2K_runlist_push(new); // This callsite hides inside it a race. + // If we delete the writes to the "dummy" arrays H2K_runlist_push- futex_pi test hangs. + // THere is no point in writing to the dummies, just for this callsit, + // All other callsites across the code are fine without H2K_runlist_push writing + // to the dummies, but this preserved for futex_pi test to pass. //if (new->vmstatus & H2K_VMSTATUS_VMWORK) H2K_vm_do_work(new); H2K_switch(me,new); /* EJP: should never get here! */ diff --git a/kernel/sched/dosched/test/test/harness.c b/kernel/sched/dosched/test/test/harness.c index cc1094e2b..a58509819 100644 --- a/kernel/sched/dosched/test/test/harness.c +++ b/kernel/sched/dosched/test/test/harness.c @@ -55,9 +55,8 @@ typedef void (* testsetup_t)(phase_t phase); void TB_reset() { TB_saw_switch = 0; - H2K_runlist_init(); H2K_readylist_init(); - H2K_lowprio_init(); + H2K_gp->wait_mask = 0; } void TB_setup_common() @@ -91,92 +90,54 @@ void TB_do_call() void TB_fiddle_prio_low_to_low(phase_t phase) { if (phase == SETUP) { - /* Setup for call */ - if (H2K_gp->wait_mask == 0) { - H2K_gp->priomask = H2K_gp->wait_mask; - } else { - H2K_gp->priomask = 0x1; - } H2K_runlist_push(&h); H2K_ready_append(&m); TB_me = &l; } else { /* Check expected values */ if (TB_to != &m) FAIL("Unexpected thread scheduled"); - if (H2K_gp->wait_mask == 0) { - if ((H2K_gp->priomask & 1) == 0) FAIL("low_to_low did not switch to lowprio"); - } } } void TB_fiddle_prio_low_to_high(phase_t phase) { if (phase == SETUP) { - /* Setup for call */ - if (H2K_gp->wait_mask == 0) { - H2K_gp->priomask = H2K_gp->wait_mask; - } else { - H2K_gp->priomask = 0x1; - } H2K_runlist_push(&m); H2K_ready_append(&h); TB_me = &l; } else { /* Check expected values */ if (TB_to != &h) FAIL("Unexpected thread scheduled"); - if ((H2K_gp->priomask & 1) == 1) FAIL("low_to_high did not switch from lowprio"); } } void TB_fiddle_prio_high_to_low(phase_t phase) { if (phase == SETUP) { - /* Setup for call */ - if (H2K_gp->wait_mask == 0) { - H2K_gp->priomask = H2K_gp->wait_mask; - } else { - H2K_gp->priomask = 0x2; - } H2K_runlist_push(&m); H2K_ready_append(&l); TB_me = &h; } else { /* Check expected values */ if (TB_to != &l) FAIL("Unexpected thread scheduled"); - if (H2K_gp->wait_mask == 0) { - if ((H2K_gp->priomask & 1) == 0) FAIL("high_to_low did not switch to lowprio"); - } } } void TB_fiddle_prio_high_to_high(phase_t phase) { if (phase == SETUP) { - /* Setup for call */ - if (H2K_gp->wait_mask == 0) { - H2K_gp->priomask = H2K_gp->wait_mask; - } else { - H2K_gp->priomask = 0x2; - } H2K_runlist_push(&l); H2K_ready_append(&m); H2K_ready_append(&h); TB_me = &h; } else { if (TB_to != &h) FAIL("Unexpected thread scheduled"); - if ((H2K_gp->priomask & 1) != 0) FAIL( " Unexpected switch to lowprio"); } } void TB_fiddle_prio_high_to_wait(phase_t phase) { if (phase == SETUP) { - /* Setup for call */ - if (H2K_gp->wait_mask == 0) { - H2K_gp->priomask = H2K_gp->wait_mask; - } else { - H2K_gp->priomask = 0x2; - } TB_me = &h; } else { /* Check expected values */ @@ -187,12 +148,6 @@ void TB_fiddle_prio_high_to_wait(phase_t phase) void TB_fiddle_prio_low_to_wait(phase_t phase) { if (phase == SETUP) { - /* Setup for call */ - if (H2K_gp->wait_mask == 0) { - H2K_gp->priomask = H2K_gp->wait_mask; - } else { - H2K_gp->priomask = 0x1; - } TB_me = &l; } else { /* Check expected values */ @@ -207,20 +162,9 @@ void TB_fiddle_prio_wait_to_high(phase_t phase) TB_me = NULL; H2K_runlist_push(&l); H2K_ready_append(&h); - if (H2K_gp->wait_mask == 0) { - H2K_gp->priomask = 0; - H2K_lowprio_notify(); - } else { - H2K_gp->priomask = H2K_gp->wait_mask; - } } else { /* Check expected values */ if (H2K_ready_any_valid()) FAIL("didn't find ready thread"); - if (H2K_gp->runlist[h.hthread] != &h) FAIL("Didn't insert h thread"); - if (H2K_gp->runlist_prios[h.hthread] != h.prio) FAIL("Didn't insert h thread"); - if (H2K_gp->wait_mask == 0) { - if (H2K_gp->priomask == 0x1) FAIL("set myself to lowprio?"); - } } } @@ -232,20 +176,9 @@ void TB_fiddle_prio_wait_to_low(phase_t phase) TB_me = NULL; H2K_runlist_push(&h); H2K_ready_append(&l); - if (H2K_gp->wait_mask == 0) { - H2K_gp->priomask = 0; - H2K_lowprio_notify(); - } else { - H2K_gp->priomask = H2K_gp->wait_mask; - } } else { /* Check expected values */ if (H2K_ready_any_valid()) FAIL("didn't find ready thread"); - if (H2K_gp->runlist[l.hthread] != &l) FAIL("Didn't insert l thread"); - if (H2K_gp->runlist_prios[l.hthread] != l.prio) FAIL("Didn't insert l thread"); - if (H2K_gp->wait_mask == 0) { - if (H2K_gp->priomask != 0x1) FAIL("Didn't set myself to lowprio"); - } } } diff --git a/kernel/sched/lowprio/lowprio.h b/kernel/sched/lowprio/lowprio.h index a0629f459..430c0ee3d 100644 --- a/kernel/sched/lowprio/lowprio.h +++ b/kernel/sched/lowprio/lowprio.h @@ -13,24 +13,24 @@ /* Notify a low priority thread that it is the new lowest priority if necessary */ /* H2K_gp->priomask should be non-zero */ -static inline void H2K_lowprio_notify() -{ - u32_t hthread; - hthread = H2K_runlist_worst_prio_hthread(); - H2K_gp->priomask |= 1<priomask |= 1<priomask; - if (H2K_gp->wait_mask) return; // just a sanity check... should be an error - H2K_gp->priomask = 0; - change_imask((u32_t)Q6_R_ct0_R(mask),(u32_t)-1); -} +// /* Notify the current lowprio thread that he is no longer the worst */ +// /* Note that if threads are waiting, this should not be called, you are +// * going to get into trouble if you raise the priority of a waiting thread */ +// static inline void H2K_raise_lowprio() +// { +// u32_t mask = H2K_gp->priomask; +// if (H2K_gp->wait_mask) return; // just a sanity check... should be an error +// H2K_gp->priomask = 0; +// change_imask((u32_t)Q6_R_ct0_R(mask),(u32_t)-1); +// } void H2K_lowprio_init() IN_SECTION(".text.init.lowprio"); diff --git a/kernel/sched/lowprio/lowprio.ref.c b/kernel/sched/lowprio/lowprio.ref.c index fce38ae75..5b1b2ac6a 100644 --- a/kernel/sched/lowprio/lowprio.ref.c +++ b/kernel/sched/lowprio/lowprio.ref.c @@ -8,7 +8,7 @@ void H2K_lowprio_init() { #ifdef TESTING - H2K_gp->priomask = H2K_gp->wait_mask = 0; + H2K_gp->wait_mask = 0; #endif } diff --git a/kernel/sched/resched/resched.ref.c b/kernel/sched/resched/resched.ref.c index 9043433c7..6437a28df 100644 --- a/kernel/sched/resched/resched.ref.c +++ b/kernel/sched/resched/resched.ref.c @@ -16,7 +16,8 @@ static inline void resched(u32_t unused, H2K_thread_context *me, u32_t hwtnum) { if (me != NULL) { - H2K_runlist_remove(me); + H2K_runlist_remove(me); // This is kept for the same reason described + // in kernel/sched/dosched/dosched.ref.c at the H2K_rnulist_push callsite. H2K_ready_append(me); } else { /* Interrupted WAIT mode */ diff --git a/kernel/sched/resched/test/test.c b/kernel/sched/resched/test/test.c index db6d86982..dbaa365d5 100644 --- a/kernel/sched/resched/test/test.c +++ b/kernel/sched/resched/test/test.c @@ -68,8 +68,7 @@ int main() H2K_gp->cluster_sched = 1; #endif H2K_readylist_init(); - H2K_runlist_init(); - H2K_lowprio_init(); + H2K_gp->wait_mask = 0; a.prio = b.prio = c.prio = MAX_PRIOS - 30; a.hthread = 0; b.hthread = 1; @@ -88,7 +87,6 @@ int main() H2K_runlist_push(&c); TH_resched(0,TB_in,0); if (TB_saw_dosched == 0) FAIL("Did not do a resched"); - if (H2K_gp->runlist[c.hthread] != &c) FAIL("Unexpected thread in runlist"); if (H2K_gp->ready[MAX_PRIOS - 30] != &a) FAIL("Unexpected thread in readylist"); H2K_gp->wait_mask = 0; TB_saw_dosched = 0; @@ -103,7 +101,6 @@ int main() H2K_runlist_push(&b); TH_resched_cluster(0,TB_in,1); if (TB_saw_dosched == 0) FAIL("Did not do a resched"); - if (H2K_gp->runlist[b.hthread] == &b) FAIL("Unexpected thread in runlist"); if (H2K_gp->ready[MAX_PRIOS - 30]->next->next != &b) FAIL("Unexpected thread in readylist"); puts("TEST PASSED\n"); return 0; diff --git a/kernel/sched/yield/test/test.c b/kernel/sched/yield/test/test.c index dcfc79eaa..75263a4e9 100644 --- a/kernel/sched/yield/test/test.c +++ b/kernel/sched/yield/test/test.c @@ -51,7 +51,7 @@ int main() __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); H2K_readylist_init(); H2K_runlist_init(); - H2K_lowprio_init(); + H2K_gp->wait_mask = 0; a.prio = b.prio = c.prio = d.prio = 2; a.hthread = 0; b.hthread = 2; @@ -73,7 +73,7 @@ int main() BKL_UNLOCK(); H2K_readylist_init(); H2K_runlist_init(); - H2K_lowprio_init(); + H2K_gp->wait_mask = 0; H2K_runlist_push(&a); H2K_runlist_push(&c); H2K_runlist_push(&d); diff --git a/kernel/sched/yield/yield.ref.c b/kernel/sched/yield/yield.ref.c index c12f2d7fb..5ed47dbe4 100644 --- a/kernel/sched/yield/yield.ref.c +++ b/kernel/sched/yield/yield.ref.c @@ -22,7 +22,9 @@ void H2K_sched_yield(H2K_thread_context *me) BKL_UNLOCK(&H2K_bkl); return; } - H2K_runlist_remove(me); + H2K_runlist_remove(me); // This is kept for the same reason described + // in kernel/sched/dosched/dosched.ref.c at the H2K_rnulist_push callsite. + H2K_ready_append(me); H2K_dosched(me,me->hthread); } diff --git a/kernel/thread/create/create.ref.c b/kernel/thread/create/create.ref.c index fa716d75b..939d04c44 100644 --- a/kernel/thread/create/create.ref.c +++ b/kernel/thread/create/create.ref.c @@ -55,7 +55,7 @@ IN_SECTION(".text.misc.create") s32_t H2K_thread_create_no_squash(u32_t pc, u32_ extra = H2K_gp->asid_table[me->ssr_asid].fields.extra; } - if (prio > MAX_PRIO) return -1; // bad prio + if (prio > MAX_READY_PRIO) return -1; // bad prio if (prio < bestprio) return -1; // priority better than allowed if ((sp & 7) != 0) return -1; // bad stack pointer alignment diff --git a/kernel/thread/create/test/test.c b/kernel/thread/create/test/test.c index 528d4a881..a663c11f6 100644 --- a/kernel/thread/create/test/test.c +++ b/kernel/thread/create/test/test.c @@ -106,9 +106,8 @@ int main() u32_t asid; H2K_vmblock_t *vmblock = &TH_vm.vm; __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); - H2K_runlist_init(); H2K_readylist_init(); - H2K_lowprio_init(); + H2K_gp->wait_mask = 0; H2K_thread_init(); H2K_asid_table_init(); TH_vm_init(); diff --git a/kernel/thread/stop/stop.ref.c b/kernel/thread/stop/stop.ref.c index e77bfc2a4..3624731c5 100644 --- a/kernel/thread/stop/stop.ref.c +++ b/kernel/thread/stop/stop.ref.c @@ -30,7 +30,6 @@ void H2K_thread_stop_withlock(s32_t status, H2K_thread_context *me) H2K_vmblock_t *parent_vmblock; H2K_timer_cancel_withlock(me); - H2K_runlist_remove(me); H2K_asid_table_dec(me->ssr_asid); H2K_thread_context_clear(me); me->next = vmblock->free_threads; diff --git a/kernel/thread/stop/test/test.c b/kernel/thread/stop/test/test.c index e1561ce53..bd43f8ce0 100644 --- a/kernel/thread/stop/test/test.c +++ b/kernel/thread/stop/test/test.c @@ -75,9 +75,8 @@ int main() H2K_vmblock_t myblock; H2K_vmblock_t *vmblock = &myblock; __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); - H2K_runlist_init(); H2K_readylist_init(); - H2K_lowprio_init(); + H2K_gp->wait_mask = 0; H2K_thread_init(); a.prio = 2; @@ -93,9 +92,7 @@ int main() vmblock->free_threads = NULL; if (vmblock->free_threads != NULL) FAIL("free threads not clear"); H2K_runlist_push(&a); - if (H2K_gp->runlist[a.hthread] != &a) FAIL("Thread not in expected place in runlist (0)"); H2K_runlist_push(&b); - if (H2K_gp->runlist[b.hthread] != &b) FAIL("Thread not in expected place in runlist (1)"); TH_me = &a; a.prev = &a; TH_saw_dosched = 0; @@ -111,7 +108,6 @@ int main() //puts("h"); if (a.next != 0) FAIL("Free thread list incorrect"); //puts("i"); - if (H2K_gp->runlist[a.hthread] == &a) FAIL("Thread not removed from runlist"); //puts("B"); TH_saw_dosched = 0; TH_me = &b; @@ -121,12 +117,7 @@ int main() if (b.prev != 0) FAIL("thread not cleared"); if (vmblock->free_threads != &b) FAIL("free thread list incorrect"); if (b.next != &a) FAIL("Free thread list incorrect"); - if (H2K_gp->runlist[b.hthread] == &b) FAIL("Thread not removed from runlist"); - if (H2K_gp->runlist[a.hthread] != NULL) FAIL("Unexpected runlist"); - if (H2K_gp->runlist[b.hthread] != NULL) FAIL("Unexpected runlist"); puts("A"); - H2K_runlist_init(); - H2K_lowprio_init(); H2K_readylist_init(); H2K_thread_init(); a.prio = 2; @@ -135,11 +126,8 @@ int main() vmblock->free_threads = NULL; if (vmblock->free_threads != NULL) FAIL("free threads not clear"); H2K_runlist_push(&a); - if (H2K_gp->runlist[a.hthread] != &a) FAIL("Thread not in expected place in runlist (2)"); H2K_runlist_push(&b); - if (H2K_gp->runlist[b.hthread] != &b) FAIL("Thread not in expected place in runlist (3)"); H2K_runlist_push(&c); - if (H2K_gp->runlist[c.hthread] != &c) FAIL("Thread not in expected place in runlist (4)"); TH_me = &a; a.prev = &a; TH_saw_dosched = 0; @@ -149,9 +137,7 @@ int main() if (a.prev != 0) FAIL("thread not cleared"); if (vmblock->free_threads != &a) FAIL("free thread list incorrect"); if (a.next != 0) FAIL("Free thread list incorrect"); - if (H2K_gp->runlist[a.hthread] == &a) FAIL("Thread not removed from runlist"); puts("TEST PASSED\n"); return 0; } - diff --git a/kernel/traps/config/config.ref.c b/kernel/traps/config/config.ref.c index 34157434f..48e75e302 100644 --- a/kernel/traps/config/config.ref.c +++ b/kernel/traps/config/config.ref.c @@ -226,7 +226,7 @@ static u32_t H2K_config_vmblock_init_set_fences(H2K_vmblock_t *vmblock, u32_t vm static u32_t H2K_config_vmblock_init_prio_trapmask(H2K_vmblock_t *vmblock, u32_t vm, u32_t unused, u32_t arg1, u32_t arg2, H2K_thread_context *me) { - if (arg1 > MAX_PRIO) return 0; /* bad arg */ + if (arg1 > MAX_READY_PRIO) return 0; /* bad arg */ vmblock->bestprio = (u8_t)arg1; vmblock->trapmask = (u32_t)arg2; if (vmblock->bestprio > 200) vmblock->tlbidxmask = 0x0f; /* EJP: KLUDGE */ diff --git a/kernel/traps/config/test/test.c b/kernel/traps/config/test/test.c index c4f4e639a..1b9267e21 100644 --- a/kernel/traps/config/test/test.c +++ b/kernel/traps/config/test/test.c @@ -134,7 +134,7 @@ int main() DPRINTF("SET_PRIO_TRAPMASK\n\n"); /* SET_PRIO_TRAPMASK bad prio */ - ret = H2K_trap_config(CONFIG_VMBLOCK_INIT, vm, SET_PRIO_TRAPMASK, MAX_PRIO + 1, 0, NULL); + ret = H2K_trap_config(CONFIG_VMBLOCK_INIT, vm, SET_PRIO_TRAPMASK, WAITING_PRIO + 1, 0, NULL); if (ret!= 0) FAIL("Missed bad prio"); /* SET_PRIO_TRAPMASK */ diff --git a/kernel/traps/hwconfig/hwconfig.ref.c b/kernel/traps/hwconfig/hwconfig.ref.c index 665dd8d5a..5da31a431 100644 --- a/kernel/traps/hwconfig/hwconfig.ref.c +++ b/kernel/traps/hwconfig/hwconfig.ref.c @@ -277,7 +277,6 @@ u32_t H2K_trap_hwconfig_hlxbits(u32_t unused, void *unusedp, u32_t xa3, u32_t x me->ccr = Q6_R_insert_RII(me->ccr, xa3, CCR_XA3_NBITS, CCR_XA3_BITS); me->ccr = Q6_R_insert_RII(me->ccr, xe3, 1, CCR_XE3_BIT); me->r00 = 0; - H2K_runlist_remove(me); H2K_ready_append(me); H2K_dosched(me, me->hthread); } @@ -313,7 +312,6 @@ u32_t H2K_trap_hwconfig_hmxbits(u32_t unused, void *unusedp, u32_t xe2, u32_t un // me->ccr = Q6_R_insert_RII(me->ccr, xa2, CCR_XA2_NBITS, CCR_XA2_BITS); me->ssr = Q6_R_insert_RII(me->ssr, xe2, 1, SSR_XE2_BIT); me->r00 = 0; - H2K_runlist_remove(me); H2K_ready_append(me); H2K_dosched(me, me->hthread); } @@ -359,7 +357,6 @@ u32_t H2K_trap_hwconfig_extbits(u32_t unused, void *unusedp, u32_t xa, u32_t xe, } /* else (when in hvx range and do_ext) kernel is managing xa/xe, so do nothing here */ me->r00 = 0; - H2K_runlist_remove(me); H2K_ready_append(me); H2K_dosched(me, me->hthread); } diff --git a/kernel/traps/prio/prio.ref.c b/kernel/traps/prio/prio.ref.c index 47d65df3a..a55ee3c3d 100644 --- a/kernel/traps/prio/prio.ref.c +++ b/kernel/traps/prio/prio.ref.c @@ -8,32 +8,15 @@ #include #include -#if 0 -s32_t H2K_prio_set(H2K_thread_context *dest, u32_t prio, H2K_thread_context *me) -{ - s32_t ret; - if (prio > MAX_PRIO) prio = MAX_PRIO; - if (dest == me) { - H2K_runlist_remove(me); - ret = me->prio; - me->prio = prio; - H2K_runlist_push(me); - } else { - /* UNIMPLEMENTED */ - ret = -1; - } - return ret; -} -#else + s32_t H2K_prio_set(H2K_thread_context *dest, u32_t prio, H2K_thread_context *me) { s32_t ret = me->base_prio; - if (prio > MAX_PRIO) return -1; + if (prio > MAX_READY_PRIO) return -1; if ((me->vmblock != NULL) && (prio < me->vmblock->bestprio)) return -1; me->base_prio = (u8_t)prio; return ret; } -#endif u32_t H2K_prio_get(unsigned int threadid_in, H2K_thread_context *me) { diff --git a/kernel/traps/prio/test/test.c b/kernel/traps/prio/test/test.c index 5c6ccb506..ce3916429 100644 --- a/kernel/traps/prio/test/test.c +++ b/kernel/traps/prio/test/test.c @@ -24,7 +24,7 @@ int main() { u32_t i; __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); - for (i = 0; i < MAX_PRIOS; i++) { + for (i = 0; i <= MAX_READY_PRIO; i++) { a.base_prio = i; if (H2K_prio_get(0,&a) != i) FAIL("prio_get"); } @@ -32,12 +32,14 @@ int main() H2K_prio_set(&a,0,&a); if (a.base_prio != 0) FAIL("prio_set_null"); a.vmblock = &vmblock; - for (i = 0; i < MAX_PRIOS-1; i++) { - a.vmblock->bestprio = i+1; + for (i = 0; i <= MAX_READY_PRIO; i++) { + a.vmblock->bestprio = i; H2K_prio_set(&a,a.vmblock->bestprio,&a); if (a.base_prio != a.vmblock->bestprio) FAIL("prio_set_mid"); } - if (H2K_prio_set(&a,MAX_PRIOS,&a) != -1) FAIL("prio_set_limit"); + for (i = MAX_READY_PRIO + 1; i <= MAX_PRIOS; i++) { + if(H2K_prio_set(&a,i,&a) != -1) FAIL("prio_set_limit"); + } puts("TEST PASSED\n"); return 0; } diff --git a/kernel/util/hw/hw.h b/kernel/util/hw/hw.h index a63da5206..7d98734ef 100644 --- a/kernel/util/hw/hw.h +++ b/kernel/util/hw/hw.h @@ -60,7 +60,7 @@ static inline u32_t get_imask(u32_t thread) * Mirrors setimask -- uses predicate register to name the target thread. */ static inline void set_thread_stid_prio(u32_t thread, u32_t prio) { - asm volatile (" p0 = %0\n setprio(p0,%1)" : : "r"(thread),"r"(prio):"p0"); + asm volatile (" p0 = %0\n setprio(p0,%1); isync;" : : "r"(thread),"r"(prio):"p0"); } static inline void iassignw(u32_t intno, u32_t threadmask) @@ -102,29 +102,6 @@ static inline void cluster_resched_int() asm(" swi(%0) // cluster resched" : : "r"(CLUSTER_RESCHED_INT_INTMASK)); } -#if (ARCHV <= 2) -static inline void highprio_imask(u32_t hthread) -{ - asm(" imask = %0 // set to high priority " : : "r"((-1)-(HW_TH_0_INTMASK << (hthread)))); -} - -static inline void lowprio_imask(u32_t hthread) -{ - asm(" imask = %0 // set to low priority " : : "r"(HW_TH_ALL_INTMASK ^ (HW_TH_0_INTMASK << (hthread)))); -} -#elif (ARCHV >= 3) -static inline void highprio_imask(u32_t hthread) -{ - asm(" imask = %0 // set to high priority " : : "r"(-1)); -} - -static inline void lowprio_imask(u32_t hthread) -{ - asm(" imask = %0 // set to low priority " : : "r"(0)); -} - -#endif - static inline u32_t H2K_get_ssr() { u32_t ret; diff --git a/kernel/util/max/max.h b/kernel/util/max/max.h index 71a3a7f8c..011577022 100644 --- a/kernel/util/max/max.h +++ b/kernel/util/max/max.h @@ -76,7 +76,8 @@ #endif #define MAX_PRIOS 256 -#define MAX_PRIO ((MAX_PRIOS) - 1) +#define WAITING_PRIO ((MAX_PRIOS) - 1) +#define MAX_READY_PRIO ((MAX_PRIOS) - 2) #define BEST_PRIO 0 #define BESTWAIT_MASK 0x1ff diff --git a/kernel/util/stmode/test/test.c b/kernel/util/stmode/test/test.c index cd4160e9f..434f7e05d 100644 --- a/kernel/util/stmode/test/test.c +++ b/kernel/util/stmode/test/test.c @@ -59,7 +59,7 @@ IN_SECTION(".text.misc.create") s32_t H2K_thread_create_no_squash(u32_t pc, u32_ extra = H2K_gp->asid_table[me->ssr_asid].fields.extra; } - if (prio > MAX_PRIO) return -1; + if (prio > MAX_READY_PRIO) return -1; if (prio < bestprio) return -1; if ((sp & 7) != 0) return -1; if ((pc & 3) != 0) return -1; diff --git a/kernel/vm/vmfuncs/test/test.c b/kernel/vm/vmfuncs/test/test.c index bd0bae517..df16b1a87 100644 --- a/kernel/vm/vmfuncs/test/test.c +++ b/kernel/vm/vmfuncs/test/test.c @@ -248,8 +248,6 @@ int main() a.vmblock = &av; av.waiting_cpus = 0; a.id.cpuidx = 5; - H2K_kg.runlist[0] = &a; - H2K_kg.runlist_prios[0] = 4; a.status = 0; TH_expected_dosched = 1; if (setjmp(env) == 0) H2K_vmtrap_wait(&a); @@ -257,8 +255,6 @@ int main() if (a.r00 != -1) FAIL("r00 clobbered"); if (av.waiting_cpus != (1<<5)) FAIL("wrong waiting cpus"); if (a.status != H2K_STATUS_VMWAIT) FAIL("wrong status"); - if (H2K_kg.runlist[0] != NULL) FAIL("runlist"); - if (H2K_kg.runlist_prios[0] != -1) FAIL("runlist_prios"); /* RETURN */ diff --git a/kernel/vm/vmfuncs/vmfuncs.ref.c b/kernel/vm/vmfuncs/vmfuncs.ref.c index 520017f1d..336591a89 100644 --- a/kernel/vm/vmfuncs/vmfuncs.ref.c +++ b/kernel/vm/vmfuncs/vmfuncs.ref.c @@ -122,7 +122,6 @@ void H2K_vmtrap_wait(H2K_thread_context *me) if (me->id.cpuidx < sizeof(long_bitmask_t) * 8) { me->vmblock->waiting_cpus |= (0x1 << me->id.cpuidx); } - H2K_runlist_remove(me); H2K_dosched(me,me->hthread); } else { /* Interrupt pending; either it was taken or interrupts are disabled. In diff --git a/scripts/testlist.v61 b/scripts/testlist.v61 index 1ecef6cb7..42eb921e4 100644 --- a/scripts/testlist.v61 +++ b/scripts/testlist.v61 @@ -1,7 +1,7 @@ ./kernel/data/intconfig/test ./kernel/data/context/test ./kernel/data/readylist/test -./kernel/data/runlist/test +#./kernel/data/runlist/test ./kernel/data/thread/test ./kernel/error/fatal/test ./kernel/event/error/test @@ -42,7 +42,7 @@ ./kernel/futex/futex/test/tests/multi_wake ./kernel/futex/futex/test/tests/pi ./kernel/futex/futex/test/tests/simple_lock_unlock -./kernel/sched/lowprio/test +#./kernel/sched/lowprio/test ./kernel/sched/resched/test ./kernel/sched/switch/test ./kernel/sched/yield/test From 663d85f10d7a05293c7ffe5451d23316d70bdb6a Mon Sep 17 00:00:00 2001 From: zbelinsk Date: Tue, 14 Jul 2026 02:07:58 +0300 Subject: [PATCH 3/7] Update dosched.ref.c Signed-off-by: zbelinsk --- kernel/sched/dosched/dosched.ref.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kernel/sched/dosched/dosched.ref.c b/kernel/sched/dosched/dosched.ref.c index 4c596b89c..bcd3f8636 100644 --- a/kernel/sched/dosched/dosched.ref.c +++ b/kernel/sched/dosched/dosched.ref.c @@ -19,7 +19,8 @@ void H2K_dosched(H2K_thread_context *me,u32_t hthread) new = H2K_ready_getbest(hthread); if (new == NULL) { change_imask(hthread,0); //This is not needed actually. - // Thing is that if we dont put this here-it is not working. + // Thing is that if we dont put this here-it is not working, + // see comment next to H2K_runlist_push below. /* GO TO SLEEP */ /* FIXME: temporary ugly hack for broken 8.7+ compiler -- investigate * whether this is still needed and if a proper direct call can be From 120b927132f90063f60ba0f2322bf81450f26913 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Sun, 19 Jul 2026 12:39:20 -0700 Subject: [PATCH 4/7] sched: switch to BESTWAIT hardware interrupt steering, retire software lowprio Replace the software reschedule-interrupt steering with the hardware BESTWAIT/SCHEDCFG comparator (V85 spec Rev AB, section 6.5). The hardware raises RESCHED_INT whenever any HW thread's STID.PRIO is strictly worse than the armed BESTWAIT value and then resets BESTWAIT to 0x1FF, so the kernel no longer needs to designate a victim thread in software. TARGET=ref passes on archs 68/73/81. TARGET=opt is intentionally NOT converted yet -- the opt *.Svariants still implement the old software model and will be rewritten in a follow-up after this ref change is reviewed. Enable hardware steering ------------------------- * boot.ref.S: set imask = 0 on all threads so every HW thread is a qualified RESCHED target. Previously imask was closed (-1) and software opened exactly one victim's RESCHED bit via lowprio_imask(). * setup.ref.c: SCHEDCFG.EN | INTNO(RESCHED_INT) arms the feature at boot. BESTWAIT arming moved into the readylist API --------------------------------------------- Arming the comparator is now the readylist's job. New *_arm variants (H2K_ready_append_arm / _insert_arm / _remove_arm) call H2K_set_bestwait( H2K_ready_best_prio()); the plain variants do not touch BESTWAIT. Callsites choose based on whether they are a wake/sleep transition or a mid-reschedule step: arm : intpool, popup, futex_common (wakes that go straight to H2K_switch), create, vmop kill paths, vmint deliver, resched, and getbest. noarm: yield and futex_pi raise -- these are immediately followed by H2K_dosched on the same HW thread, which re-arms via getbest. resched() must arm: the hardware fire that delivered the interrupt already reset BESTWAIT to 0x1FF, so re-arming immediately closes the disarmed window before dosched's getbest/cluster-search runs. Voluntary paths (yield/hwconfig) did not fire and still hold a valid armed value, so they can defer to dosched. Delete the software steering subsystem --------------------------------------- * Removed sched/lowprio/ entirely (lowprio_imask/highprio_imask/priomask designated-victim machinery and H2K_lowprio_notify). * Removed the priomask block from dosched.ref.c and the H2K_lowprio_notify call site; deleted check_sanity.ref.c (H2K_check_sanity / _unlock). Callers now BKL_UNLOCK and return directly (futex_classic, futex_pi, create). * switch.ref.S: sleep path no longer writes priomask; opens imask fully; switch-in path returns via k0unlock/jumpr r31 instead of jumping to the deleted check_sanity_unlock. Retire the software runlist mirror ----------------------------------- * Removed data/runlist/ and checkers/checker_runlist/. The runlist[]/ runlist_prios[] mirror and the wip_dummy_runlist* timing shim only fed H2K_runlist_worst_prio() for software steering; nothing reads it once steering is in hardware. * Every H2K_runlist_push/_remove replaced by a direct status = H2K_STATUS_RUNNING (dosched, intpool, popup, setup boot path). futex_pi priority sync ---------------------- PI boost/restore now writes dest->prio and set_thread_stid_prio() directly (no runlist mirror). unlock_pi restores me->base_prio in software and hardware STID up front, before releasing, so the BESTWAIT comparator reads the correct priority and cannot hide the unblocked holder behind a stale boosted value. Spec-mandated synchronization ----------------------------- switch.ref.S adds isync after STID writes (V85 spec: "After updating the STID, an isync instruction must be executed to ensure that the new STID value is fully observed"). This is a correctness requirement, not removable overhead -- and the change is still faster overall (see below). CLUSTER_SCHED guards -------------------- Convert every `#ifdef CLUSTER_SCHED` to `#if CLUSTER_SCHED` so the single `#define CLUSTER_SCHED 0/1` in h2_common_defs.h actually gates the cluster/coproc code. Behavior is identical to the previously-tested build: the cluster paths were already runtime-gated by `cluster`sched == 0`, so compiling them out changes nothing observable. H2K_ready_head reduces to returning the ready-list head; getbest's sleep branch reduces to `return NULL`. Performance (futex/pi TOTAL TEST TIME, pcycles) ----------------------------------------------- ARCHV before (SW) after (HW) delta 68 1,813,302 1,731,697 -81,605 (-4.5%) 73 1,833,006 1,765,404 -67,602 (-3.7%) 81 1,968,943 1,889,073 -79,870 (-4.1%) Faster on every arch despite the added spec-mandated isyncs, from removing per-schedule software work: the runlist_worst_prio() walk, priomask bookkeeping, H2K_lowprio_notify, and the mirror writes. Follow-ups (not in this change) ------------------------------- * Rewrite the opt *.Svariants to the pure-BESTWAIT model; TARGET=opt failures are expected until then. * Research whether wait_mask is still needed for cluster scheduling; if not, drop it and its write sites in resched/intpool/popup/switch.ref.S/setup. Signed-off-by: Zeev Belinsky --- kernel/CMakeLists.txt | 1 - kernel/bugs | 14 -- kernel/build/offsets/offsets.ref.c | 2 +- .../checker_runlist/checker_runlist.check.c | 25 --- .../checker_runlist/checker_runlist.h | 14 -- kernel/checkers/checker_runlist/make.inc | 1 - kernel/data/globals/globals.h | 6 +- kernel/data/globals/globals.ref.c | 6 +- kernel/data/readylist/readylist.h | 31 ++- kernel/data/readylist/test/test.c | 4 +- kernel/data/runlist/make.inc | 1 - kernel/data/runlist/runlist.h | 41 ---- kernel/data/runlist/runlist.ref.c | 19 -- kernel/data/runlist/runlist.spec | 168 ---------------- kernel/data/runlist/test/Makefile | 13 -- kernel/data/runlist/test/Makefile.inc | 6 - kernel/data/runlist/test/test.c | 135 ------------- kernel/error/fatal/test/test.c | 2 - kernel/event/intpool/intpool.ref.c | 7 +- kernel/event/intpool/intpool.spec | 6 - kernel/event/intpool/test/Makefile | 4 - kernel/event/intpool/test/test.c | 10 - kernel/event/passthru/test/test.c | 3 - kernel/event/popup/popup.ref.c | 7 +- kernel/event/popup/popup.spec | 8 +- kernel/event/popup/test/Makefile | 4 - kernel/event/popup/test/test.c | 18 +- .../futex/futex/test/tests/multi_wake/main.c | 2 +- kernel/futex/futex/test/tests/pi/test.c | 45 ++++- .../futex/futex_classic/futex_classic.ref.c | 6 +- kernel/futex/futex_classic/futex_classic.spec | 4 - kernel/futex/futex_common/futex_common.ref.c | 2 +- kernel/futex/futex_pi/futex_pi.ref.c | 16 +- kernel/init/boot/boot.ref.S | 5 +- kernel/init/setup/setup.ref.c | 8 +- kernel/init/setup/setup.spec | 6 +- kernel/init/setup/test/test.c | 2 - kernel/sched/check_sanity/check_sanity.ref.c | 36 ---- kernel/sched/check_sanity/check_sanity.spec | 5 - .../test/tests/H2K_bestwait/test.c | 136 +++++++------ .../test/tests/H2K_check_sanity/Makefile | 6 - .../test/tests/H2K_check_sanity/Makefile.inc | 3 - .../tests/H2K_check_sanity/scenarios/Makefile | 23 --- .../H2K_check_sanity/scenarios/Makefile.inc | 6 - .../H2K_check_sanity/scenarios/scenarios.py | 100 ---------- .../tests/H2K_check_sanity/scenarios/test.c | 182 ------------------ kernel/sched/check_sanity/test/tests/Makefile | 2 +- kernel/sched/dosched/dosched.ref.c | 13 +- kernel/sched/dosched/dosched.spec | 34 +--- kernel/sched/dosched/test/test/Makefile | 4 - kernel/sched/dosched/test/test/harness.c | 16 +- kernel/sched/lowprio/lowprio.h | 38 ---- kernel/sched/lowprio/lowprio.ref.c | 14 -- kernel/sched/lowprio/lowprio.spec | 106 ---------- kernel/sched/lowprio/make.inc | 1 - kernel/sched/lowprio/test/Makefile | 14 -- kernel/sched/lowprio/test/Makefile.inc | 7 - kernel/sched/lowprio/test/test.c | 69 ------- kernel/sched/resched/resched.ref.c | 8 +- kernel/sched/resched/resched.spec | 7 +- kernel/sched/resched/test/Makefile | 3 - kernel/sched/resched/test/test.c | 21 +- kernel/sched/switch/switch.ref.S | 20 +- kernel/sched/switch/switch.spec | 11 +- kernel/sched/yield/test/Makefile | 4 - kernel/sched/yield/test/test.c | 13 +- kernel/sched/yield/yield.ref.c | 5 - kernel/sched/yield/yield.spec | 15 +- kernel/thread/create/create.ref.c | 8 +- kernel/thread/create/create.spec | 5 +- kernel/thread/create/test/Makefile | 4 - kernel/thread/create/test/test.c | 76 +------- kernel/thread/stop/stop.ref.c | 1 - kernel/thread/stop/stop.spec | 12 +- kernel/thread/stop/test/Makefile | 4 - kernel/thread/stop/test/test.c | 9 +- kernel/todo | 3 - kernel/traps/config/config.h | 2 +- kernel/traps/config/config.ref.c | 6 +- kernel/traps/hwconfig/hwconfig.ref.c | 13 +- kernel/traps/info/info.ref.c | 2 +- kernel/traps/prio/prio.ref.c | 3 +- kernel/traps/prio/test/test.c | 6 +- kernel/util/hw/hw.h | 2 - kernel/util/max/max.h | 2 +- kernel/util/stmode/test/test.c | 7 +- kernel/vm/vmcache/vmcache.ref.c | 1 - kernel/vm/vmfuncs/vmfuncs.ref.c | 1 - kernel/vm/vmint/test/test.c | 31 --- kernel/vm/vmint/vmint.ref.c | 3 +- kernel/vm/vmmap/vmmap.ref.c | 1 - kernel/vm/vmop/test/test.c | 3 - kernel/vm/vmop/vmop.ref.c | 6 +- kernel/vm/vmwork/vmwork.spec | 4 +- libs/h2/common/h2_common_config.h | 2 +- libs/h2/config/h2_config.h | 2 +- libs/h2/config/h2_config_imp.ref.c | 2 +- scripts/testlist.v4 | 1 - scripts/testlist.v61 | 7 +- 99 files changed, 280 insertions(+), 1523 deletions(-) delete mode 100644 kernel/checkers/checker_runlist/checker_runlist.check.c delete mode 100644 kernel/checkers/checker_runlist/checker_runlist.h delete mode 100644 kernel/checkers/checker_runlist/make.inc delete mode 100644 kernel/data/runlist/make.inc delete mode 100644 kernel/data/runlist/runlist.h delete mode 100644 kernel/data/runlist/runlist.ref.c delete mode 100644 kernel/data/runlist/runlist.spec delete mode 100644 kernel/data/runlist/test/Makefile delete mode 100644 kernel/data/runlist/test/Makefile.inc delete mode 100644 kernel/data/runlist/test/test.c delete mode 100644 kernel/sched/check_sanity/check_sanity.ref.c delete mode 100644 kernel/sched/check_sanity/test/tests/H2K_check_sanity/Makefile delete mode 100644 kernel/sched/check_sanity/test/tests/H2K_check_sanity/Makefile.inc delete mode 100644 kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/Makefile delete mode 100644 kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/Makefile.inc delete mode 100644 kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/scenarios.py delete mode 100644 kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c delete mode 100644 kernel/sched/lowprio/lowprio.h delete mode 100644 kernel/sched/lowprio/lowprio.ref.c delete mode 100644 kernel/sched/lowprio/lowprio.spec delete mode 100644 kernel/sched/lowprio/make.inc delete mode 100644 kernel/sched/lowprio/test/Makefile delete mode 100644 kernel/sched/lowprio/test/Makefile.inc delete mode 100644 kernel/sched/lowprio/test/test.c diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt index c0419e77c..290aea40b 100644 --- a/kernel/CMakeLists.txt +++ b/kernel/CMakeLists.txt @@ -16,7 +16,6 @@ set( "data/readylist/readylist.ref.c" "data/intconfig/intconfig.ref.c" "data/stacks/stacks.ref.S" - "data/runlist/runlist.ref.c" "data/globals/globals.ref.c" "data/context/context.v${ARCHV}opt.S" "data/vm/vm.ref.c" diff --git a/kernel/bugs b/kernel/bugs index 742485038..ca7b3a401 100644 --- a/kernel/bugs +++ b/kernel/bugs @@ -37,17 +37,3 @@ Other specing / assertions * For every data element in a struct, spec where it should be updated * Add collection of assertions that we can check on function entry/exit * Add structure verifier that can make sure structures are sane - - - -runlist valid states -==================== - -An empty runlist is apparently not a valid state; should probably -document this in the spec and maybe make an assertion. - - - - - - diff --git a/kernel/build/offsets/offsets.ref.c b/kernel/build/offsets/offsets.ref.c index 4c4864c6a..ad1f9336f 100644 --- a/kernel/build/offsets/offsets.ref.c +++ b/kernel/build/offsets/offsets.ref.c @@ -119,7 +119,7 @@ int main(int argc, char **argv) PRINT_KG_OFFSET(hthreads_mask); PRINT_KG_OFFSET(hthreads); -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED PRINT_KG_OFFSET(cluster_clusters); PRINT_KG_OFFSET(cluster_hthreads); PRINT_KG_OFFSET(cluster_mask); diff --git a/kernel/checkers/checker_runlist/checker_runlist.check.c b/kernel/checkers/checker_runlist/checker_runlist.check.c deleted file mode 100644 index 499bbe69f..000000000 --- a/kernel/checkers/checker_runlist/checker_runlist.check.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#include -#include -#include -#include -#include -#include - -s32_t checker_runlist() -{ - u32_t i; - for (i = 0; i < H2K_gp->hthreads; i++) { - if (0 <= H2K_gp->runlist_prios[i] && H2K_gp->runlist_prios[i] <= MAX_READY_PRIO) { - if (H2K_gp->runlist_prios[i] != H2K_gp->runlist[i]->prio) FAIL("runlist_prios does not match priority of scheduled thread"); - } else { - if (H2K_gp->runlist[i]) FAIL("Priority out of range but readylist non-null"); - } - } - return 1; -} - diff --git a/kernel/checkers/checker_runlist/checker_runlist.h b/kernel/checkers/checker_runlist/checker_runlist.h deleted file mode 100644 index 7b08593f0..000000000 --- a/kernel/checkers/checker_runlist/checker_runlist.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#ifndef H2K_CHECKER_RUNLIST_H -#define H2K_CHECKER_RUNLIST_H 1 - -#include - -s32_t checker_runlist(); - -#endif - diff --git a/kernel/checkers/checker_runlist/make.inc b/kernel/checkers/checker_runlist/make.inc deleted file mode 100644 index d00f59119..000000000 --- a/kernel/checkers/checker_runlist/make.inc +++ /dev/null @@ -1 +0,0 @@ -include $(MAKE_INC_DEFAULT) diff --git a/kernel/data/globals/globals.h b/kernel/data/globals/globals.h index e95a3adb8..df3b20b2c 100644 --- a/kernel/data/globals/globals.h +++ b/kernel/data/globals/globals.h @@ -97,7 +97,7 @@ typedef struct { pa_t gpio_reg; #endif -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED u32_t cluster_clusters; // number of clusters u32_t cluster_hthreads; // hardware threads per cluster u32_t cluster_mask[4]; // bitmask of threads in cluster @@ -146,8 +146,6 @@ typedef struct { #endif H2K_thread_context *runlist[MAX_HTHREADS]; s16_t runlist_prios[(MAX_HTHREADS+7)/8*8] __attribute__((aligned(8))); - H2K_thread_context *wip_dummy_runlist[MAX_HTHREADS]; - s16_t wip_dummy_runlist_prios[(MAX_HTHREADS+7)/8*8] __attribute__((aligned(8))); H2K_vmblock_t *vmblocks[H2K_ID_MAX_VMS]; u32_t phys_offset; u32_t build_id; @@ -218,7 +216,7 @@ static inline H2K_kg_t PURITY *H2K_gp_llvm() #undef PURITY #endif -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED static inline u32_t H2K_hthread_cluster(u32_t hthread) { return (hthread / H2K_gp->cluster_hthreads); diff --git a/kernel/data/globals/globals.ref.c b/kernel/data/globals/globals.ref.c index aec8c54c6..a6d9cc49d 100644 --- a/kernel/data/globals/globals.ref.c +++ b/kernel/data/globals/globals.ref.c @@ -69,7 +69,7 @@ void H2K_kg_init(u32_t phys_offset, u32_t multicore_shift, u32_t devpage_offset, have_hvx = (H2K_cfg_table(CFG_TABLE_COPROC_TYPE) & CFG_TABLE_COPROC_TYPE_HVX_MASK) != 0; have_silver = (H2K_cfg_table(CFG_TABLE_COPROC_TYPE) & CFG_TABLE_COPROC_TYPE_SILVER_MASK) != 0; H2K_kg.coproc_contexts = (have_hvx || have_silver ? H2K_cfg_table(CFG_TABLE_COPROC_CONTEXTS) : 0); -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED /* FIXME: need a cfg_table entry for this */ H2K_kg.cluster_clusters = (u32_t)(Q6_R_popcount_P(H2K_cfg_table(CFG_TABLE_HTHREADS_MASK)) > 8 ? 4 : 2); // hack H2K_kg.cluster_hthreads = (u32_t)(Q6_R_popcount_P(H2K_cfg_table(CFG_TABLE_HTHREADS_MASK)) / H2K_kg.cluster_clusters); @@ -144,7 +144,7 @@ void H2K_kg_init(u32_t phys_offset, u32_t multicore_shift, u32_t devpage_offset, H2K_kg.hmx_units = (H2K_cfg_table(CFG_TABLE_HMX_INT8_RATE) != 0); // exists? H2K_kg.info_boot_flags.boot_have_hmx = (H2K_kg.hmx_units > 0); #endif -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED H2K_kg.coproc_max_save = ((H2K_kg.coproc_contexts + H2K_kg.hmx_units) / H2K_kg.cluster_clusters) + (((H2K_kg.coproc_contexts + H2K_kg.hmx_units) % H2K_kg.cluster_clusters) != 0); H2K_kg.coproc_max_save = (H2K_kg.coproc_max < CLUSTER_SCHED_MIN_COPROCS ? CLUSTER_SCHED_MIN_COPROCS : H2K_kg.coproc_max); #endif @@ -230,7 +230,7 @@ void H2K_kg_init(u32_t phys_offset, u32_t multicore_shift, u32_t devpage_offset, } -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED void H2K_cluster_config(void) { u32_t i; diff --git a/kernel/data/readylist/readylist.h b/kernel/data/readylist/readylist.h index 145f3d806..01f9d4f94 100644 --- a/kernel/data/readylist/readylist.h +++ b/kernel/data/readylist/readylist.h @@ -13,7 +13,6 @@ #include #include #include -#include /* Get the best ready priority */ static inline u32_t H2K_ready_best_prio() @@ -86,7 +85,29 @@ static inline void H2K_ready_remove(H2K_thread_context *thread) if (H2K_gp->ready[prio] == NULL) H2K_ready_clear_prio(prio); } -#ifdef CLUSTER_SCHED +static inline void H2K_ready_append_arm(H2K_thread_context *thread) +{ + H2K_ready_append(thread); + H2K_set_bestwait(H2K_ready_best_prio()); +} + +/* Take the thread and place it in the ready structure, + * the first thread to be scheduled at its priority */ +static inline void H2K_ready_insert_arm(H2K_thread_context *thread) +{ + H2K_ready_insert(thread); + H2K_set_bestwait(H2K_ready_best_prio()); +} + +/* Remove a specific thread from the ready list */ +/* The caller guarantees that the thread is actually in the ready list correctly */ +static inline void H2K_ready_remove_arm(H2K_thread_context *thread) +{ + H2K_ready_remove(thread); + H2K_set_bestwait(H2K_ready_best_prio()); +} + +#if CLUSTER_SCHED static inline void H2K_update_coprocs(u32_t hthread, u32_t hthread_xe, u32_t hthread_xe2, u32_t hthread_xe3,u32_t head_xe, u32_t head_xe2, u32_t head_xe3) { xex(hthread, head_xe, head_xe2, head_xe3, hthread_xe, hthread_xe2, hthread_xe3); if (hthread_xe) { @@ -123,7 +144,7 @@ static inline void H2K_update_coprocs(u32_t hthread, u32_t hthread_xe, u32_t hth static inline H2K_thread_context *H2K_ready_head(u32_t prio, u32_t hthread) { H2K_thread_context *head = H2K_gp->ready[prio]; -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED if ((!H2K_gp->cluster_sched) || H2K_gp->coproc_max == -1) { return head; } @@ -223,7 +244,7 @@ static inline H2K_thread_context *H2K_ready_getbest(u32_t hthread) H2K_log("hthread %d getbest\n", hthread); prio = H2K_ready_best_prio(); if (prio >= MAX_PRIOS) { // !H2K_ready_any_valid(), go to sleep -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED if (!H2K_gp->cluster_sched) { return NULL; } @@ -246,7 +267,7 @@ static inline H2K_thread_context *H2K_ready_getbest(u32_t hthread) ret = H2K_ready_head(prio, hthread); if (ret != NULL) { - H2K_ready_remove(ret); + H2K_ready_remove_arm(ret); } return ret; } diff --git a/kernel/data/readylist/test/test.c b/kernel/data/readylist/test/test.c index 4a2945fc0..9c4e34284 100644 --- a/kernel/data/readylist/test/test.c +++ b/kernel/data/readylist/test/test.c @@ -90,7 +90,7 @@ H2K_thread_context *H2K_ready_getbest_TB() return H2K_ready_getbest(CURRENT_HTHREAD); } -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED void H2K_ready_REG_SSR_XE_CLEAR_TB() { H2K_set_ssr(H2K_get_ssr() & ~SSR_XE_BIT_MASK); @@ -230,7 +230,7 @@ __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); if (H2K_ready_getbest_TB() != &c) FAIL("ready_best_prio failed (c) "); if (H2K_ready_getbest_TB() != NULL) FAIL("ready_best_prio failed (empty) "); -# ifdef CLUSTER_SCHED +# if CLUSTER_SCHED u32_t hthreadmask = H2K_cfg_table(CFG_TABLE_HTHREADS_MASK); u32_t hthreads = (u32_t)Q6_R_popcount_P(hthreadmask); diff --git a/kernel/data/runlist/make.inc b/kernel/data/runlist/make.inc deleted file mode 100644 index d00f59119..000000000 --- a/kernel/data/runlist/make.inc +++ /dev/null @@ -1 +0,0 @@ -include $(MAKE_INC_DEFAULT) diff --git a/kernel/data/runlist/runlist.h b/kernel/data/runlist/runlist.h deleted file mode 100644 index ace6dc5d7..000000000 --- a/kernel/data/runlist/runlist.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#ifndef RUNLIST_H -#define RUNLIST_H 1 - -#include -#include -#include -#include -#include -#include - -static inline void H2K_runlist_push(H2K_thread_context *newthread) -{ - u32_t hthread = newthread->hthread; - u32_t prio = newthread->prio; - newthread->status = H2K_STATUS_RUNNING; - H2K_gp->wip_dummy_runlist[hthread] = newthread; - H2K_gp->wip_dummy_runlist_prios[hthread] = (s16_t)prio; -} - -static inline void H2K_runlist_remove(H2K_thread_context *thread) -{ - u32_t hthread = thread->hthread; - H2K_gp->wip_dummy_runlist[hthread] = NULL; - H2K_gp->wip_dummy_runlist_prios[hthread] = -1; -} - -static inline void H2K_runlist_set_thread_prio(H2K_thread_context *thread, u32_t new_prio) -{ - thread->prio = (u8_t)new_prio; - H2K_gp->wip_dummy_runlist_prios[thread->hthread] = (s16_t)new_prio; -} - -void H2K_runlist_init(void) IN_SECTION(".text.init.runlist"); - -#endif - diff --git a/kernel/data/runlist/runlist.ref.c b/kernel/data/runlist/runlist.ref.c deleted file mode 100644 index d402d3fd5..000000000 --- a/kernel/data/runlist/runlist.ref.c +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#include - -void H2K_runlist_init(void) -{ - u32_t i; - for (i = 0; i < sizeof(H2K_gp->runlist_prios)/sizeof(H2K_gp->runlist_prios[0]); i++) { -#ifdef TESTING - if (i < H2K_gp->hthreads) { - H2K_gp->runlist[i] = NULL; - } -#endif - H2K_gp->runlist_prios[i] = -1; - } -} diff --git a/kernel/data/runlist/runlist.spec b/kernel/data/runlist/runlist.spec deleted file mode 100644 index b89f6444a..000000000 --- a/kernel/data/runlist/runlist.spec +++ /dev/null @@ -1,168 +0,0 @@ - -:mod:`runlist` -- managing the currently-running threads -======================================================== - -.. module:: runlist - -runlist and runlist_prios --------------------------- - -The ready list contains the threads that are currently running - -The requirements for the run list are: - -* O(1) insertions of any priority -* O(1) removals of the lowest priority -* Very fast detection of the lowest priority running thread - -We acheive this by using an array of linked lists of threads running at a given -priority, and a bitmask that has a bit set for each non-empty linked list. - -We insert a thread into the run list by adding the thread to the list at the -priority corresponding to the thread, and setting the corresponding bit. - -We find the lowest priority running thread by using the CL0 instruction to find -the lowest priority that has a running thread. We then can remove the thread in -the corresponding list. - -TBD: This datastructure is scalable to any number of hardware threads. It may -be preferable to have an array of the currently running thread on each hardware -thread, and find the minimum by inspecting each value. - - -H2K_runlist_init ----------------- - -.. c:function:: void H2K_runlist_init() - -Description -~~~~~~~~~~~ - -Initializes the :c:data:`H2K_kg.runlist` and :c:data:`H2K_kg.runlist_prios` -structures. - -Functionality -~~~~~~~~~~~~~ - -Set all elements of :c:data:`H2K_kg.runlist` to NULL, set all elements of -:c:data:`H2K_kg.runlist_prios` to -1. - - -H2K_runlist_push ----------------- - -.. c:function:: static inline void H2K_runlist_push(H2K_thread_context *newthread) - - :param newthread: Thread to add to the runlist - -Description -~~~~~~~~~~~ - -Inserts a thread into the runlist. - -Functionality -~~~~~~~~~~~~~ - -Set newthread's status to running, add newthread to the runlist, and add newthread's -priority to runlist_prios. - - -H2K_runlist_worst_prio ----------------------- - -.. c:function:: static inline u32_t H2K_runlist_worst_prio() - - :returns: the priority of the worst priority running thread. Returns - MAX_PRIOS or higher if no threads are in the runlist. - -Description -~~~~~~~~~~~ - -Returns the priority corresponding to the running thread with the worst priority. -Returns MAX_PRIOS or higher if no threads are in the runlist. - -Functionality -~~~~~~~~~~~~~ - -We iterate through the hardware threads to find the one with the worst priority -and return its priority. - - -H2K_runlist_worst_prio_hthread ------------------------------- - -.. c:function:: static inline u32_t H2K_runlist_worst_prio_hthread() - - :returns: the hardware thread number of the worst priority running thread. - Returns -1 if no threads are in the runlist. - -Description -~~~~~~~~~~~ - -Returns the priority corresponding to the running thread with the worst priority. -Returns MAX_PRIOS or higher if no threads are in the runlist. - -Functionality -~~~~~~~~~~~~~ - -We iterate through the hardware threads to find the one with the worst priority -and return its priority. - - -H2K_runlist_remove ------------------- - -.. c:function:: static inline void H2K_runlist_remove(H2K_thread_context *thread) - - :param thread: the thread to remove from the runlist - -Description -~~~~~~~~~~~ - -Removes ``thread`` from the runlist. By calling this function, you guarantee -that the thread is in the runlist. - -Functionality -~~~~~~~~~~~~~ - -We set runlist to NULL and runlist_prios to -1 for thread's hthread. - - - - - -Testing -------- - -Samples -~~~~~~~ - -* Input: H2K_kg.runlist array -* Input: H2K_kg.runlist_prios array -* Thread to push/remove -* Output: H2K_runlist_worst_prio: Priority of worst running thread -* Output: H2K_ready_array / H2K_ready_valids for remove/push - - -Important Cases -~~~~~~~~~~~~~~~ - -* H2K_runlist_worst_prio and H2K_runlist_worst_prio_hthread when the runlist is empty -* H2K_runlist_worst_prio and H2K_runlist_worst_prio_hthread when the runlist has - different threads in it - -* H2K_runlist_push should set H2K_kg.runlist and H2K_kg.runlist_prios appropriately. - -* H2K_runlist_remove should set H2K_kg.runlist to NULL and H2K_kg.runlist_prios to an - invalid priority. - -* Check H2K_runlist_init clears out randomized values. - -Harness -~~~~~~~ - -The runlist module is reasonably self-contained, so the test harness will only -use the header file and object file. - - - diff --git a/kernel/data/runlist/test/Makefile b/kernel/data/runlist/test/Makefile deleted file mode 100644 index 0e061956f..000000000 --- a/kernel/data/runlist/test/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -STANDALONE=1 - -OBJS+=test.o -RECOMPILE_DIRS += $(H2DIR)/kernel/data/runlist -RECOMPILE_SRCS_PREFS += runlist - -EXTRA_CFLAGS += -DTESTING -EXTRA_ASFLAGS += -DTESTING - -EXEC=test.elf - -include Makefile.inc -OSLIB= diff --git a/kernel/data/runlist/test/Makefile.inc b/kernel/data/runlist/test/Makefile.inc deleted file mode 100644 index 9d275c989..000000000 --- a/kernel/data/runlist/test/Makefile.inc +++ /dev/null @@ -1,6 +0,0 @@ -# Need to define how to get back to the main H2 dir -H2DIR=${UPDIR}../../../.. - -# Everything else defined here -include ${H2DIR}/scripts/Makefile.inc.test - diff --git a/kernel/data/runlist/test/test.c b/kernel/data/runlist/test/test.c deleted file mode 100644 index 20dfdcac4..000000000 --- a/kernel/data/runlist/test/test.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -void FAIL(const char *str) -{ - puts("FAIL"); - puts(str); - exit(1); -} - -static H2K_thread_context a,b,c; -static u32_t hthread_mask; - -/* Create real versions of inlined functions */ - -s32_t H2K_runlist_worst_prio_TB() -{ - return H2K_runlist_worst_prio(); -} - -s32_t H2K_runlist_worst_prio_hthread_TB() -{ - return H2K_runlist_worst_prio_hthread(); -} - -void H2K_runlist_push_TB(H2K_thread_context *thread) -{ - H2K_runlist_push(thread); - hthread_mask |= (0x1 << thread->hthread); -} - -void H2K_runlist_remove_TB(H2K_thread_context *thread) -{ - H2K_runlist_remove(thread); - hthread_mask &= ~(0x1 << thread->hthread); -} - -void H2K_runlist_set_thread_prio_TB(H2K_thread_context *thread, u32_t new_prio) -{ - H2K_runlist_set_thread_prio(thread, new_prio); -} - -u32_t H2K_runlist_worst_prio_hthread_OK() -{ - s32_t hthread = H2K_runlist_worst_prio_hthread_TB(); - s32_t prio = H2K_runlist_worst_prio_TB(); - if (prio < 0 || prio > MAX_PRIO) { - return hthread < 0 || hthread > H2K_gp->hthreads; - } - return H2K_gp->runlist[hthread] != NULL && H2K_gp->runlist[hthread]->prio == prio; -} - -int main() -{ - __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); - hthread_mask = 0; - H2K_gp->hthreads = 0; - if (H2K_runlist_worst_prio_TB() <= MAX_PRIO) FAIL("hthreads-off runlist worst prio in [0,MAX_PRIO]"); - H2K_gp->runlist[0] = &a; - H2K_gp->hthreads = get_hthreads(); - H2K_runlist_init(); - if (H2K_gp->runlist[0] != 0) FAIL("runlist_init failed to clear array"); - if (0 <= H2K_gp->runlist_prios[1] && H2K_gp->runlist_prios[1] <= MAX_PRIO) FAIL("runlist_init failed to clear prios"); - if (H2K_runlist_worst_prio_TB() <= MAX_PRIO) FAIL("cleared runlist worst prio in [0,MAX_PRIO]"); - if (!H2K_runlist_worst_prio_hthread_OK()) FAIL("cleared runlist worst prio hthread in [0,H2K_gp->hthreads)"); - - b.prio = a.prio = 2; - c.prio = 3; - a.hthread = 0; - b.hthread = 1; - c.hthread = 2; - - H2K_runlist_push_TB(&c); - H2K_runlist_remove_TB(&c); - u32_t hthreads_none = hthread_mask; - if (hthreads_none != 0) FAIL("runlist push-remove combo failed"); - - H2K_runlist_push_TB(&a); - if (H2K_gp->runlist[0] != &a) FAIL("runlist_push failed (0)"); - if (H2K_gp->runlist_prios[0] != 2) FAIL("runlist_push failed (1)"); - if (H2K_runlist_worst_prio_TB() != 2) FAIL("runlist_worst_prio failed (3)"); - if (!H2K_runlist_worst_prio_hthread_OK()) FAIL("runlist_worst_prio_hthread failed (30)"); - - H2K_runlist_push_TB(&b); - if (H2K_gp->runlist[1] != &b) FAIL("runlist_push failed (4)"); - if (H2K_gp->runlist_prios[1] != 2) FAIL("runlist_push failed (5)"); - if (H2K_runlist_worst_prio_TB() != 2) FAIL("runlist_worst_prio failed (7)"); - if (!H2K_runlist_worst_prio_hthread_OK()) FAIL("runlist_worst_prio_hthread failed (31)"); - - H2K_runlist_push_TB(&c); - if (H2K_runlist_worst_prio_TB() != 3) FAIL("runlist_worst_prio (8)"); - if (!H2K_runlist_worst_prio_hthread_OK()) FAIL("runlist_worst_prio_hthread failed (32)"); - - H2K_runlist_set_thread_prio_TB(&a, 5); - if (a.prio != 5) FAIL("runlist_set_thread_prio failed (40)"); - if (H2K_gp->runlist_prios[0] != 5) FAIL("runlist_set_thread_prio failed (41)"); - if (H2K_runlist_worst_prio_TB() != 5) FAIL("runlist_set_thread_prio worst_prio (42)"); - if (!H2K_runlist_worst_prio_hthread_OK()) FAIL("runlist_set_thread_prio_hthread (43)"); - - H2K_runlist_set_thread_prio_TB(&a, 2); - if (a.prio != 2) FAIL("runlist_set_thread_prio failed (44)"); - if (H2K_gp->runlist_prios[0] != 2) FAIL("runlist_set_thread_prio failed (45)"); - if (H2K_runlist_worst_prio_TB() != 3) FAIL("runlist_set_thread_prio worst_prio (46)"); - if (!H2K_runlist_worst_prio_hthread_OK()) FAIL("runlist_set_thread_prio_hthread (47)"); - - H2K_runlist_remove_TB(&a); - H2K_runlist_remove_TB(&c); - if (H2K_gp->runlist[0] != NULL) FAIL("runlist_remove failed (9)"); - if (H2K_gp->runlist[1] != &b) FAIL("runlist_remove failed (10)"); - if (H2K_gp->runlist[2] != NULL) FAIL("runlist_remove failed (11)"); - if (H2K_gp->runlist_prios[1] != 2) FAIL("runlist_remove failed (12)"); - if (0 <= H2K_gp->runlist_prios[2] && H2K_gp->runlist_prios[2] <= MAX_PRIO) FAIL("runlist_remove failed (13)"); - if (H2K_runlist_worst_prio_TB() != 2) FAIL("runlist_worst_prio (17)"); - if (!H2K_runlist_worst_prio_hthread_OK()) FAIL("runlist_worst_prio_hthread failed (33)"); - - H2K_runlist_remove_TB(&b); - if (H2K_gp->runlist[1] != NULL) FAIL("runlist_remove failed (18)"); - if (0 <= H2K_gp->runlist_prios[1] && H2K_gp->runlist_prios[1] <= MAX_PRIO) FAIL("runlist_remove failed (19)"); - if (H2K_runlist_worst_prio_TB() <= MAX_PRIO) FAIL("runlist_worst_prio (21)"); - - puts("TEST PASSED\n"); - return 0; -} - diff --git a/kernel/error/fatal/test/test.c b/kernel/error/fatal/test/test.c index 300960712..ef8680f0e 100644 --- a/kernel/error/fatal/test/test.c +++ b/kernel/error/fatal/test/test.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/kernel/event/intpool/intpool.ref.c b/kernel/event/intpool/intpool.ref.c index 1d1a77d05..fbd2fb161 100644 --- a/kernel/event/intpool/intpool.ref.c +++ b/kernel/event/intpool/intpool.ref.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -35,11 +34,13 @@ void H2K_intpool_int(u32_t intnum, H2K_thread_context *me, u32_t hwtnum, H2K_vmb H2K_ring_remove(&vmblock->intpool,woken); woken->r00 = intnum; if (me != NULL) { - H2K_ready_append(me); + H2K_ready_append_arm(me); } else { +#if CLUSTER_SCHED H2K_gp->wait_mask = (u32_t)Q6_R_clrbit_RR(H2K_gp->wait_mask,hwtnum); +#endif } - H2K_runlist_push(woken); + woken->status = H2K_STATUS_RUNNING; H2K_switch(me,woken); } diff --git a/kernel/event/intpool/intpool.spec b/kernel/event/intpool/intpool.spec index e6dc955fe..0e20f6400 100644 --- a/kernel/event/intpool/intpool.spec +++ b/kernel/event/intpool/intpool.spec @@ -34,12 +34,6 @@ If we soft pend the interrupt, we are done. If a thread was interrupted, we unschedule it and put it in the ready queue. Otherwise, the thread was idle, and so we mark ourselves as no longer idle. -We clear the low-priority status of the current thread, change our IMASK -appropriately, and place the woken thread directly into the runlist and switch -to it. This is speculative; the woken thread may not be higher priority than -the interrupted thread. However we expect this to be likely, and if it is incorrect -it will be remedied by :c:func:`H2K_check_sanity()`. - Note that we do not re-enable the interrupt at this time. The interrupt is only re-enabled when a thread explicitly calls to enable the interrupt, or waits with the int_ack field set to a valid interrupt. By keeping the interrupt disabled, diff --git a/kernel/event/intpool/test/Makefile b/kernel/event/intpool/test/Makefile index d5b84e2a9..c993ab28b 100644 --- a/kernel/event/intpool/test/Makefile +++ b/kernel/event/intpool/test/Makefile @@ -1,12 +1,8 @@ STANDALONE=1 OBJS+=test.o -RECOMPILE_DIRS += $(H2DIR)/kernel/data/runlist RECOMPILE_DIRS += $(H2DIR)/kernel/data/readylist -RECOMPILE_DIRS += $(H2DIR)/kernel/sched/lowprio -RECOMPILE_SRCS_PREFS += runlist RECOMPILE_SRCS_PREFS += readylist -RECOMPILE_SRCS_PREFS += lowprio EXTRA_CFLAGS += -DTESTING EXTRA_ASFLAGS += -DTESTING diff --git a/kernel/event/intpool/test/test.c b/kernel/event/intpool/test/test.c index 44e6fb6e1..209d315ff 100644 --- a/kernel/event/intpool/test/test.c +++ b/kernel/event/intpool/test/test.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include #include @@ -15,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -266,19 +263,16 @@ int main() #if ARCHV >= 4 if (i == 31) continue; #endif - H2K_runlist_push(&a); TH_clear_intpool(); if (TH_call_intpool_wait(i,&a) != 0) { FAIL("Couldn't wait"); } TH_check_waiting(i,&a); - H2K_runlist_push(&b); if (TH_call_intpool_wait(i,&b) != 0) { FAIL("Couldn't set second thread"); } TH_clear_intpool(); //TH_check_running(i,&b); - //H2K_runlist_remove(&b); } /* @@ -351,7 +345,6 @@ int main() } /* Case B: VMWORK alone -- gate must fire and return -1 without INTBLOCKED */ - H2K_runlist_push(&a); a.status = H2K_STATUS_RUNNING; a.vmstatus = H2K_VMSTATUS_VMWORK; TH_saw_do_work = 0; @@ -359,10 +352,8 @@ int main() if (!TH_saw_do_work) FAIL("B: VMWORK alone must call vm_do_work"); if (a.status == H2K_STATUS_INTBLOCKED) FAIL("B: must not set INTBLOCKED"); a.vmstatus = 0; - H2K_runlist_remove(&a); /* Case C: VMWORK|KILL -- killed thread racing into intpool_wait */ - H2K_runlist_push(&a); a.status = H2K_STATUS_RUNNING; a.vmstatus = H2K_VMSTATUS_VMWORK | H2K_VMSTATUS_KILL; TH_saw_do_work = 0; @@ -370,7 +361,6 @@ int main() if (!TH_saw_do_work) FAIL("C: VMWORK|KILL must call vm_do_work"); if (a.status == H2K_STATUS_INTBLOCKED) FAIL("C: must not set INTBLOCKED"); a.vmstatus = 0; - H2K_runlist_remove(&a); puts("TEST PASSED\n"); return 0; diff --git a/kernel/event/passthru/test/test.c b/kernel/event/passthru/test/test.c index 69559dbf7..79bd8c4c8 100644 --- a/kernel/event/passthru/test/test.c +++ b/kernel/event/passthru/test/test.c @@ -6,15 +6,12 @@ #include #include #include -#include -#include #include #include #include #include #include #include -#include #include #include #include diff --git a/kernel/event/popup/popup.ref.c b/kernel/event/popup/popup.ref.c index ecfe1e260..ea1d6b23e 100644 --- a/kernel/event/popup/popup.ref.c +++ b/kernel/event/popup/popup.ref.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -27,11 +26,13 @@ void H2K_popup_int(u32_t intnum, H2K_thread_context *me, u32_t hwtnum, H2K_threa return; } if (me != NULL) { - H2K_ready_append(me); + H2K_ready_append_arm(me); } else { +#if CLUSTER_SCHED H2K_gp->wait_mask = (u32_t)Q6_R_clrbit_RR(H2K_gp->wait_mask,hwtnum); +#endif } - H2K_runlist_push(woken); + woken->status = H2K_STATUS_RUNNING; H2K_switch(me,woken); } diff --git a/kernel/event/popup/popup.spec b/kernel/event/popup/popup.spec index ecf63077b..b9405bf40 100644 --- a/kernel/event/popup/popup.spec +++ b/kernel/event/popup/popup.spec @@ -31,12 +31,6 @@ If the popup thread is NULL, we merely unlock and return. If a thread was interrupted, we unschedule it and put it in the ready queue. Otherwise, the thread was idle, and so we mark ourselves as no longer idle. -We clear the low-priority status of the current thread, change our IMASK -appropriately, and place the woken thread directly into the runlist and switch -to it. This is speculative; the woken thread may not be higher priority than -the interrupted thread. However we expect this to be likely, and if it is incorrect -it will be remedied by :c:func:`H2K_check_sanity()`. - Note that we do not re-enable the interrupt at this time. The interrupt is only re-enabled when the thread blocks waiting for another interrupt. By keeping the interrupt disabled, we allow it to pend while the popup thread executes. @@ -73,7 +67,7 @@ return error. Set the interrupt handler to popup_int, and the extra interrupt argument to the thread context. -Do the work of blocking: take the thread out of the runlist, mark it as BLOCKED, and +Do the work of blocking: mark thread's state as BLOCKED, and set the return value to a successful return of the interrupt. Finally, enable the interrupt and select a new thread to schedule. diff --git a/kernel/event/popup/test/Makefile b/kernel/event/popup/test/Makefile index 32407b341..d27ac4f24 100644 --- a/kernel/event/popup/test/Makefile +++ b/kernel/event/popup/test/Makefile @@ -1,12 +1,8 @@ STANDALONE=1 OBJS+=test.o -RECOMPILE_DIRS += $(H2DIR)/kernel/data/runlist RECOMPILE_DIRS += $(H2DIR)/kernel/data/readylist -RECOMPILE_DIRS += $(H2DIR)/kernel/sched/lowprio -RECOMPILE_SRCS_PREFS += runlist RECOMPILE_SRCS_PREFS += readylist -RECOMPILE_SRCS_PREFS += lowprio EXTRA_CFLAGS += -DTESTING EXTRA_ASFLAGS += -DTESTING diff --git a/kernel/event/popup/test/test.c b/kernel/event/popup/test/test.c index e87a6e66c..4453acd7b 100644 --- a/kernel/event/popup/test/test.c +++ b/kernel/event/popup/test/test.c @@ -6,15 +6,12 @@ #include #include #include -#include -#include #include #include #include #include #include #include -#include #include #include #include @@ -187,7 +184,9 @@ void TH_popup_int(int i, H2K_thread_context *interrupted, int hthread, H2K_threa */ void TH_set_idle(int hthread) { +#if CLUSTER_SCHED H2K_gp->wait_mask = 1<wait_mask &= ~(1<wait_mask) FAIL("wait_mask still set"); +#endif if ((get_imask(thread->hthread)) != 0) FAIL("IMASK set for hthread"); } @@ -271,19 +274,16 @@ int main() #if ARCHV >= 4 if (L2_CORE_INTERRUPT == i) continue; #endif - H2K_runlist_push(&a); TH_clear_popups(); if (TH_call_popup_wait(i,&a) != 0) { FAIL("Couldn't wait"); } TH_check_waiting(i,&a); - H2K_runlist_push(&b); if (TH_call_popup_wait(i,&b) == 0) { FAIL("Set popup for int twice"); } TH_clear_popups(); TH_check_running(i,&b); - H2K_runlist_remove(&b); } for (i = 0; i < MAX_INTERRUPTS; i++) { @@ -311,7 +311,6 @@ int main() TH_clear_ready(&a); } /* Case B: VMWORK alone -- gate must fire and return -1 without INTBLOCKED */ - H2K_runlist_push(&a); a.status = H2K_STATUS_RUNNING; a.vmstatus = H2K_VMSTATUS_VMWORK; TH_saw_do_work = 0; @@ -319,10 +318,8 @@ int main() if (!TH_saw_do_work) FAIL("B: VMWORK alone must call vm_do_work"); if (a.status == H2K_STATUS_INTBLOCKED) FAIL("B: must not set INTBLOCKED"); a.vmstatus = 0; - H2K_runlist_remove(&a); /* Case C: VMWORK|KILL -- killed thread racing into popup_wait */ - H2K_runlist_push(&a); a.status = H2K_STATUS_RUNNING; a.vmstatus = H2K_VMSTATUS_VMWORK | H2K_VMSTATUS_KILL; TH_saw_do_work = 0; @@ -330,7 +327,6 @@ int main() if (!TH_saw_do_work) FAIL("C: VMWORK|KILL must call vm_do_work"); if (a.status == H2K_STATUS_INTBLOCKED) FAIL("C: must not set INTBLOCKED"); a.vmstatus = 0; - H2K_runlist_remove(&a); /* popup_cancel: thread was waiting on interrupt i; cancel must clear the * handler slot and reset r00 to -1. */ @@ -341,7 +337,6 @@ int main() if (i == L2_CORE_INTERRUPT) continue; #endif TH_clear_popups(); - H2K_runlist_push(&a); /* Simulate the state popup_wait leaves: INTBLOCKED, r00=intnum, handler set */ a.status = H2K_STATUS_INTBLOCKED; a.r0100 = i; @@ -354,7 +349,6 @@ int main() if (H2K_gp->inthandlers[i].raw != 0) FAIL("cancel: handler not cleared"); if (a.r00 != (u32_t)-1) FAIL("cancel: r00 not reset"); - H2K_runlist_remove(&a); } } diff --git a/kernel/futex/futex/test/tests/multi_wake/main.c b/kernel/futex/futex/test/tests/multi_wake/main.c index d9c74bf58..535c63d34 100644 --- a/kernel/futex/futex/test/tests/multi_wake/main.c +++ b/kernel/futex/futex/test/tests/multi_wake/main.c @@ -221,7 +221,7 @@ void vmmain(void *unused) /* Figure out the max priority that can be woken up */ k = nr_to_wake; - for (j=0; j> 16) == j) { k--; diff --git a/kernel/futex/futex/test/tests/pi/test.c b/kernel/futex/futex/test/tests/pi/test.c index 96ac4a0f1..6c7a5ebc2 100644 --- a/kernel/futex/futex/test/tests/pi/test.c +++ b/kernel/futex/futex/test/tests/pi/test.c @@ -56,6 +56,26 @@ volatile int TH_shutdown_now = 0; volatile int TH_done = 0; volatile int TH_caller_woke = 0; +typedef struct { + u64_t start; + u64_t end; +} cycle_timer_t; + +static void timer_start(cycle_timer_t *t) +{ + t->start = h2_get_core_pcycles(); +} + +static void timer_end(cycle_timer_t *t) +{ + t->end = h2_get_core_pcycles(); +} + +static u64_t timer_elapsed(cycle_timer_t *t) +{ + return t->end - t->start; +} + #define info(...) { h2_printf("INFO: "); h2_printf(__VA_ARGS__);} #define warn(...) { h2_printf("WARNING: "); h2_printf(__VA_ARGS__);} #define debug(...) { h2_printf("DEBUG: "); h2_printf(__VA_ARGS__);} @@ -173,6 +193,7 @@ void spawn_pi_caller(int tnum, int prio, int *futex_addr) int main(int argc, char **argv) { + cycle_timer_t total_timer, phase_timer; h2_handle_errors(0); futex1 = futex0 = h2_thread_myid(); @@ -183,7 +204,10 @@ int main(int argc, char **argv) h2_sem_init_val(&blocker2.sem,0); info("main() starting\n"); + timer_start(&total_timer); + /* Start up two low priority spinner threads */ + timer_start(&phase_timer); spawn_spinner(0,31); spawn_spinner(1,30); /* Start up a blocking spinner */ @@ -191,6 +215,8 @@ int main(int argc, char **argv) spawn_blocker(2,29,&blocker); blocker2.threadid = 3; spawn_blocker(3,28,&blocker2); + timer_end(&phase_timer); + info("Phase: Initial thread spawn - %llu cycles\n", timer_elapsed(&phase_timer)); /* Check spin status */ if (!still_spinning(&spinner_arr[0])) FAIL("t0 not spinning"); @@ -199,15 +225,18 @@ int main(int argc, char **argv) if (still_spinning(&spinner_arr[3])) FAIL("t3 spinning"); /* Priority inherit blocked thread */ + timer_start(&phase_timer); futex0 = thread_ids[2]; spawn_pi_caller(4,4,&futex0); /* Priority inherit running thread */ futex1 = thread_ids[1]; spawn_pi_caller(5,5,&futex1); + timer_end(&phase_timer); + info("Phase: Priority inherit setup - %llu cycles\n", timer_elapsed(&phase_timer)); /* Generate middlish spinners */ - + timer_start(&phase_timer); spawn_spinner(8,16); spawn_spinner(9,16); spawn_spinner(10,16); @@ -240,11 +269,13 @@ int main(int argc, char **argv) spawn_spinner(37,16); spawn_spinner(38,16); spawn_spinner(39,16); + timer_end(&phase_timer); + info("Phase: Middle spinners spawn - %llu cycles\n", timer_elapsed(&phase_timer)); info("Middle Spinners Launched\n"); /* Check that previous priority inheritance worked */ - + timer_start(&phase_timer); if (still_spinning(&spinner_arr[0])) FAIL("t0 spinning"); if (!still_spinning(&spinner_arr[1])) FAIL("t1 not spinning"); if (still_spinning(&spinner_arr[2])) FAIL("t2 spinning"); @@ -260,7 +291,7 @@ int main(int argc, char **argv) wait(1000); if (!still_spinning(&spinner_arr[2])) FAIL("t2 not spinning"); if (still_spinning(&spinner_arr[3])) FAIL("t3 spinning"); - + info("Blocked thread inherited OK, shutting down that test thread\n"); /* EJP: Add extra test case: additional blocked thread in same bin */ @@ -277,11 +308,14 @@ int main(int argc, char **argv) if (!still_spinning(&spinner_arr[0])) FAIL("t0 not spinning"); info("Waiting thread inherited OK, going to next step (handoff)\n"); + timer_end(&phase_timer); + info("Phase: Priority inheritance tests - %llu cycles\n", timer_elapsed(&phase_timer)); TH_shutdown_now = 0; TH_expected_futex_wakeup_thread = thread_ids[4]; TH_expected_futex_wakeup_val = FUTEX_PASS; + timer_start(&phase_timer); TH_nextstep_id = thread_ids[0]; while (TH_nextstep_id != 0) /* SPIN */; @@ -314,6 +348,11 @@ int main(int argc, char **argv) h2_sem_up(&blocker2.sem); TH_shutdown_now = 1; TH_done = 1; + timer_end(&phase_timer); + info("Phase: Futex unlock/handoff - %llu cycles\n", timer_elapsed(&phase_timer)); + + timer_end(&total_timer); + info("TOTAL TEST TIME: %llu cycles\n", timer_elapsed(&total_timer)); puts("TEST PASSED"); exit(0); } diff --git a/kernel/futex/futex_classic/futex_classic.ref.c b/kernel/futex/futex_classic/futex_classic.ref.c index ea11bd614..e34fa4f2f 100644 --- a/kernel/futex/futex_classic/futex_classic.ref.c +++ b/kernel/futex/futex_classic/futex_classic.ref.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -15,7 +14,6 @@ #include #include #include -#include #include #include @@ -86,6 +84,8 @@ s32_t H2K_futex_resume(u32_t *lock, u32_t n_to_wake, H2K_thread_context *me) break; } } while (n_woken < n_to_wake); - return (s32_t)H2K_check_sanity_unlock(n_woken); + + BKL_UNLOCK(); + return (s32_t)n_woken; } diff --git a/kernel/futex/futex_classic/futex_classic.spec b/kernel/futex/futex_classic/futex_classic.spec index eeb54433d..b56074886 100644 --- a/kernel/futex/futex_classic/futex_classic.spec +++ b/kernel/futex/futex_classic/futex_classic.spec @@ -102,7 +102,3 @@ Matching threads, up to n_to_wake, are removed from the futex hash bucket and added to the ready queue. Threads have their `status` field modified to be `H2K_STATUS_READY`. -Finally, we sibcall to :c:func:`H2K_check_sanity_unlock()`, asking it to return -the number of woken threads. - - diff --git a/kernel/futex/futex_common/futex_common.ref.c b/kernel/futex/futex_common/futex_common.ref.c index d1898bef6..7f5d53831 100644 --- a/kernel/futex/futex_common/futex_common.ref.c +++ b/kernel/futex/futex_common/futex_common.ref.c @@ -57,7 +57,7 @@ H2K_thread_context *H2K_futex_hash_remove_one(u32_t locklo, H2K_thread_context * if (cur->futex_ptr_lo == locklo) { tmp = cur->next; H2K_ring_remove(ring,cur); - H2K_ready_append(cur); + H2K_ready_append_arm(cur); *pos = tmp; return cur; } else { diff --git a/kernel/futex/futex_pi/futex_pi.ref.c b/kernel/futex/futex_pi/futex_pi.ref.c index 2ac273ceb..66375b234 100644 --- a/kernel/futex/futex_pi/futex_pi.ref.c +++ b/kernel/futex/futex_pi/futex_pi.ref.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -15,7 +14,6 @@ #include #include #include -#include #include #include @@ -41,9 +39,7 @@ static inline void H2K_futex_pi_raise(u32_t prio, H2K_id_t destid) dest->prio = (u8_t)prio; H2K_ready_insert(dest); } else if (dest->status == H2K_STATUS_RUNNING) { - H2K_runlist_set_thread_prio(dest, prio); - /* Sync hardware STID.PRIO so BESTWAIT sees the boosted priority - * immediately -- avoids spurious preemption of the holder. */ + dest->prio = (u8_t)prio; set_thread_stid_prio(dest->hthread, prio); /* Need to update lowprio */ } else if (dest->status == H2K_STATUS_INTBLOCKED) { @@ -119,6 +115,8 @@ s32_t H2K_futex_unlock_pi(u32_t *lock, H2K_thread_context *me) hashval = FUTEX_HASHVAL(pa); ring = &H2K_gp->futexhash[hashval]; pos = *ring; + me->prio = me->base_prio; + set_thread_stid_prio(me->hthread, me->base_prio); /* FIXME: pass full PA when supported */ ret = H2K_futex_hash_remove_one((u32_t)pa,ring,&pos); if (ret == NULL) { @@ -129,10 +127,6 @@ s32_t H2K_futex_unlock_pi(u32_t *lock, H2K_thread_context *me) H2K_atomic_swap(lock,H2K_id_from_context(ret).raw+1); } H2K_safemem_unlock(); - /* Restore priority in software and hardware atomically -- BESTWAIT - * comparator reads STID.PRIO; without the hardware sync the stale - * boosted value hides me from the comparator causing a priority inversion. */ - H2K_runlist_set_thread_prio(me, me->base_prio); - set_thread_stid_prio(me->hthread, me->base_prio); - return (s32_t)H2K_check_sanity_unlock(0); + BKL_UNLOCK(); + return 0; } diff --git a/kernel/init/boot/boot.ref.S b/kernel/init/boot/boot.ref.S index ebc68ef25..db07f165d 100644 --- a/kernel/init/boot/boot.ref.S +++ b/kernel/init/boot/boot.ref.S @@ -348,9 +348,8 @@ boot_continuation: SETCONST(H2K_GP,H2K_kg) /* Set up rising edge triggered */ - TMP = #0 - /* Set imask to -1, since we are not lowest priority at boot */ - /* (other idle threads) */ + /* Set imask to 0, enabling hardware interrupt steering */ + TMP = #0 imask = TMP TMP = #-1 #if ARCHV < 65 diff --git a/kernel/init/setup/setup.ref.c b/kernel/init/setup/setup.ref.c index c86d19d10..6ce261d37 100644 --- a/kernel/init/setup/setup.ref.c +++ b/kernel/init/setup/setup.ref.c @@ -5,12 +5,10 @@ #include #include -#include #include #include #include #include -#include #include #include #include @@ -93,7 +91,9 @@ IN_SECTION(".text.init.setup") static H2K_vmblock_t *H2K_init_setup(u32_t multic H2K_tcm_copy(last_tlb_index); H2K_trace_init(); H2K_readylist_init(); +#if CLUSTER_SCHED H2K_gp->wait_mask = 0; +#endif H2K_futex_init(); H2K_intconfig_init(ssbase); H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); @@ -223,10 +223,10 @@ IN_SECTION(".text.init.boot") void H2K_thread_boot(u32_t multicore_shift, u32_t #endif -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED H2K_cluster_config(); #endif - H2K_runlist_push(boot); //removing this will make kernel/time/timer/test_h2 to fail + boot->status = H2K_STATUS_RUNNING; H2K_mutex_unlock_tlb(); H2K_switch(NULL,boot); } diff --git a/kernel/init/setup/setup.spec b/kernel/init/setup/setup.spec index 4804809c2..680b88cd3 100644 --- a/kernel/init/setup/setup.spec +++ b/kernel/init/setup/setup.spec @@ -22,7 +22,6 @@ The :c:func:`H2K_init_setup()` function initializes kernel state at boot time. This function calls other initialization functions: * :c:func:`H2K_ready_init()` -* :c:func:`H2K_runlist_init()` * :c:func:`H2K_lowprio_init()` * :c:func:`H2K_futex_init()` * :c:func:`H2K_intconfig_init()` @@ -47,9 +46,8 @@ Next, we set up the boot thread context. Specifically: * Continuation should point to :c:func:`H2K_interrupt_restore()` * Trapmask should be initialized to all 1's. -Once we have set up the boot thread context and placed it into the runlist, we -switch to the thread. This will cause the kernel to go to the continuation -function, and will end up at qdsp6_pre_main, in crt0. +Once we have set up the boot thread context, we switch to the thread. +This will cause the kernel to go to the continuation function, and will end up at qdsp6_pre_main, in crt0. Testing ------- diff --git a/kernel/init/setup/test/test.c b/kernel/init/setup/test/test.c index 5ecc8363d..2106c671c 100644 --- a/kernel/init/setup/test/test.c +++ b/kernel/init/setup/test/test.c @@ -7,9 +7,7 @@ #include #include #include -#include #include -#include #include #include #include diff --git a/kernel/sched/check_sanity/check_sanity.ref.c b/kernel/sched/check_sanity/check_sanity.ref.c deleted file mode 100644 index a22ecb30c..000000000 --- a/kernel/sched/check_sanity/check_sanity.ref.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -u64_t H2K_check_sanity(const u64_t retval) -{ - u32_t best = H2K_ready_best_prio(); - H2K_set_bestwait(best); // This is blind for waiting thread- with prio -1, ie 255, and ready thread with prio 255- This won't fire an interrupt - - if (H2K_get_bestwait() == BESTWAIT_MASK) { //bestwait fired - return(retval); - } - - if (H2K_gp->wait_mask && best < MAX_PRIOS) { //We reach here only if ready thread's prio is 255. If it was 254 bestwait see waiting's prio 255 > 254 and fires. - resched_int(); - } - return(retval); -} - -u64_t H2K_check_sanity_unlock(const u64_t retval) -{ - call(H2K_check_sanity,retval); - BKL_UNLOCK(); - return(retval); -} diff --git a/kernel/sched/check_sanity/check_sanity.spec b/kernel/sched/check_sanity/check_sanity.spec index 439e4c2de..3e9727524 100644 --- a/kernel/sched/check_sanity/check_sanity.spec +++ b/kernel/sched/check_sanity/check_sanity.spec @@ -104,7 +104,6 @@ Samples * input MAX_PRIOS number of priority levels available (default 256) * input MAX_HTHREADS number of hardware threads available (default 6) * input H2K_kg.ready_valids priorities with ready jobs -* input H2K_kg.runlist_prios priorities of currently running threads * input H2K_kg.waitmask indicates hardware threads which are in wait * output ipend shows interrupts pending (see H2K_resched_int()) * i/o H2K_kg.priomask indicates lowest priority mask (see H2K_lowprio_notify) @@ -117,10 +116,6 @@ Important cases * H2K_kg.waitmask == 0 * H2K_kg.waitmask != 0 -* MAX(H2K_kg.runlist_prios) > CL0(H2K_kg.ready_valids) -* MAX(H2K_kg.runlist_prios) <= CL0(H2K_kg.ready_valids) -* H2K_kg.priomask == 0 -* H2K_kg.priomask != 0 Harness diff --git a/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c b/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c index 205142c0c..befe4ca65 100644 --- a/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c +++ b/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c @@ -6,11 +6,8 @@ /* * bestwait_sim_check * ================== - * Demonstrates that the simulator (hexagon-sim + devsim_v81.cfg) does NOT model - * the BESTWAIT/SCHEDCFG hardware reschedule-interrupt comparator described in - * the V85 spec (80-V9418-400) section 6.5. * - * Per the spec: + * How it works: * - BESTWAIT holds the priority of the best task waiting to run. * - When the effective priority of ANY hardware thread (STID.PRIO) is worse * than BESTWAIT, the hardware raises the reschedule interrupt (the interrupt @@ -20,20 +17,18 @@ * * This test arranges the exact trigger condition and checks: * PART A: the BESTWAIT and SCHEDCFG registers can be read/written (storage). - * PART B: with the feature enabled and this thread's STID.PRIO made WORSE than - * BESTWAIT, the hardware raises RESCHED_INT and resets BESTWAIT. - * PART C: negative case - it does NOT fire when no thread is worse. + * PART B: negative case - it does NOT fire when no thread is worse. + * PART C: equal priorities - it does NOT fire when STID.PRIO equals BESTWAIT. * PART D: it does NOT fire when SCHEDCFG.EN=0 (the feature must be enabled, * which the boot path H2K_init_setup normally does). - * - * Result observed on the current sim: ALL PASS - the comparator IS modeled. - * (An earlier conclusion that it was not modeled was a measurement error: with - * interrupts enabled the posted RESCHED_INT is immediately taken and its IPEND - * bit auto-clears, so it reads back as 0. This test disables interrupts first.) + * PART E: hardware steering delivers RESCHED to a qualified thread whose + * RESCHED imask bit is clear (the boot/hw-steering model). This verifies + * that BESTWAIT fires again and is not stale by re-arming it and checking + * that the interrupt is posted again with IAD=0 and IPEND raising the + * RESCHED_INT_MASK bit. * * Interrupts are kept globally disabled (clear_gie) so that, if the interrupt - * is posted, it stays pending in IPEND for us to observe rather than being - * taken (which would auto-clear the IPEND bit per spec 6.1). + * is posted, it stays pending in IPEND for us to observe rather than being taken. */ #include @@ -42,9 +37,6 @@ #include #include -/* STID.PRIORITY is bits [23:16]; 0 = highest priority, 0xFF = lowest. */ -#define STID_PRIO_SHIFT 16 - static int failures; static void check(const char *what, int ok) @@ -56,7 +48,8 @@ static void check(const char *what, int ok) int main() { - u32_t bw, sc, ipend; + u32_t bw, sc, ipend, iad, best_ready; + u32_t hthread = get_hwtnum(); /* Keep interrupts globally disabled so a posted RESCHED_INT remains pending * in IPEND (taken interrupts auto-clear their IPEND bit; see spec 6.1). */ @@ -66,85 +59,87 @@ int main() puts("PART A: BESTWAIT / SCHEDCFG behave as readable/writable registers"); u32_t garbage_value = 0x123; H2K_set_bestwait(garbage_value); - asm volatile ("isync"); bw = H2K_get_bestwait(); + iad = H2K_get_iad(); + ipend = H2K_get_ipend(); + printf(" BESTWAIT: wrote 0x%x, read 0x%x\n", garbage_value, bw); + printf(" IPEND=0x%x (RESCHED bit %d), IAD=0x%x, BESTWAIT now 0x%x\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, iad, bw); check("BESTWAIT round-trips", bw == garbage_value); + check("IAD is 0", iad == 0); H2K_set_bestwait(BESTWAIT_MASK); sc = SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT); H2K_set_schedcfg(sc); - asm volatile ("isync"); printf(" SCHEDCFG: wrote 0x%x, read 0x%x\n", sc, H2K_get_schedcfg()); check("SCHEDCFG round-trips", H2K_get_schedcfg() == sc); - puts("PART B: hardware comparator should raise RESCHED_INT when a thread's " - "STID.PRIO is worse than BESTWAIT"); - - /* Make THIS thread look like the worst-priority running thread (prio 200). */ - asm volatile ("stid = %0; isync" : : "r"(200u << STID_PRIO_SHIFT)); - - /* Enable the feature and arm BESTWAIT with a BETTER priority (50). - * 200 (us) is worse than 50 (bestwait) -> the reg fires. */ - H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); - asm volatile ("isync"); - u32_t best_ready = 50; - H2K_set_bestwait(best_ready); - asm volatile ("isync"); - - ipend = H2K_get_ipend(); - bw = H2K_get_bestwait(); - printf(" armed: STID.PRIO=200, BESTWAIT=0x%x, SCHEDCFG.EN=1, INTNO=%d\n", - best_ready, RESCHED_INT); - printf(" IPEND=0x%x (RESCHED bit %d), BESTWAIT now 0x%x\n", - ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, bw); - - check("hardware posted RESCHED_INT into IPEND", - (ipend & RESCHED_INT_INTMASK) != 0); - check("hardware reset BESTWAIT to 0x1ff after firing", bw == BESTWAIT_MASK); - - puts("PART C: negative case - comparator must NOT fire when no thread is " + puts("PART B: negative case - comparator must NOT fire when no thread is " "worse than BESTWAIT"); /* Make this thread a GOOD priority (10) and arm BESTWAIT WORSE (50). * 10 (us) is better than 50 (bestwait) -> nothing is worse -> no fire. */ H2K_clear_ipend(0xffffffff); - asm volatile ("stid = %0; isync" : : "r"(10u << STID_PRIO_SHIFT)); + set_thread_stid_prio(hthread, 10); best_ready = 50; H2K_set_bestwait(best_ready); - asm volatile ("isync"); ipend = H2K_get_ipend(); + iad = H2K_get_iad(); bw = H2K_get_bestwait(); - printf(" armed: STID.PRIO=10, BESTWAIT=0x%x\n", best_ready); - printf(" IPEND=0x%x (RESCHED bit %d), BESTWAIT now 0x%x\n", - ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, bw); + printf(" state: STID.PRIO=10, BESTWAIT=0x%x\n", best_ready); + printf(" IPEND=0x%x (RESCHED bit %d), IAD=0x%x, BESTWAIT now 0x%x\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, iad, bw); check("comparator did NOT post RESCHED_INT (no thread worse)", (ipend & RESCHED_INT_INTMASK) == 0); + check("IAD is 0", iad == 0); check("BESTWAIT retained its value (not auto-reset)", bw == best_ready); + puts("PART C: equal priorities - comparator must NOT fire when STID.PRIO equals BESTWAIT"); + + /* Make this thread priority equal to BESTWAIT (50). + * 50 (us) is NOT worse than 50 (bestwait) -> no fire. */ + H2K_clear_ipend(0xffffffff); + set_thread_stid_prio(hthread, 50); + best_ready = 50; + H2K_set_bestwait(best_ready); + ipend = H2K_get_ipend(); + iad = H2K_get_iad(); + bw = H2K_get_bestwait(); + printf(" state: STID.PRIO=50, BESTWAIT=0x%x (equal priorities)\n", best_ready); + printf(" IPEND=0x%x (RESCHED bit %d), IAD=0x%x, BESTWAIT now 0x%x\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, iad, bw); + check("comparator did NOT fire when priorities are equal", + (ipend & RESCHED_INT_INTMASK) == 0); + check("IAD is 0", iad == 0); + check("BESTWAIT retained its value when equal", bw == best_ready); + puts("PART D: does the feature require SCHEDCFG.EN? (mimics the scenario " "unit test, which never calls H2K_init_setup and so never enables it)"); /* Clear only the EN bit (keep INTNO) to confirm EN specifically gates * the feature -- not just any SCHEDCFG write. */ - H2K_set_schedcfg(~SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); + sc = ~SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT); + H2K_set_schedcfg(sc); + printf(" SCHEDCFG: wrote 0x%x, read 0x%x\n", sc, H2K_get_schedcfg()); asm volatile ("isync"); H2K_clear_ipend(0xffffffff); - asm volatile ("stid = %0; isync" : : "r"(200u << STID_PRIO_SHIFT)); + set_thread_stid_prio(hthread, 200); best_ready = 50; H2K_set_bestwait(best_ready); - asm volatile ("isync"); ipend = H2K_get_ipend(); + iad = H2K_get_iad(); bw = H2K_get_bestwait(); printf(" SCHEDCFG=~EN|INTNO (EN=0, INTNO kept), STID.PRIO=200, BESTWAIT=50\n"); - printf(" IPEND=0x%x (RESCHED bit %d), BESTWAIT now 0x%x\n", - ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, bw); + printf(" IPEND=0x%x (RESCHED bit %d), IAD=0x%x, BESTWAIT now 0x%x\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, iad, bw); printf(" OBSERVATION: with EN=0, comparator fires=%d " "(if 0, SCHEDCFG.EN is REQUIRED)\n", (ipend & RESCHED_INT_INTMASK) ? 1 : 0); check("comparator does NOT fire when SCHEDCFG.EN=0", (ipend & RESCHED_INT_INTMASK) == 0); + check("IAD is 0", iad == 0); check("Bestwait retains its value (not auto-reset) when EN=0", bw == best_ready); puts("PART E: hardware steering delivers RESCHED to a qualified thread whose " @@ -155,23 +150,40 @@ int main() * than BESTWAIT. The hardware should steer RESCHED_INT to this thread and * post it in IPEND. Re-enable interrupts briefly is NOT done here (we keep * GIE off so the posted bit stays observable in IPEND). */ - H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); + sc = SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT); + H2K_set_schedcfg(sc); + printf(" SCHEDCFG: wrote 0x%x, read 0x%x\n", sc, H2K_get_schedcfg()); asm volatile ("isync"); iassignw(RESCHED_INT, 0); /* clear RESCHED imask bit on all threads */ H2K_clear_ipend(0xffffffff); - asm volatile ("stid = %0; isync" : : "r"(200u << STID_PRIO_SHIFT)); + set_thread_stid_prio(hthread, 200); best_ready = 50; H2K_set_bestwait(best_ready); - asm volatile ("isync"); ipend = H2K_get_ipend(); + iad = H2K_get_iad(); bw = H2K_get_bestwait(); - printf(" steered: RESCHED imask clear, STID.PRIO=200, BESTWAIT=0x%x -> " - "IPEND=0x%x (RESCHED %d)\n", - best_ready, ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0); + printf(" IPEND=0x%x (RESCHED bit %d), IAD=0x%x, BESTWAIT now 0x%x\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, iad, bw); check("RESCHED steered to this qualified thread", (ipend & RESCHED_INT_INTMASK) != 0); + check("IAD is 0", iad == 0); check("Bestwait retains its value (not auto-reset)", bw == BESTWAIT_MASK); + /* Re-arm BESTWAIT to verify it fires again (not stale) */ + H2K_clear_ipend(0xffffffff); + set_thread_stid_prio(hthread, 200); + best_ready = 50; + H2K_set_bestwait(best_ready); + ipend = H2K_get_ipend(); + iad = H2K_get_iad(); + bw = H2K_get_bestwait(); + printf(" IPEND=0x%x (RESCHED bit %d), IAD=0x%x, BESTWAIT now 0x%x\n", + ipend, (ipend & RESCHED_INT_INTMASK) ? 1 : 0, iad, bw); + check("BESTWAIT fires again (not stale)", (ipend & RESCHED_INT_INTMASK) != 0); + check("IAD is 0", iad == 0); + + + if (failures == 0) { puts("TEST PASSED"); return 0; diff --git a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/Makefile b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/Makefile deleted file mode 100644 index 12882e607..000000000 --- a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/Makefile +++ /dev/null @@ -1,6 +0,0 @@ - - -SUBDIRS += scenarios - -include Makefile.inc - diff --git a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/Makefile.inc b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/Makefile.inc deleted file mode 100644 index 148f7df95..000000000 --- a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ - -UPDIR := ../${UPDIR} -include ${UPDIR}/Makefile.inc diff --git a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/Makefile b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/Makefile deleted file mode 100644 index adff44fc9..000000000 --- a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -STANDALONE=1 - -OBJS+=test.o -RECOMPILE_DIRS += $(H2DIR)/kernel/data/runlist -RECOMPILE_DIRS += $(H2DIR)/kernel/data/readylist -RECOMPILE_DIRS += $(H2DIR)/kernel/sched/lowprio -RECOMPILE_SRCS_PREFS += runlist -RECOMPILE_SRCS_PREFS += readylist -RECOMPILE_SRCS_PREFS += lowprio - -EXTRA_CFLAGS += -DTESTING -EXTRA_ASFLAGS += -DTESTING - -EXEC=test.elf -PYTHON_GENERATOR_SCRIPT=scenarios.py -PYTHON_GENERATED_FILES=scenarios.h - -# Include the include makefile. -include Makefile.inc -CC += -I../../../include -ffixed-r28 - -# Empty out the OSLIB variable. -OSLIB= diff --git a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/Makefile.inc b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/Makefile.inc deleted file mode 100644 index 5e50a109a..000000000 --- a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/Makefile.inc +++ /dev/null @@ -1,6 +0,0 @@ -# Need to define how to get back to the main H2 dir -H2DIR=${UPDIR}../../../../../../.. - -# Everything else defined here -include ${H2DIR}/scripts/Makefile.inc.test - diff --git a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/scenarios.py b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/scenarios.py deleted file mode 100644 index e420ecab8..000000000 --- a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/scenarios.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. -# SPDX-License-Identifier: BSD-3-Clause-Clear - -import sys -import random - -NUM_SCENARIOS = 10000 -NUM_THREADS_IN_SCENARIOS = 12 # must match the C code -MAX_PRIOS = 256 # must match max.h - -# This script generates scenarios for H2K_check_sanity. The scenarios are in -# the form of an initializer for a C array of structs. The initializer is -# included in test.c. test.c uses the information in the struct to set up the -# state before entering H2K_check_sanity, and to check the results of -# H2K_check_sanity. -# -# For each scenario, we generate a list of threads, each with three properties, -# status (RUNNING, READY, or BLOCKED), hthread, and prio. There may be at most -# MAX_HTHREADS RUNNING threads, and each RUNNING thread must have a valid -# hthread. No two RUNNING threads may have the same hthread. -# -# -# We also generate whether the resched interrupt should be raised. - -with open('scenarios.h', 'w') as outfile: - random.seed(0) - MAX_HTHREADS_possibilities = (2, 3, 4, 6, 8) - - print('#if MAX_HTHREADS < %d' % min(MAX_HTHREADS_possibilities), file=outfile) - print('#error MAX_HTHREADS must be at least %d for this test.' % min(MAX_HTHREADS_possibilities), file=outfile) - print('#endif', file=outfile) - for MAX_HTHREADS in MAX_HTHREADS_possibilities: - print('#if MAX_HTHREADS >= ' + str(MAX_HTHREADS), file=outfile) - for i in range(NUM_SCENARIOS): - print('\t // status, hthread, prio', file=outfile) - # First we decide how many threads are RUNNING, READY, and BLOCKED. - num_running_threads = random.randrange(1, MAX_HTHREADS + 1) - num_ready_threads = random.randrange(NUM_THREADS_IN_SCENARIOS - num_running_threads + 1) - num_blocked_threads = NUM_THREADS_IN_SCENARIOS - num_running_threads - num_ready_threads - # Then we determine the hthread and prio of each RUNNING thread. - available_threads = list(range(MAX_HTHREADS)) - running_hthreads = [] - running_prios = [] - for thread_id in range(num_running_threads): - # For each RUNNING thread, we choose its hthread from the list of available hthreads. - hthread = random.choice(available_threads) - # Then we remove that hthread from the list of available hthreads so that no two - # RUNNING threads get assigned the same hthread. - available_threads.remove(hthread) - prio = random.randrange(MAX_PRIOS) - # We record the hthread and prio of each RUNNING thread in order to later compute - # the worst RUNNING prio. - running_hthreads.append(hthread) - running_prios.append(prio) - # We then print out the state of the RUNNING thread. - if thread_id == 0: - outfile.write('\t{{') - else: - outfile.write('\t ') - print('{ RUNNING, %2d, %8d },' % (hthread, prio), file=outfile) - # Next we determine the hthread and prio of each READY thread. We record the READY prio - # and best in order to later compute whether the resched interrupt should be raised. - best_ready_prio = MAX_PRIOS - for thread_id in range(num_ready_threads): - hthread = random.randrange(-5, 20) - prio = random.randrange(MAX_PRIOS) - if prio < best_ready_prio: - best_ready_prio = prio - # We then print out the state of the READY thread. - print('\t { READY, %2d, %8d },' % (hthread, prio), file=outfile) - # Next we determine the hthread and prio of each BLOCKED thread. - for thread_id in range(num_blocked_threads): - hthread = random.randrange(-5, 20) - prio = random.randrange(MAX_PRIOS) - # We then print out the state of the BLOCKED thread. - print('\t { BLOCKED, %2d, %8d },' % (hthread, prio), file=outfile) - print('\t },', file=outfile) - # Next we compute the list of RUNNING threads with the worst prio and the list of non-RUNNING hthreads. - worst_running_prio = max(running_prios) - worst_prio_running_threads = [] - non_running_threads = list(range(MAX_HTHREADS)) - for j in range(num_running_threads): - if running_prios[j] == worst_running_prio: - worst_prio_running_threads.append(running_hthreads[j]) - non_running_threads.remove(running_hthreads[j]) - # We then compute whether the resched interrupt should be raised. - should_resched = (worst_running_prio > best_ready_prio) - # Finally, we print out the remaining input and output state. - print('\t %d, // should_resched' % should_resched, file=outfile) - print('\t %d, // hthreads' % MAX_HTHREADS, file=outfile) - print('\t},', file=outfile) - print('#endif', file=outfile) - # We print one last scenario to terminate the array. - print(""" // status, hthread, prio - {{{ RUNNING, 0, 0 },""", file=outfile) - for i in range(1, NUM_THREADS_IN_SCENARIOS): - print('\t { BLOCKED, %2d, %8d },' % (i, i), file=outfile) - print(""" }, - 0, // should_resched - }""", file=outfile) diff --git a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c b/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c deleted file mode 100644 index 50e60e63c..000000000 --- a/kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios/test.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NUM_THREADS_IN_SCENARIOS 12 // must match the Python script - -enum status { - BLOCKED, - READY, - RUNNING -}; - -struct thread_state { - enum status status; - int hthread; - int prio; -}; - -struct scenario { - struct thread_state thread[NUM_THREADS_IN_SCENARIOS]; - int should_resched; - int hthreads; -}; - -static char *status_string[] = { - "BLOCKED", - "READY", - "RUNNING" -}; - -static int test_status_to_H2_status[] = { - H2K_STATUS_BLOCKED, - H2K_STATUS_READY, - H2K_STATUS_RUNNING -}; - -static H2K_thread_context threads[NUM_THREADS_IN_SCENARIOS]; - -/* Get the scenarios from scenarios.h. */ -static struct scenario scenarios[] = { -#include "scenarios.h" -}; - -/* Prints a scenario. */ -static void print_scenario(struct scenario *scenario) -{ - int num_threads = sizeof(threads) / sizeof(threads[0]); - int status; - int hthread; - int prio; - int i; - puts("Thread Status hthread prio"); - for (i = 0; i < num_threads; i++) { - status = scenario->thread[i].status; - hthread = scenario->thread[i].hthread; - prio = scenario->thread[i].prio; - printf("t%-5d %s %-7d %d\n", i, status_string[status], hthread, prio); - } - printf("should_resched = %d\n", scenario->should_resched); -} - -/* Indicates a failure. Prints the scenario that failed. */ -static void FAIL(const char *str, struct scenario *scenario) -{ - puts("FAIL"); - puts(str); - print_scenario(scenario); - exit(1); -} - -/* Checks if the resched interrupt was raised. */ -static int resched_requested(void) -{ - return (H2K_get_ipend() & RESCHED_INT_INTMASK) != 0; -} - -/* Sets up the state described by the scenario. */ -static void setup(struct scenario *scenario) -{ - int num_threads = sizeof(threads) / sizeof(threads[0]); - int status; - int hthread; - int prio; - int i; - int worst_running_prio = 0; /* 0 == best; track max over RUNNING threads */ - - H2K_clear_ipend(0xffffffff); - H2K_readylist_init(); - H2K_set_schedcfg(SCHEDCFG_EN | SCHEDCFG_INTNO(RESCHED_INT)); - for (i = 0; i < num_threads; i++) { - status = scenario->thread[i].status; - hthread = scenario->thread[i].hthread; - prio = scenario->thread[i].prio; - threads[i].status = test_status_to_H2_status[status]; - threads[i].hthread = hthread; - threads[i].prio = prio; - if (status == RUNNING) { - H2K_runlist_push(&threads[i]); - if (prio > worst_running_prio) - worst_running_prio = prio; - } else if (status == READY) { - H2K_ready_append(&threads[i]); - } - } - /* The BESTWAIT comparator reads each hw thread's REAL STID.PRIO (bits - * [23:16]), not the software runlist_prios[] array that H2K_runlist_push - * fills. This test runs on a single hw thread, so drive that thread's real - * STID.PRIO to the scenario's worst running priority -- the only running - * priority that affects the decision (hardware fires iff some thread's - * STID.PRIO is worse than BESTWAIT, i.e. worst_running > best_ready). - * - * The comparator is level-sensitive, so disarm BESTWAIT (0x1FF) BEFORE - * writing STID, otherwise a stale BESTWAIT left by the previous scenario - * would fire spuriously the instant we install a worse STID.PRIO. Clear - * IPEND last so setup() leaves a clean slate; only H2K_check_sanity (under - * test) should arm BESTWAIT and raise the interrupt. */ - H2K_set_bestwait(BESTWAIT_MASK); - asm volatile ("stid = %0;" : : "r"((u32_t)worst_running_prio << 16)); - H2K_clear_ipend(0xffffffff); -} - -/* Checks to see that H2K_check_sanity did its job, given the scenario. */ -static void check(struct scenario *scenario) -{ - if (scenario->should_resched && !resched_requested()) { - FAIL("failed to raise resched interrupt", scenario); - } - if (!scenario->should_resched && resched_requested()) { - FAIL("raised resched interrupt unnecessarily", scenario); - } -} - -static inline u64_t do_H2K_check_sanity(u64_t input) -{ - __asm__ __volatile__ (GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); - return H2K_check_sanity(input); -} - -static inline u64_t do_H2K_check_sanity_unlock(u64_t input) -{ - __asm__ __volatile__ (GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); - return H2K_check_sanity_unlock(input); -} - -/* Runs through the scenarios, setting them up and knocking them down. */ -int main() -{ - int num_scenarios = sizeof(scenarios) / sizeof(scenarios[0]); - int i; - - __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); - - H2K_gp->hthreads = get_hthreads(); - - H2K_clear_gie(); - for (i = 0; i < num_scenarios && scenarios[i].hthreads <= H2K_gp->hthreads; i++) { - setup(&scenarios[i]); - BKL_LOCK(); - call(do_H2K_check_sanity, rand()); - BKL_UNLOCK(); - check(&scenarios[i]); - - setup(&scenarios[i]); - BKL_LOCK(); - call(do_H2K_check_sanity_unlock, rand()); - check(&scenarios[i]); - } - puts("TEST PASSED\n"); - return 0; -} diff --git a/kernel/sched/check_sanity/test/tests/Makefile b/kernel/sched/check_sanity/test/tests/Makefile index e962c4afe..c477007bc 100644 --- a/kernel/sched/check_sanity/test/tests/Makefile +++ b/kernel/sched/check_sanity/test/tests/Makefile @@ -1,4 +1,4 @@ -SUBDIRS+=H2K_check_sanity +SUBDIRS+=H2K_bestwait include Makefile.inc diff --git a/kernel/sched/dosched/dosched.ref.c b/kernel/sched/dosched/dosched.ref.c index bcd3f8636..381d535b1 100644 --- a/kernel/sched/dosched/dosched.ref.c +++ b/kernel/sched/dosched/dosched.ref.c @@ -5,9 +5,7 @@ #include #include -#include #include -#include #include #include #include @@ -18,9 +16,6 @@ void H2K_dosched(H2K_thread_context *me,u32_t hthread) H2K_thread_context *new; new = H2K_ready_getbest(hthread); if (new == NULL) { - change_imask(hthread,0); //This is not needed actually. - // Thing is that if we dont put this here-it is not working, - // see comment next to H2K_runlist_push below. /* GO TO SLEEP */ /* FIXME: temporary ugly hack for broken 8.7+ compiler -- investigate * whether this is still needed and if a proper direct call can be @@ -29,16 +24,12 @@ void H2K_dosched(H2K_thread_context *me,u32_t hthread) "r1 = #0\n" "call H2K_switch\n" : : "r"(me)); - // H2K_switch(me,NULL); + // H2K_switch(me,NULL); /* EJP: should never get here! */ } new->hthread = (u8_t)hthread; - H2K_runlist_push(new); // This callsite hides inside it a race. - // If we delete the writes to the "dummy" arrays H2K_runlist_push- futex_pi test hangs. - // THere is no point in writing to the dummies, just for this callsit, - // All other callsites across the code are fine without H2K_runlist_push writing - // to the dummies, but this preserved for futex_pi test to pass. //if (new->vmstatus & H2K_VMSTATUS_VMWORK) H2K_vm_do_work(new); + new->status = H2K_STATUS_RUNNING; H2K_switch(me,new); /* EJP: should never get here! */ } diff --git a/kernel/sched/dosched/dosched.spec b/kernel/sched/dosched/dosched.spec index 55a63eab1..b01014089 100644 --- a/kernel/sched/dosched/dosched.spec +++ b/kernel/sched/dosched/dosched.spec @@ -34,32 +34,9 @@ The currently running thread must have already been removed from the list of running threads. First, we remove the best ready thread. If no ready thread is available, we -go to sleep: +go to sleep by switching from me to NULL - 0. If a running hthread is marked as lowest priority, it should be made non-lowprio - 1. We switch from me to NULL. - -Otherwise, if the waitmask is zero, and the priority of the new thread is worse than all the -other running threads, and the current hthread is not already marked as the lowprio thread, -we make ourselves the lowest priority thread: - - 0. Make the current lowprio thread non-lowprio - 1. The bit corresponding to the current hthread should be set in the priomask - 2. Our IMASK should change to be appropriate for the lowprio hthread. - -Otherwise, if the waitmask is nonzero, or the priority of the new thread is -better than all the other running threads, we check to see if we were marked as the -lowprio thread. If we were also marked as the lowprio hthread, we make ourselves non-lowprio: - - 0. Our IMASK should change to be appropriate for the non-lowprio thread. - 1. If the waitmask is zero, we should "notify" the new lowprio hthread. - -It is essential that we make ourselves non-lowprio here if appropriate, however it is NOT -essential that we find a lowprio hthread at this point. :c:func:`H2K_check_sanity()` will find a lowprio -hthread if priomask is zero. - -Finally, we set the new thread's hthread and add the new thread to the runlist -via :c:func:`H2K_runlist_push()`, and then switch to the thread by jumping to +Otherwise, we set the new thread's hthread, switch to the thread by jumping to :c:func:`H2K_switch()`, which does not return. Testing @@ -71,9 +48,6 @@ Samples * Input: me, which may or may not have a valid thread * Input: correct ready queue, which may or may not have ready threads -* I/O: runlist, which is updated if there is a new thread to schedule -* I/O: priomask, modified if new is NULL or the newly selected thread - is lowest priority (XXX: or if newly selected thread is non-lowprio?) * I/O: waitmask, modified if new is NULL Important cases @@ -85,10 +59,6 @@ Important cases * me is NULL * me is a valid thread -* We are the new lowest priority thread -* We are no longer the lowest priority thread -* We remain the lowest priority thread - * Other waiting threads * No other waiting threads diff --git a/kernel/sched/dosched/test/test/Makefile b/kernel/sched/dosched/test/test/Makefile index 8207cccd3..0fd1eeb2e 100644 --- a/kernel/sched/dosched/test/test/Makefile +++ b/kernel/sched/dosched/test/test/Makefile @@ -6,12 +6,8 @@ STANDALONE=1 # Hrm... check_sanity assertion stuff causing problems. Fix later. OBJS += harness.o -RECOMPILE_DIRS += $(H2DIR)/kernel/data/runlist RECOMPILE_DIRS += $(H2DIR)/kernel/data/readylist -RECOMPILE_DIRS += $(H2DIR)/kernel/sched/lowprio -RECOMPILE_SRCS_PREFS += runlist RECOMPILE_SRCS_PREFS += readylist -RECOMPILE_SRCS_PREFS += lowprio EXTRA_CFLAGS += -DTESTING EXTRA_ASFLAGS += -DTESTING diff --git a/kernel/sched/dosched/test/test/harness.c b/kernel/sched/dosched/test/test/harness.c index a58509819..28d8052c8 100644 --- a/kernel/sched/dosched/test/test/harness.c +++ b/kernel/sched/dosched/test/test/harness.c @@ -6,13 +6,10 @@ #include #include #include -#include #include #include -#include #include #include -#include #include #include @@ -56,7 +53,9 @@ void TB_reset() { TB_saw_switch = 0; H2K_readylist_init(); +#if CLUSTER_SCHED H2K_gp->wait_mask = 0; +#endif } void TB_setup_common() @@ -69,7 +68,6 @@ void TB_check_common() { if (TB_saw_switch == 0) FAIL("No switch?"); checker_ready(); - checker_runlist(); } /* Do call to dosched, longjmp can bring us back */ @@ -90,7 +88,6 @@ void TB_do_call() void TB_fiddle_prio_low_to_low(phase_t phase) { if (phase == SETUP) { - H2K_runlist_push(&h); H2K_ready_append(&m); TB_me = &l; } else { @@ -102,7 +99,6 @@ void TB_fiddle_prio_low_to_low(phase_t phase) void TB_fiddle_prio_low_to_high(phase_t phase) { if (phase == SETUP) { - H2K_runlist_push(&m); H2K_ready_append(&h); TB_me = &l; } else { @@ -114,7 +110,6 @@ void TB_fiddle_prio_low_to_high(phase_t phase) void TB_fiddle_prio_high_to_low(phase_t phase) { if (phase == SETUP) { - H2K_runlist_push(&m); H2K_ready_append(&l); TB_me = &h; } else { @@ -126,7 +121,6 @@ void TB_fiddle_prio_high_to_low(phase_t phase) void TB_fiddle_prio_high_to_high(phase_t phase) { if (phase == SETUP) { - H2K_runlist_push(&l); H2K_ready_append(&m); H2K_ready_append(&h); TB_me = &h; @@ -160,7 +154,6 @@ void TB_fiddle_prio_wait_to_high(phase_t phase) if (phase == SETUP) { /* Setup for call */ TB_me = NULL; - H2K_runlist_push(&l); H2K_ready_append(&h); } else { /* Check expected values */ @@ -174,7 +167,6 @@ void TB_fiddle_prio_wait_to_low(phase_t phase) if (phase == SETUP) { /* Setup for call */ TB_me = NULL; - H2K_runlist_push(&h); H2K_ready_append(&l); } else { /* Check expected values */ @@ -208,6 +200,7 @@ testsetup_t TB_fiddle_prio[] = { }; /* Set up or check wait mask */ +#if CLUSTER_SCHED void TB_fiddle_wait_mask_zero(phase_t phase) { if (phase == SETUP) { @@ -236,6 +229,7 @@ testsetup_t TB_fiddle_wait_mask[] = { TB_fiddle_wait_mask_nonzero, NULL }; +#endif H2K_kg_t H2K_kg; @@ -261,6 +255,7 @@ int main() h2.prio = 2; h2.hthread = 0; +#if CLUSTER_SCHED /* For each wait mask type... */ for (i = 0; TB_fiddle_wait_mask[i] != NULL; i++) { /* For each change type... */ @@ -283,6 +278,7 @@ int main() TB_fiddle_prio[j](CHECK); } } +#endif puts("TEST PASSED\n"); return 0; } diff --git a/kernel/sched/lowprio/lowprio.h b/kernel/sched/lowprio/lowprio.h deleted file mode 100644 index 430c0ee3d..000000000 --- a/kernel/sched/lowprio/lowprio.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#ifndef LOWPRIO_H -#define LOWPRIO_H 1 - -#include -#include -#include -#include - -/* Notify a low priority thread that it is the new lowest priority if necessary */ -/* H2K_gp->priomask should be non-zero */ -// static inline void H2K_lowprio_notify() -// { -// u32_t hthread; -// hthread = H2K_runlist_worst_prio_hthread(); -// H2K_gp->priomask |= 1<priomask; -// if (H2K_gp->wait_mask) return; // just a sanity check... should be an error -// H2K_gp->priomask = 0; -// change_imask((u32_t)Q6_R_ct0_R(mask),(u32_t)-1); -// } - -void H2K_lowprio_init() IN_SECTION(".text.init.lowprio"); - -#endif - diff --git a/kernel/sched/lowprio/lowprio.ref.c b/kernel/sched/lowprio/lowprio.ref.c deleted file mode 100644 index 5b1b2ac6a..000000000 --- a/kernel/sched/lowprio/lowprio.ref.c +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#include - -void H2K_lowprio_init() -{ -#ifdef TESTING - H2K_gp->wait_mask = 0; -#endif -} - diff --git a/kernel/sched/lowprio/lowprio.spec b/kernel/sched/lowprio/lowprio.spec deleted file mode 100644 index e3def878a..000000000 --- a/kernel/sched/lowprio/lowprio.spec +++ /dev/null @@ -1,106 +0,0 @@ - -:mod:`lowprio` -- managing the lowest priority thread -===================================================== - -.. module:: lowprio - -H2K_kg.wait_mask and H2K_kg.priomask ------------------------------------- - -These words describe the hardware threads that are waiting for an interrupt, -and the hardware thread or threads that are the lowest priority. - -H2K_lowprio_notify ------------------- - -.. c:function:: static inline void H2K_lowprio_notify() - -Description -~~~~~~~~~~~ - -:c:func:`H2K_lowprio_notify()` identifies a new thread to be the lowest-priority thread -for receiving interrupts, and takes action to make that thread be receptive to -interrupts. - -Functionality -~~~~~~~~~~~~~ - -We get the hardware thread number the worst priority running thread and use that to set -the :c:data:`H2K_kg.priomask` bit corresponding to the hardware thread and to call -change_imask(). - - -H2K_lowprio_raise ------------------ - -.. c:function:: static inline void H2K_lowprio_raise() - -Description -~~~~~~~~~~~ - -:c:func:`H2K_lowprio_raise()` takes the thread currently marked as lowest priority, and -modifies the state to indicate it is no longer lowest priority. - -Functionality -~~~~~~~~~~~~~ - -If :c:data:`H2K_kg.wait_mask` is nonzero, we return, as we should never mask interrupts on -a waiting thread. Otherwise, count the trailing zeros of :c:data:`H2K_kg.priomask`, which -yields the hardware thread that should no longer be the low priority thread. -We clear that bit from the :c:data:`H2K_kg.priomask` and call :c:func:`H2K_prio_change_high()` for -the hardware thread. - - -H2K_lowprio_raise ------------------ - -.. c:function:: static inline void H2K_lowprio_init() - -Description -~~~~~~~~~~~ - -:c:func:`H2K_lowprio_init()` initializes the data structures used by the lowprio facility. - -Functionality -~~~~~~~~~~~~~ - -Set :c:data:`H2K_kg.wait_mask` and :c:data:`H2K_kg.priomask` to zero. - - - -Testing -------- - - -Samples -~~~~~~~ - -* Input: runlist -* Input: :c:data:`H2K_kg.wait_mask` -* I/O: :c:data:`H2K_kg.priomask` -* Output: IMASK values - -Important Cases -~~~~~~~~~~~~~~~ - -* :c:data:`H2K_kg.wait_mask` == 0: H2K_lowprio_raise should have no effect - -Harness -~~~~~~~ - -H2 lib kernel will be built. - -Various threads at various priorities should be added to runlist. -The lowest priority thread in the runlist should be marked as lowprio. -H2K_lowprio_raise will be called, and the formerly lowest priority -hardware thread should have a modified IMASK and the :c:data:`H2K_kg.priomask` bit -should be configured to be non-receptive to most interrutps. - -H2K_lowprio_notify should then be called. If :c:data:`H2K_kg.wait_mask` is nonzero, the -lowest priority thread in the runlist should be selected, the corresponding bit -should be added to :c:data:`H2K_kg.priomask`, and the IMASK on the corresponding hardware -thread should be receptive to most interrupts. - -Also, check that H2K_lowprio_init initializes :c:data:`H2K_kg.wait_mask` and :c:data:`H2K_kg.priomask`. - - diff --git a/kernel/sched/lowprio/make.inc b/kernel/sched/lowprio/make.inc deleted file mode 100644 index d00f59119..000000000 --- a/kernel/sched/lowprio/make.inc +++ /dev/null @@ -1 +0,0 @@ -include $(MAKE_INC_DEFAULT) diff --git a/kernel/sched/lowprio/test/Makefile b/kernel/sched/lowprio/test/Makefile deleted file mode 100644 index 9a09b17be..000000000 --- a/kernel/sched/lowprio/test/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -INC_KERNEL=1 - -OBJS+=test.o -RECOMPILE_DIRS += $(H2DIR)/kernel/sched/lowprio -RECOMPILE_SRCS_PREFS += lowprio - -EXTRA_CFLAGS += -DTESTING -EXTRA_ASFLAGS += -DTESTING - -EXEC=test.elf - -include Makefile.inc - -CFLAGS+= -ffixed-r28 -O0 diff --git a/kernel/sched/lowprio/test/Makefile.inc b/kernel/sched/lowprio/test/Makefile.inc deleted file mode 100644 index d3a8c046c..000000000 --- a/kernel/sched/lowprio/test/Makefile.inc +++ /dev/null @@ -1,7 +0,0 @@ -# Need to define how to get back to the main H2 dir -H2DIR=${UPDIR}../../../.. - -# Everything else defined here -include ${H2DIR}/scripts/Makefile.inc.test - - diff --git a/kernel/sched/lowprio/test/test.c b/kernel/sched/lowprio/test/test.c deleted file mode 100644 index 00dd52f64..000000000 --- a/kernel/sched/lowprio/test/test.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. - * SPDX-License-Identifier: BSD-3-Clause-Clear - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void FAIL(const char *x) -{ - puts("FAIL"); - puts(x); - exit(1); -} - -void h2_init(); - -H2K_thread_context a,b; - -void H2K_lowprio_notify_TB() -{ - return H2K_lowprio_notify(); -} - -void H2K_raise_lowprio_TB() -{ - return H2K_raise_lowprio(); -} - -typedef void (*TB_func)(); - -TB_func notify = H2K_lowprio_notify_TB; -TB_func raise = H2K_raise_lowprio_TB; - -int main() -{ - int i; - __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); - for (i = 0; i < 1000; i++) { - h2_init(); - } - - a.prio = b.prio = 2; - a.hthread = b.hthread = 1; - if ((get_imask(1) & 1) != 0) FAIL("T1 should be idle at boot"); - - H2K_runlist_push(&a); - raise(); - if ((get_imask(1) & 1) != 0) FAIL("should not have raised if idle"); - H2K_gp->wait_mask = 0; - H2K_gp->priomask = 0x2; - raise(); - if ((get_imask(1) & 1) == 0) FAIL("should have raised T1"); - H2K_gp->priomask = 0; - H2K_gp->hthreads = 2; // so that H2K_runlist_worst_prio_hthread() will find t1 - notify(); - if ((get_imask(1) & 1) != 0) FAIL("should have notified T1"); - puts("TEST PASSED\n"); - return 0; -} - diff --git a/kernel/sched/resched/resched.ref.c b/kernel/sched/resched/resched.ref.c index 6437a28df..9932bfd12 100644 --- a/kernel/sched/resched/resched.ref.c +++ b/kernel/sched/resched/resched.ref.c @@ -6,22 +6,20 @@ #include #include #include -#include #include #include -#include #include #include #include static inline void resched(u32_t unused, H2K_thread_context *me, u32_t hwtnum) { if (me != NULL) { - H2K_runlist_remove(me); // This is kept for the same reason described - // in kernel/sched/dosched/dosched.ref.c at the H2K_rnulist_push callsite. - H2K_ready_append(me); + H2K_ready_append_arm(me); } else { /* Interrupted WAIT mode */ +#if CLUSTER_SCHED H2K_gp->wait_mask = Q6_R_clrbit_RR(H2K_gp->wait_mask,hwtnum); +#endif } H2K_dosched(me, hwtnum); } diff --git a/kernel/sched/resched/resched.spec b/kernel/sched/resched/resched.spec index 2cdc48cb1..9f21add85 100644 --- a/kernel/sched/resched/resched.spec +++ b/kernel/sched/resched/resched.spec @@ -40,7 +40,6 @@ Samples * input: Pointer to the current thread (or NULL) * input: Hardware Thread number -* input: If me != NULL, Runlist structure including me thread in the correct location * output: if me == NULL, clear the H2K_kg.wait_mask bit corresponding to the hardware thread number * i/o: if me != NULL, readylist structure will have me appended to it * Must call H2K_dosched when finished @@ -50,7 +49,7 @@ Important Cases * me == NULL, bit set in H2K_kg.wait_mask (bit must be cleared) * me == NULL, bit not set in H2K_kg.wait_mask (bit must stay cleared) -* me != NULL, thread must be removed from runlist and added to readylist +* me != NULL, thread must be added to readylist * All: must call H2K_dosched at end of routine Check to make sure continuation is set? @@ -63,8 +62,8 @@ H2 lib kernel will be built, and linked with the test harness. The test harness will define our own H2K_dosched(), to replace the function in the H2 kernel. It will set a flag indicating that it was called. -For each test, we initialize and set up the appropriate structures (runlist, -readylist, wait_mask, etc), and then call H2K_resched(). We check to make +For each test, we initialize and set up the appropriate structures +(readylist, wait_mask, etc), and then call H2K_resched(). We check to make sure that our version of H2K_dosched() was called, and check to make sure other appropraite actions were taken. diff --git a/kernel/sched/resched/test/Makefile b/kernel/sched/resched/test/Makefile index 32407b341..d0f09c55c 100644 --- a/kernel/sched/resched/test/Makefile +++ b/kernel/sched/resched/test/Makefile @@ -1,12 +1,9 @@ STANDALONE=1 OBJS+=test.o -RECOMPILE_DIRS += $(H2DIR)/kernel/data/runlist RECOMPILE_DIRS += $(H2DIR)/kernel/data/readylist RECOMPILE_DIRS += $(H2DIR)/kernel/sched/lowprio -RECOMPILE_SRCS_PREFS += runlist RECOMPILE_SRCS_PREFS += readylist -RECOMPILE_SRCS_PREFS += lowprio EXTRA_CFLAGS += -DTESTING EXTRA_ASFLAGS += -DTESTING diff --git a/kernel/sched/resched/test/test.c b/kernel/sched/resched/test/test.c index dbaa365d5..bca355120 100644 --- a/kernel/sched/resched/test/test.c +++ b/kernel/sched/resched/test/test.c @@ -6,15 +6,12 @@ #include #include #include -#include -#include #include #include #include #include #include #include -#include #include #include #include @@ -36,11 +33,12 @@ void H2K_dosched(H2K_thread_context *in, int hthread) { if (in != TB_in) FAIL("Unexpected thread passed to dosched"); if (TB_in && hthread != TB_in->hthread) FAIL("Unexpected hardware thread"); +#if CLUSTER_SCHED if (H2K_gp->wait_mask != 0) FAIL("Set bit in wait_mask"); +#endif TB_saw_dosched ++; checker_kernel_locked(); BKL_UNLOCK(); - checker_runlist(); checker_ready(); longjmp(env,1); } @@ -64,11 +62,13 @@ void TH_resched_cluster(u32_t unused, H2K_thread_context *me, u32_t hwtnum) int main() { __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED H2K_gp->cluster_sched = 1; #endif H2K_readylist_init(); +#if CLUSTER_SCHED H2K_gp->wait_mask = 0; +#endif a.prio = b.prio = c.prio = MAX_PRIOS - 30; a.hthread = 0; b.hthread = 1; @@ -77,28 +77,33 @@ int main() TH_resched(0,TB_in,0); if (TB_saw_dosched == 0) FAIL("did not do a resched"); TB_saw_dosched = 0; +#if CLUSTER_SCHED H2K_gp->wait_mask = 1; +#endif TH_resched(0,TB_in,0); if (TB_saw_dosched == 0) FAIL("Did not do a resched"); +#if CLUSTER_SCHED H2K_gp->wait_mask = 0; +#endif TB_saw_dosched = 0; TB_in = &a; - H2K_runlist_push(&a); - H2K_runlist_push(&c); TH_resched(0,TB_in,0); if (TB_saw_dosched == 0) FAIL("Did not do a resched"); if (H2K_gp->ready[MAX_PRIOS - 30] != &a) FAIL("Unexpected thread in readylist"); +#if CLUSTER_SCHED H2K_gp->wait_mask = 0; +#endif TB_saw_dosched = 0; TB_in = &c; TH_resched(0,TB_in,2); if (TB_saw_dosched == 0) FAIL("Did not do a resched"); if (H2K_gp->ready[MAX_PRIOS - 30] != &a) FAIL("Unexpected thread in readylist"); if (H2K_gp->ready[MAX_PRIOS - 30]->next != &c) FAIL("Unexpected thread in readylist"); +#if CLUSTER_SCHED H2K_gp->wait_mask = 0; +#endif TB_saw_dosched = 0; TB_in = &b; - H2K_runlist_push(&b); TH_resched_cluster(0,TB_in,1); if (TB_saw_dosched == 0) FAIL("Did not do a resched"); if (H2K_gp->ready[MAX_PRIOS - 30]->next->next != &b) FAIL("Unexpected thread in readylist"); diff --git a/kernel/sched/switch/switch.ref.S b/kernel/sched/switch/switch.ref.S index b1f06acf4..c8762751d 100644 --- a/kernel/sched/switch/switch.ref.S +++ b/kernel/sched/switch/switch.ref.S @@ -16,7 +16,7 @@ * We don't care about any registers * Handle any tracing and profiling * If switching to NULL, go to sleep - * Otherwise, load continuation into LR and jump to check_sanity_unlock + * Otherwise, load continuation into LR */ FUNC_START H2K_switch .text.core.switch .p2align 5 @@ -279,6 +279,7 @@ FUNC_START H2K_switch .text.core.switch .p2align 5 #else stid = r4 #endif + isync r17 = r1 r0 = r17 @@ -286,7 +287,8 @@ FUNC_START H2K_switch .text.core.switch .p2align 5 r1:0 = memd(r17+#CONTEXT_r0100) r31 = memw(r17+#CONTEXT_continuation) r31 = and(r31,#-4) // ignore LSBs - jump H2K_check_sanity_unlock + k0unlock + jumpr r31 .Lto_sleep: memd(r9) = r19:18 @@ -313,20 +315,14 @@ FUNC_START H2K_switch .text.core.switch .p2align 5 //ASM_INLINE_TRACE(r14,r27:26,r27,r26,r25:24,r25,r24,p0,r21,r20,r31,,) r9 = memw(H2K_GP+#KG_wait_mask) - r8 = memw(H2K_GP+#KG_priomask) r9 = setbit(r9,r5) - r8 = setbit(r8,r5) memw(H2K_GP+#KG_wait_mask) = r9 - memw(H2K_GP+#KG_priomask) = r8 - k0unlock + // set SGP to NULL sgp0 = r1 - // set IMASK to receive most interrupts - r0 = imask - r1.h = #HI(0) - r1.l = #LO(0) - r0 = and(r0,r1) + // set IMASK to receive all interrupts + r0 = #0 imask = r0 // set TID to special value (-1) @@ -336,6 +332,8 @@ FUNC_START H2K_switch .text.core.switch .p2align 5 #else stid = r1 #endif + isync + k0unlock // set SSR to enable interrupts // NOTE: should be the last thing before going to WAIT mode, we may get an interrupt diff --git a/kernel/sched/switch/switch.spec b/kernel/sched/switch/switch.spec index 8628fceea..5971afcf9 100644 --- a/kernel/sched/switch/switch.spec +++ b/kernel/sched/switch/switch.spec @@ -50,13 +50,6 @@ register, load the saved r1:0 (which contain a return value from the blocking function), and set or clear the PMU bit for the current hardware thread, depending on whether it is enabled for the software thread. -Finally, we jump to :c:func:`H2K_check_sanity_unlock()`. -:c:func:`H2K_check_sanity_unlock()` will return to the continuation. - - - - - Testing ------- @@ -67,12 +60,10 @@ Samples * Input: from, which may be NULL * Input: to, which may be NULL -* Flow: If to is non-NULL, we should arrive at :c:func:`H2K_check_sanity_unlock()` with the return address - set to the continuation value in "to" +* Flow: If to is non-NULL, we should return the address set to the continuation value in "to" * Ouptut: If to is NULL, we should unlock the kernel lock, * Flow: if to is NULL, we should jump to H2K_wait_forever * I/O: H2K_wait_mask bit set for our hardware thread only if to is NULL -* I/O: H2K_priomask bit set for our hardware thread only if to is NULL * Output: if to is NULL, we should additionally have the machine configured to be in WAIT mode: * The kernel is unlocked * SGP for our hardware thread is set to NULL diff --git a/kernel/sched/yield/test/Makefile b/kernel/sched/yield/test/Makefile index 32407b341..d27ac4f24 100644 --- a/kernel/sched/yield/test/Makefile +++ b/kernel/sched/yield/test/Makefile @@ -1,12 +1,8 @@ STANDALONE=1 OBJS+=test.o -RECOMPILE_DIRS += $(H2DIR)/kernel/data/runlist RECOMPILE_DIRS += $(H2DIR)/kernel/data/readylist -RECOMPILE_DIRS += $(H2DIR)/kernel/sched/lowprio -RECOMPILE_SRCS_PREFS += runlist RECOMPILE_SRCS_PREFS += readylist -RECOMPILE_SRCS_PREFS += lowprio EXTRA_CFLAGS += -DTESTING EXTRA_ASFLAGS += -DTESTING diff --git a/kernel/sched/yield/test/test.c b/kernel/sched/yield/test/test.c index 75263a4e9..8c09d73cf 100644 --- a/kernel/sched/yield/test/test.c +++ b/kernel/sched/yield/test/test.c @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include #include #include @@ -50,16 +48,15 @@ int main() { __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); H2K_readylist_init(); - H2K_runlist_init(); +#if CLUSTER_SCHED H2K_gp->wait_mask = 0; +#endif a.prio = b.prio = c.prio = d.prio = 2; a.hthread = 0; b.hthread = 2; c.hthread = 1; d.hthread = 2; TB_in = &a; - H2K_runlist_push(&a); - H2K_runlist_push(&c); TH_sched_yield(TB_in); if (TB_saw_dosched != 0) FAIL("Did a resched"); H2K_ready_append(&b); @@ -72,11 +69,9 @@ int main() if (TB_saw_dosched == 0) FAIL("Did not do a resched"); BKL_UNLOCK(); H2K_readylist_init(); - H2K_runlist_init(); +#if CLUSTER_SCHED H2K_gp->wait_mask = 0; - H2K_runlist_push(&a); - H2K_runlist_push(&c); - H2K_runlist_push(&d); +#endif H2K_ready_append(&b); TB_in = &a; TH_sched_yield(TB_in); diff --git a/kernel/sched/yield/yield.ref.c b/kernel/sched/yield/yield.ref.c index 5ed47dbe4..92da034e6 100644 --- a/kernel/sched/yield/yield.ref.c +++ b/kernel/sched/yield/yield.ref.c @@ -4,7 +4,6 @@ */ #include -#include #include #include #include @@ -22,10 +21,6 @@ void H2K_sched_yield(H2K_thread_context *me) BKL_UNLOCK(&H2K_bkl); return; } - H2K_runlist_remove(me); // This is kept for the same reason described - // in kernel/sched/dosched/dosched.ref.c at the H2K_rnulist_push callsite. - H2K_ready_append(me); H2K_dosched(me,me->hthread); } - diff --git a/kernel/sched/yield/yield.spec b/kernel/sched/yield/yield.spec index 4757aa4ab..58822ff89 100644 --- a/kernel/sched/yield/yield.spec +++ b/kernel/sched/yield/yield.spec @@ -26,14 +26,12 @@ return immediately after releasing the BKL. (EJP: can we do this outside the BK Another thread might be inserting itself into the ready list. Can we spec the function so that it does a best effort?) -Next, the :c:func:`H2K_sched_yield()` function removes the current thread from the runlist, and -appends it on the end of the ready list. +Next, the :c:func:`H2K_sched_yield()` function appends the thread to the end of the ready list. We can then call :c:func:`H2K_dosched()` to pick a new thread to run. As an optimization, we can instead remove the thread at the head of the -readylist at the same priority, and insert it into the runlist. We switch to -the thread inserted into the runlist. +readylist at the same priority and switch to it. @@ -47,14 +45,13 @@ Samples * Input: me, which may or may not have a valid thread * Input: correct ready queue, which may or may not have ready threads -* I/O: runlist, which is updated if there is a new thread to schedule * I/O: waitmask, modified if new is NULL Important cases ~~~~~~~~~~~~~~~ -* Runlist has no valid threads at current thread's priority -* Runlist has valid threads at current thread's priority +* No valid threads at current thread's priority +* There are valid threads at current thread's priority Harness ~~~~~~~ @@ -62,8 +59,8 @@ Harness Link with H2 kernel library. If valid threads exist at the current priority, :c:func:`H2K_sched_yield()` should lock -the kernel, remove the current thread from the runlist, append the current -thread to the ring at the current thread priority, and call :c:func:`H2K_dosched()`. +the kernel, append the current thread to the ring at the current thread priority, +and call :c:func:`H2K_dosched()`. If no valid threads exist at the current priority, :c:func:`H2K_sched_yield()` may return immediately. Since this optimization may be important for performance diff --git a/kernel/thread/create/create.ref.c b/kernel/thread/create/create.ref.c index 939d04c44..ee50bec15 100644 --- a/kernel/thread/create/create.ref.c +++ b/kernel/thread/create/create.ref.c @@ -19,6 +19,7 @@ #include #include #include +#include void H2K_interrupt_restore(); @@ -55,7 +56,7 @@ IN_SECTION(".text.misc.create") s32_t H2K_thread_create_no_squash(u32_t pc, u32_ extra = H2K_gp->asid_table[me->ssr_asid].fields.extra; } - if (prio > MAX_READY_PRIO) return -1; // bad prio + if (prio > MAX_PRIO) return -1; // bad prio if (prio < bestprio) return -1; // priority better than allowed if ((sp & 7) != 0) return -1; // bad stack pointer alignment @@ -106,8 +107,9 @@ IN_SECTION(".text.misc.create") s32_t H2K_thread_create_no_squash(u32_t pc, u32_ vmblock->num_cpus++; tmp->vmblock = vmblock; - H2K_ready_append(tmp); - return (s32_t)H2K_check_sanity_unlock(H2K_id_from_context(tmp).raw); + H2K_ready_append_arm(tmp); + BKL_UNLOCK(); + return (s32_t)H2K_id_from_context(tmp).raw; } IN_SECTION(".text.misc.create") s32_t H2K_thread_create(u32_t pc, u32_t sp, u32_t arg1, u32_t prio, H2K_vmblock_t *vmblock, H2K_thread_context *me) diff --git a/kernel/thread/create/create.spec b/kernel/thread/create/create.spec index 7ab4bfd65..a0c01613c 100644 --- a/kernel/thread/create/create.spec +++ b/kernel/thread/create/create.spec @@ -72,8 +72,7 @@ If vmblock is non-NULL, these actions are added: * The vmblock pointer of the new thread is inherited from the caller. -We then add the new thread to the readylist, and call :c:func:`H2K_check_sanity_unlock()` -before returning. +We then add the new thread to the readylist. For security, we need to assure that no values are in registers incorrectly. We accomplish this by clearing the thread context during initialization and @@ -113,8 +112,6 @@ Harness We link directly with the create object file, and also the readylist object file. -We define :c:func:`H2K_check_sanity_unlock()` to set a flag indicating that the function was called. - The test harness will call :c:func:`H2K_thread_create()` with various inputs and check to make sure that the appropriate action was taken: diff --git a/kernel/thread/create/test/Makefile b/kernel/thread/create/test/Makefile index c6bf76489..a368c29a7 100644 --- a/kernel/thread/create/test/Makefile +++ b/kernel/thread/create/test/Makefile @@ -1,13 +1,9 @@ STANDALONE=1 OBJS+=test.o -RECOMPILE_DIRS += $(H2DIR)/kernel/data/runlist RECOMPILE_DIRS += $(H2DIR)/kernel/data/readylist -RECOMPILE_DIRS += $(H2DIR)/kernel/sched/lowprio RECOMPILE_DIRS += $(H2DIR)/kernel/mem/asid -RECOMPILE_SRCS_PREFS += runlist RECOMPILE_SRCS_PREFS += readylist -RECOMPILE_SRCS_PREFS += lowprio RECOMPILE_SRCS_PREFS += asid EXTRA_CFLAGS += -DTESTING diff --git a/kernel/thread/create/test/test.c b/kernel/thread/create/test/test.c index a663c11f6..054fa4e9b 100644 --- a/kernel/thread/create/test/test.c +++ b/kernel/thread/create/test/test.c @@ -6,9 +6,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -66,24 +64,8 @@ void TH_vm_init() H2K_kg.vmblocks[2] = &TH_vm.vm; } -u32_t TH_saw_check_sanity = 0; H2K_thread_context *TH_me = NULL; -u64_t H2K_check_sanity_unlock(u64_t x) -{ - TH_saw_check_sanity++; - checker_kernel_locked(); - BKL_UNLOCK(); - return x; -} - -u64_t H2K_check_sanity(u64_t x) -{ - TH_saw_check_sanity++; - checker_kernel_locked(); - return x; -} - u64_t H2K_check_sched_mask(u64_t x) { FAIL("Saw sched mask check"); @@ -107,7 +89,9 @@ int main() H2K_vmblock_t *vmblock = &TH_vm.vm; __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); H2K_readylist_init(); - H2K_gp->wait_mask = 0; +#if CLUSTER_SCHED + H2K_gp->wait_mask = 0; +#endif H2K_thread_init(); H2K_asid_table_init(); TH_vm_init(); @@ -143,11 +127,8 @@ int main() if (H2K_thread_create(((u32_t)test_thread),((u32_t)(&stack)),0xdeadbeef,902,vmblock,a) != 0xffffffff) FAIL("Created thread w/ bad prio"); - if (TH_saw_check_sanity != 0) FAIL("Called check_sanity on failure"); - if (gpcall_H2K_thread_create(((u32_t)test_thread),((u32_t)(&stack)),0xdeadbeef,2,vmblock,a) != (b->id.raw)) FAIL("Failed to create expected thread"); - if (TH_saw_check_sanity == 0) FAIL("Did not call check_sanity"); if (H2K_gp->ready[2] != b) FAIL("Thread inserted incorrectly into ready list"); if (b->prio != 2) FAIL("thread priority set wrong"); if (b->status == H2K_STATUS_DEAD) FAIL("status field incorrect"); @@ -158,62 +139,11 @@ int main() if (b->gp != a->gp) FAIL("Incorrect inheritance of GP"); if (b->vmblock != vmblock) FAIL("vmblock is non-NULL"); - TH_saw_check_sanity = 0; vmblock->pmap = 0x12345678; if (H2K_thread_create(((u32_t)test_thread), (u32_t)&stack,0xdeadbeef,2,vmblock,a) != (c->id.raw)) FAIL("Failed to create expected thread"); if (c->ssr_asid != a->ssr_asid) FAIL("wrong asid"); -#if 0 - vm.max_cpus = 2; - vm.num_cpus = 2; // initially full - vm.bestprio = 5; - vm.trapmask = 0xfa1a1a1a; - vm.cpu_contexts = vmcontext; - vm.pmap = 0xb1ab1ab1; - vm.pmap_type = H2K_ASID_TRANS_TYPE_TABLE; - - /* so we can check if properly decremented */ - asid = H2K_asid_table_inc(vm.pmap, H2K_ASID_TRANS_TYPE_TABLE, H2K_ASID_TLB_INVALIDATE_FALSE, 0, vmblock); - - ret = H2K_thread_create_no_squash(((u32_t)test_thread),((u32_t)(&stack)),0xdeadbeef,6,&vm,&a); - /* asid count should have gone to 2 and then back to 1 */ - if (H2K_mem_asid_table[asid].fields.count != 1) FAIL("Bad asid count"); - if (ret != -1) FAIL("Exceeded max_cpus"); - - vm.num_cpus = 1; -#warning Need to reenable this test and fix when audio becomes unbroken - //ret = H2K_thread_create_no_squash(((u32_t)test_thread),((u32_t)(&stack)),0xdeadbeef,4,&vm,&a); - //if (ret != -1) FAIL("Exceeded vm bestprio"); - - /* should succeed */ - ret = H2K_thread_create_no_squash(((u32_t)test_thread),((u32_t)(&stack)),0xdeadbeef,6,&vm,&a); - if (ret == -1) FAIL("Unexpected error"); - - if (c->trapmask != 0xfa1a1a1a) FAIL("Bad vm trapmask"); - /* asid should be that of the calling thread, because we're starting an additional vcpu */ - if (c->ssr_asid != a->ssr_asid) FAIL("Bad vm asid 1"); - if (vm.num_cpus != 2) FAIL("Bad vm num_cpus"); - //if (c->vmcpu != 1) FAIL("Bad vmcpu"); /* EJP: now cpuidx field in id */ - if (vmcontext[1] != &c) FAIL("Bad vm context"); - if (c->vmblock != &vm) FAIL("Bad vmblock"); - - vm.num_cpus = 0; - /* should succeed */ - ret = H2K_thread_create_no_squash(((u32_t)test_thread),((u32_t)(&stack)),0xdeadbeef,6,&vm,&a); - if (ret == -1) FAIL("Unexpected error"); - - /* asid should come from vmblock->pmap when num_cpus == 0 */ - if (d.ssr_asid != asid) FAIL("Bad vm asid 2"); - - TH_saw_check_sanity = 0; - if (H2K_thread_create(((u32_t)test_thread),((u32_t)(&stack)),0xdeadbeef,2,0x0,&a) - != (u32_t)(&e)) FAIL("Failed to create expected thread"); - if (TH_saw_check_sanity == 0) FAIL("Did not call check_sanity"); - - if (H2K_thread_create((u32_t)test_thread,((u32_t)(&stack)),0xdeadbeef,2,0x0,&a) - != 0xffffffff) FAIL("Created thread w/o storage"); -#endif puts("TEST PASSED\n"); return 0; } diff --git a/kernel/thread/stop/stop.ref.c b/kernel/thread/stop/stop.ref.c index 3624731c5..e94bfa822 100644 --- a/kernel/thread/stop/stop.ref.c +++ b/kernel/thread/stop/stop.ref.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/kernel/thread/stop/stop.spec b/kernel/thread/stop/stop.spec index 08cda9389..e85ff7378 100644 --- a/kernel/thread/stop/stop.spec +++ b/kernel/thread/stop/stop.spec @@ -59,14 +59,12 @@ is not ``H2K_STATUS_DEAD``. Else, when the vcpu count is 0, calls :c:func:`H2K_mem_alloc_release()` to mark the vmblock as freeable (will not be freed until we relinquish BKL). -Cancels associated timers and removes the current thread from the runlist. -Clears the thread context (which sets the valid field to DEAD), then -inserts the thread into the H2K_kg.free_threads list. +Cancels associated timers, clears the thread context (which sets the valid field to DEAD), +then inserts the thread into the H2K_kg.free_threads list. Finally, calls :c:func:`H2K_dosched()` to pick a new thread. The current thread is specified as NULL, rather than as the now-dead thread context -pointer. ``H2K_dosched()`` consumes the BKL (released by -``H2K_check_sanity_unlock`` at the tail of ``H2K_switch``). +pointer. ``H2K_dosched()`` consumes the BKL (released at the tail of ``H2K_switch``). @@ -90,10 +88,10 @@ Important cases Harness ~~~~~~~ -We link directly with the stop object file, and also the runlist object file. +We link directly with the stop object file. The test harness defines :c:func:`H2K_dosched()` to set a flag indicating that the dosched -routine was called. It also adds test threads correctly into the runlist. +routine was called. The test harness calls :c:func:`H2K_thread_stop()` with a thread context pointer. We check to make sure :c:func:`H2K_dosched()` was called, and that the thread was added to the diff --git a/kernel/thread/stop/test/Makefile b/kernel/thread/stop/test/Makefile index b9941862f..bd27facc5 100644 --- a/kernel/thread/stop/test/Makefile +++ b/kernel/thread/stop/test/Makefile @@ -1,12 +1,8 @@ STANDALONE=1 OBJS+=test.o -RECOMPILE_DIRS += $(H2DIR)/kernel/data/runlist RECOMPILE_DIRS += $(H2DIR)/kernel/data/readylist -RECOMPILE_DIRS += $(H2DIR)/kernel/sched/lowprio -RECOMPILE_SRCS_PREFS += runlist RECOMPILE_SRCS_PREFS += readylist -RECOMPILE_SRCS_PREFS += lowprio EXTRA_CFLAGS += -DTESTING EXTRA_ASFLAGS += -DTESTING diff --git a/kernel/thread/stop/test/test.c b/kernel/thread/stop/test/test.c index bd43f8ce0..f5a27172a 100644 --- a/kernel/thread/stop/test/test.c +++ b/kernel/thread/stop/test/test.c @@ -6,9 +6,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -76,7 +74,9 @@ int main() H2K_vmblock_t *vmblock = &myblock; __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); H2K_readylist_init(); +#if CLUSTER_SCHED H2K_gp->wait_mask = 0; +#endif H2K_thread_init(); a.prio = 2; @@ -91,8 +91,6 @@ int main() //puts("C"); vmblock->free_threads = NULL; if (vmblock->free_threads != NULL) FAIL("free threads not clear"); - H2K_runlist_push(&a); - H2K_runlist_push(&b); TH_me = &a; a.prev = &a; TH_saw_dosched = 0; @@ -125,9 +123,6 @@ int main() c.prio = 2; vmblock->free_threads = NULL; if (vmblock->free_threads != NULL) FAIL("free threads not clear"); - H2K_runlist_push(&a); - H2K_runlist_push(&b); - H2K_runlist_push(&c); TH_me = &a; a.prev = &a; TH_saw_dosched = 0; diff --git a/kernel/todo b/kernel/todo index c6a0a4293..5e8d7a6c4 100644 --- a/kernel/todo +++ b/kernel/todo @@ -136,9 +136,6 @@ Inside the Monitor: TBD: * How do we make "in_ready_queue(owner_context)" fast? - * How can we change prio and have thread still take itself out of - runlist efficiently? - * Change runlist? Caveats: * Futex_resume may not be right place to always change back prio diff --git a/kernel/traps/config/config.h b/kernel/traps/config/config.h index 3970f60d6..2c6d520b9 100644 --- a/kernel/traps/config/config.h +++ b/kernel/traps/config/config.h @@ -78,7 +78,7 @@ u32_t H2K_trap_config(config_type_t configtype, u32_t val1, u32_t val2, u32_t va u32_t H2K_trap_config_vmblock_init(u32_t unused, u32_t vm, u32_t op, u32_t arg1, u32_t arg2, H2K_thread_context *me) IN_SECTION(".text.config.config"); u32_t H2K_trap_config_stlb_alloc(u32_t unused, u32_t sets, u32_t unused2, u32_t unused3, u32_t unused4, H2K_thread_context *me) IN_SECTION(".text.config.config"); u32_t H2K_trap_config_fatal_hook(u32_t unused, u32_t funcaddr, u32_t arg, u32_t unused3, u32_t unused4, H2K_thread_context *me) IN_SECTION(".text.config.config"); -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED u32_t H2K_trap_config_cluster_sched(u32_t unused, u32_t enable, u32_t unused2, u32_t unused3, u32_t unused4, H2K_thread_context *me) IN_SECTION(".text.config.config"); #endif u32_t H2K_trap_config_noc(u32_t unused, u32_t master, u32_t slave, u32_t unused3, u32_t unused4, H2K_thread_context *me) IN_SECTION(".text.config.config"); diff --git a/kernel/traps/config/config.ref.c b/kernel/traps/config/config.ref.c index 48e75e302..96437fa28 100644 --- a/kernel/traps/config/config.ref.c +++ b/kernel/traps/config/config.ref.c @@ -31,7 +31,7 @@ static const configptr_t H2K_configtab[CONFIG_MAX] IN_SECTION(".data.config.conf H2K_trap_config_vmblock_init, H2K_trap_config_stlb_alloc, H2K_trap_config_fatal_hook, -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED H2K_trap_config_cluster_sched, #endif H2K_trap_config_noc @@ -226,7 +226,7 @@ static u32_t H2K_config_vmblock_init_set_fences(H2K_vmblock_t *vmblock, u32_t vm static u32_t H2K_config_vmblock_init_prio_trapmask(H2K_vmblock_t *vmblock, u32_t vm, u32_t unused, u32_t arg1, u32_t arg2, H2K_thread_context *me) { - if (arg1 > MAX_READY_PRIO) return 0; /* bad arg */ + if (arg1 > MAX_PRIO) return 0; /* bad arg */ vmblock->bestprio = (u8_t)arg1; vmblock->trapmask = (u32_t)arg2; if (vmblock->bestprio > 200) vmblock->tlbidxmask = 0x0f; /* EJP: KLUDGE */ @@ -305,7 +305,7 @@ u32_t H2K_trap_config_stlb_alloc(u32_t unused, u32_t sets, u32_t unused2, u32_t return H2K_mem_stlb_alloc(); } -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED u32_t H2K_trap_config_cluster_sched(u32_t unused, u32_t enable, u32_t unused2, u32_t unused3, u32_t unused4, H2K_thread_context *me) { H2K_gp->cluster_sched = enable; diff --git a/kernel/traps/hwconfig/hwconfig.ref.c b/kernel/traps/hwconfig/hwconfig.ref.c index 5da31a431..984b2e6fc 100644 --- a/kernel/traps/hwconfig/hwconfig.ref.c +++ b/kernel/traps/hwconfig/hwconfig.ref.c @@ -23,9 +23,8 @@ #include #include -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED #include -#include #include #endif @@ -268,7 +267,7 @@ u32_t H2K_trap_hwconfig_coproc_bits(u32_t unused, void *unusedp, u32_t coproc, u32_t H2K_trap_hwconfig_hlxbits(u32_t unused, void *unusedp, u32_t xa3, u32_t xe3, H2K_thread_context *me) { #if (ARCHV >= 81 && defined(HMX_HLX_SUPPORT)) if (0 < H2K_gp->hlx_contexts) { // exists -# ifdef CLUSTER_SCHED +# if CLUSTER_SCHED if (H2K_gp->cluster_sched) { BKL_LOCK(); if (xe3 && !(me->ccr & CCR_XE3_BIT_MASK)) { // turning xe3 on @@ -303,7 +302,7 @@ u32_t H2K_trap_hwconfig_hlxbits(u32_t unused, void *unusedp, u32_t xa3, u32_t x u32_t H2K_trap_hwconfig_hmxbits(u32_t unused, void *unusedp, u32_t xe2, u32_t unused3, H2K_thread_context *me) { #if (ARCHV >= 68 && defined(HMX_HLX_SUPPORT)) if (0 < H2K_gp->hmx_units) { // exists -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED if (H2K_gp->cluster_sched) { BKL_LOCK(); if (xe2 && !(me->ssr & SSR_XE2_BIT_MASK)) { // turning xe2 on @@ -339,7 +338,7 @@ u32_t H2K_trap_hwconfig_extbits(u32_t unused, void *unusedp, u32_t xa, u32_t xe, /* FIXME: should check for allowed XA values here (maybe?) */ /* EJP: Always allow XE/XA to be set if only for silver tests working also */ -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED if (H2K_gp->cluster_sched) { BKL_LOCK(); if (xe && !(me->ssr & SSR_XE_BIT_MASK)) { // turning xe on @@ -561,7 +560,7 @@ u32_t H2K_trap_hwconfig_hwthreads_mask(u32_t unused, void *unusedp, u32_t mask, H2K_gp->hthreads_mask &= MODECTL_E_MASK; H2K_gp->hthreads = Q6_R_popcount_P(H2K_gp->hthreads_mask); -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED H2K_cluster_config(); #endif return H2K_gp->hthreads_mask; @@ -600,7 +599,7 @@ u32_t H2K_trap_hwconfig_hwthreads_num(u32_t unused, void *unusedp, u32_t num, u3 H2K_gp->hthreads_mask &= MODECTL_E_MASK; H2K_gp->hthreads = Q6_R_popcount_P(H2K_gp->hthreads_mask); -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED H2K_cluster_config(); #endif return H2K_gp->hthreads; diff --git a/kernel/traps/info/info.ref.c b/kernel/traps/info/info.ref.c index a8bd4492c..5780fe5b8 100644 --- a/kernel/traps/info/info.ref.c +++ b/kernel/traps/info/info.ref.c @@ -147,7 +147,7 @@ u32_t H2K_trap_info(info_type op, u32_t unit, h2_cfg_unit_entry entry, H2K_threa return 0; } case INFO_MAX_CLUSTER_COPROC: -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED return H2K_gp->coproc_max; #else return H2K_gp->coproc_contexts; diff --git a/kernel/traps/prio/prio.ref.c b/kernel/traps/prio/prio.ref.c index a55ee3c3d..e5fd791a9 100644 --- a/kernel/traps/prio/prio.ref.c +++ b/kernel/traps/prio/prio.ref.c @@ -4,7 +4,6 @@ */ #include -#include #include #include @@ -12,7 +11,7 @@ s32_t H2K_prio_set(H2K_thread_context *dest, u32_t prio, H2K_thread_context *me) { s32_t ret = me->base_prio; - if (prio > MAX_READY_PRIO) return -1; + if (prio > MAX_PRIO) return -1; if ((me->vmblock != NULL) && (prio < me->vmblock->bestprio)) return -1; me->base_prio = (u8_t)prio; return ret; diff --git a/kernel/traps/prio/test/test.c b/kernel/traps/prio/test/test.c index ce3916429..d2a9dddc4 100644 --- a/kernel/traps/prio/test/test.c +++ b/kernel/traps/prio/test/test.c @@ -24,7 +24,7 @@ int main() { u32_t i; __asm__ __volatile(GLOBAL_REG_STR " = %0 " : : "r"(&H2K_kg)); - for (i = 0; i <= MAX_READY_PRIO; i++) { + for (i = 0; i <= MAX_PRIO; i++) { a.base_prio = i; if (H2K_prio_get(0,&a) != i) FAIL("prio_get"); } @@ -32,12 +32,12 @@ int main() H2K_prio_set(&a,0,&a); if (a.base_prio != 0) FAIL("prio_set_null"); a.vmblock = &vmblock; - for (i = 0; i <= MAX_READY_PRIO; i++) { + for (i = 0; i <= MAX_PRIO; i++) { a.vmblock->bestprio = i; H2K_prio_set(&a,a.vmblock->bestprio,&a); if (a.base_prio != a.vmblock->bestprio) FAIL("prio_set_mid"); } - for (i = MAX_READY_PRIO + 1; i <= MAX_PRIOS; i++) { + for (i = MAX_PRIO + 1; i <= MAX_PRIOS; i++) { if(H2K_prio_set(&a,i,&a) != -1) FAIL("prio_set_limit"); } puts("TEST PASSED\n"); diff --git a/kernel/util/hw/hw.h b/kernel/util/hw/hw.h index 7d98734ef..61c875b8d 100644 --- a/kernel/util/hw/hw.h +++ b/kernel/util/hw/hw.h @@ -56,8 +56,6 @@ static inline u32_t get_imask(u32_t thread) return imask; } -/* Write STID.PRIO for a named hardware thread (cross-thread, Monitor only). - * Mirrors setimask -- uses predicate register to name the target thread. */ static inline void set_thread_stid_prio(u32_t thread, u32_t prio) { asm volatile (" p0 = %0\n setprio(p0,%1); isync;" : : "r"(thread),"r"(prio):"p0"); diff --git a/kernel/util/max/max.h b/kernel/util/max/max.h index 011577022..e09f5ced9 100644 --- a/kernel/util/max/max.h +++ b/kernel/util/max/max.h @@ -77,7 +77,7 @@ #define MAX_PRIOS 256 #define WAITING_PRIO ((MAX_PRIOS) - 1) -#define MAX_READY_PRIO ((MAX_PRIOS) - 2) +#define MAX_PRIO ((MAX_PRIOS) - 2) #define BEST_PRIO 0 #define BESTWAIT_MASK 0x1ff diff --git a/kernel/util/stmode/test/test.c b/kernel/util/stmode/test/test.c index 434f7e05d..900a47acf 100644 --- a/kernel/util/stmode/test/test.c +++ b/kernel/util/stmode/test/test.c @@ -59,7 +59,7 @@ IN_SECTION(".text.misc.create") s32_t H2K_thread_create_no_squash(u32_t pc, u32_ extra = H2K_gp->asid_table[me->ssr_asid].fields.extra; } - if (prio > MAX_READY_PRIO) return -1; + if (prio > MAX_PRIO) return -1; if (prio < bestprio) return -1; if ((sp & 7) != 0) return -1; if ((pc & 3) != 0) return -1; @@ -109,8 +109,9 @@ IN_SECTION(".text.misc.create") s32_t H2K_thread_create_no_squash(u32_t pc, u32_ vmblock->num_cpus++; tmp->vmblock = vmblock; - H2K_ready_append(tmp); - return (s32_t)H2K_check_sanity_unlock(H2K_id_from_context(tmp).raw); + H2K_ready_append_arm(tmp); + BKL_UNLOCK(); + return (s32_t)H2K_id_from_context(tmp).raw; } void FAIL(const char *str) diff --git a/kernel/vm/vmcache/vmcache.ref.c b/kernel/vm/vmcache/vmcache.ref.c index ba37816fd..e777332c2 100644 --- a/kernel/vm/vmcache/vmcache.ref.c +++ b/kernel/vm/vmcache/vmcache.ref.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/kernel/vm/vmfuncs/vmfuncs.ref.c b/kernel/vm/vmfuncs/vmfuncs.ref.c index 336591a89..56d6f76e0 100644 --- a/kernel/vm/vmfuncs/vmfuncs.ref.c +++ b/kernel/vm/vmfuncs/vmfuncs.ref.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/kernel/vm/vmint/test/test.c b/kernel/vm/vmint/test/test.c index 134c6897d..68e49ad82 100644 --- a/kernel/vm/vmint/test/test.c +++ b/kernel/vm/vmint/test/test.c @@ -119,24 +119,6 @@ void H2K_vm_event(u32_t x, u32_t cause, u32_t offset, H2K_thread_context *me) TH_saw_event = 1; } -u32_t TH_expected_sanity = 0; -u32_t TH_saw_sanity = 0; - -u64_t H2K_check_sanity_unlock(u64_t ret) -{ - if (TH_expected_sanity == 0) FAIL("Didn't expect sanity"); - TH_saw_sanity = 1; - BKL_UNLOCK(); - return ret; -} - -u64_t H2K_check_sanity(u64_t ret) -{ - if (TH_expected_sanity == 0) FAIL("Didn't expect sanity"); - TH_saw_sanity = 1; - return ret; -} - u32_t TH_expected_popup_cancel = 0; u32_t TH_saw_popup_cancel = 0; void H2K_popup_cancel(H2K_thread_context *me) @@ -324,14 +306,10 @@ int main() puts("B"); t0->vmstatus = 0; t0->status = H2K_STATUS_VMWAIT; - TH_expected_sanity = 1; ret = H2K_vm_int_deliver(&TH_vmblock,t0,0); if (ret != 0) FAIL("error code"); if (t0->status != H2K_STATUS_READY) FAIL("status"); if (t0->vmstatus != 0) FAIL("vmstatus"); - if (TH_saw_sanity != 1) FAIL("no sanity check"); - TH_saw_sanity = 0; - TH_expected_sanity = 0; puts("C"); @@ -373,7 +351,6 @@ int main() t0->vmstatus = H2K_VMSTATUS_IE; t0->status = H2K_STATUS_INTBLOCKED; TH_expected_popup_cancel = 1; - TH_expected_sanity = 1; ret = H2K_vm_int_deliver(&TH_vmblock,t0,0); if (ret != 0) FAIL("error code"); if (t0->status != H2K_STATUS_READY) FAIL("status"); @@ -381,10 +358,6 @@ int main() if (TH_saw_popup_cancel != 1) FAIL("Didn't see popup cancel"); TH_expected_popup_cancel = 0; TH_saw_popup_cancel = 0; - if (TH_saw_sanity != 1) FAIL("no sanity check"); - TH_saw_sanity = 0; - TH_expected_sanity = 0; - puts("G"); t0->vmstatus = 0; @@ -403,7 +376,6 @@ int main() t0->vmstatus = H2K_VMSTATUS_IE; t0->status = H2K_STATUS_BLOCKED; TH_expected_futex_cancel = 1; - TH_expected_sanity = 1; ret = H2K_vm_int_deliver(&TH_vmblock,t0,0); if (ret != 0) FAIL("error code"); if (t0->status != H2K_STATUS_READY) FAIL("status"); @@ -411,9 +383,6 @@ int main() if (TH_saw_futex_cancel != 1) FAIL("Didn't see popup cancel"); TH_expected_futex_cancel = 0; TH_saw_futex_cancel = 0; - if (TH_saw_sanity != 1) FAIL("no sanity check"); - TH_saw_sanity = 0; - TH_expected_sanity = 0; puts("I"); diff --git a/kernel/vm/vmint/vmint.ref.c b/kernel/vm/vmint/vmint.ref.c index 8728c7c5e..583401f40 100644 --- a/kernel/vm/vmint/vmint.ref.c +++ b/kernel/vm/vmint/vmint.ref.c @@ -34,8 +34,7 @@ s32_t H2K_vm_int_deliver_locked(H2K_vmblock_t *vmblock, H2K_thread_context *thre } thread->r00 = intno; enqueue: - H2K_ready_append(thread); - H2K_check_sanity(0); + H2K_ready_append_arm(thread); return 0; case H2K_STATUS_RUNNING: if (thread->atomic_status_word & H2K_VMSTATUS_IE) { diff --git a/kernel/vm/vmmap/vmmap.ref.c b/kernel/vm/vmmap/vmmap.ref.c index 5705172d1..a34c78572 100644 --- a/kernel/vm/vmmap/vmmap.ref.c +++ b/kernel/vm/vmmap/vmmap.ref.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include diff --git a/kernel/vm/vmop/test/test.c b/kernel/vm/vmop/test/test.c index a5fef8d9a..402310291 100644 --- a/kernel/vm/vmop/test/test.c +++ b/kernel/vm/vmop/test/test.c @@ -66,9 +66,6 @@ void H2K_futex_cancel(H2K_thread_context *t) TH_saw_futex_cancel = 1; } -u64_t H2K_check_sanity(u64_t r) { return r; } -u64_t H2K_check_sanity_unlock(u64_t r) { return r; } - static void TH_init_block(H2K_vmblock_t *blk, u32_t vmidx, u32_t parent_vmidx, H2K_thread_context *ctx) { diff --git a/kernel/vm/vmop/vmop.ref.c b/kernel/vm/vmop/vmop.ref.c index 3da9bff2d..20b924bf1 100644 --- a/kernel/vm/vmop/vmop.ref.c +++ b/kernel/vm/vmop/vmop.ref.c @@ -117,18 +117,18 @@ static void kill_thread_locked(H2K_vmblock_t *vmblock, H2K_thread_context *targe if (target->id.cpuidx < bits(long_bitmask_t)) { vmblock->waiting_cpus &= ~(0x1ULL << target->id.cpuidx); } - H2K_ready_append(target); + H2K_ready_append_arm(target); break; case H2K_STATUS_RUNNING: H2K_vm_ipi_send_withlock(target); break; case H2K_STATUS_INTBLOCKED: H2K_popup_cancel(target); - H2K_ready_append(target); + H2K_ready_append_arm(target); break; case H2K_STATUS_BLOCKED: H2K_futex_cancel(target); - H2K_ready_append(target); + H2K_ready_append_arm(target); break; case H2K_STATUS_READY: break; diff --git a/kernel/vm/vmwork/vmwork.spec b/kernel/vm/vmwork/vmwork.spec index a5dc8aa07..d840ad1c9 100644 --- a/kernel/vm/vmwork/vmwork.spec +++ b/kernel/vm/vmwork/vmwork.spec @@ -18,8 +18,8 @@ Description Handles deferred VM work for the current thread. The BKL must be held by the caller. Notable callers include the deferred-work hook in -``H2K_switch`` (between :c:func:`H2K_dosched()` and -``H2K_check_sanity_unlock``), :c:func:`H2K_vmtrap_vmwait()`, and +``H2K_switch`` (between :c:func:`H2K_dosched()` and BKL_UNLOCK()), +:c:func:`H2K_vmtrap_vmwait()`, and :c:func:`H2K_vm_ipi_do()`. INPUT_ASSERT(kernel_locked) diff --git a/libs/h2/common/h2_common_config.h b/libs/h2/common/h2_common_config.h index fc7f21589..5dc719219 100644 --- a/libs/h2/common/h2_common_config.h +++ b/libs/h2/common/h2_common_config.h @@ -14,7 +14,7 @@ typedef enum { CONFIG_VMBLOCK_INIT, CONFIG_STLB_ALLOC, CONFIG_FATAL_HOOK, -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED CONFIG_CLUSTER_SCHED, #endif CONFIG_NOC, // FIXME: hack for setting noc table addresses diff --git a/libs/h2/config/h2_config.h b/libs/h2/config/h2_config.h index 23975f0ac..ce1226a9b 100644 --- a/libs/h2/config/h2_config.h +++ b/libs/h2/config/h2_config.h @@ -54,7 +54,7 @@ int h2_config_stlb_alloc(void); int h2_config_fatal_hook(unsigned int funcaddr, unsigned int arg); -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED int h2_config_cluster_sched(unsigned int enable); #endif diff --git a/libs/h2/config/h2_config_imp.ref.c b/libs/h2/config/h2_config_imp.ref.c index 31eebf92d..2700352c5 100644 --- a/libs/h2/config/h2_config_imp.ref.c +++ b/libs/h2/config/h2_config_imp.ref.c @@ -23,7 +23,7 @@ int h2_config_fatal_hook(unsigned int funcaddr, unsigned int arg) return h2_config_trap(CONFIG_FATAL_HOOK,funcaddr,arg,0,0); } -#ifdef CLUSTER_SCHED +#if CLUSTER_SCHED int h2_config_cluster_sched(unsigned int enable) { return h2_config_trap(CONFIG_CLUSTER_SCHED, enable, 0, 0, 0); diff --git a/scripts/testlist.v4 b/scripts/testlist.v4 index ef7e7e6ba..03c39927e 100644 --- a/scripts/testlist.v4 +++ b/scripts/testlist.v4 @@ -1,7 +1,6 @@ ./kernel/data/intconfig/test ./kernel/data/context/test ./kernel/data/readylist/test -./kernel/data/runlist/test ./kernel/data/thread/test ./kernel/error/fatal/test ./kernel/event/error/test diff --git a/scripts/testlist.v61 b/scripts/testlist.v61 index 42eb921e4..cacbd074e 100644 --- a/scripts/testlist.v61 +++ b/scripts/testlist.v61 @@ -1,7 +1,6 @@ ./kernel/data/intconfig/test ./kernel/data/context/test ./kernel/data/readylist/test -#./kernel/data/runlist/test ./kernel/data/thread/test ./kernel/error/fatal/test ./kernel/event/error/test @@ -33,8 +32,6 @@ ./kernel/power/apcr/test_multi ./kernel/power/hvx/test ./kernel/power/apcr/simple_test -./kernel/sched/check_sanity/test/tests/H2K_check_sanity/scenarios -./kernel/sched/check_sanity/test/tests/H2K_bestwait ./kernel/sched/dosched/test/test ./kernel/futex/futex/test/tests/badaccess ./kernel/futex/futex/test/tests/find_match @@ -42,7 +39,7 @@ ./kernel/futex/futex/test/tests/multi_wake ./kernel/futex/futex/test/tests/pi ./kernel/futex/futex/test/tests/simple_lock_unlock -#./kernel/sched/lowprio/test +./kernel/sched/check_sanity/test/tests/H2K_bestwait ./kernel/sched/resched/test ./kernel/sched/switch/test ./kernel/sched/yield/test @@ -139,4 +136,4 @@ ./perf/myid ./perf/pingpong ./perf/mutex -./perf/mutex2 +./perf/mutex2 \ No newline at end of file From 798a3e662b5727aefbca2064dc042d2ddd65d6c9 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Mon, 20 Jul 2026 00:39:39 -0700 Subject: [PATCH 5/7] document and organize files Signed-off-by: Zeev Belinsky --- kernel/data/readylist/readylist.spec | 118 +++++++++++++++++- .../readylist}/tests/H2K_bestwait/Makefile | 0 .../tests/H2K_bestwait/Makefile.inc | 0 .../readylist}/tests/H2K_bestwait/test.c | 0 .../test => data/readylist}/tests/Makefile | 1 + .../readylist}/tests/Makefile.inc | 0 .../{test => tests/readylist}/Makefile | 0 .../{test => tests/readylist}/Makefile.inc | 0 .../{test => tests/readylist}/test.c | 0 kernel/sched/check_sanity/test/Makefile | 5 - kernel/sched/check_sanity/test/Makefile.inc | 6 - scripts/testlist.v61 | 4 +- 12 files changed, 115 insertions(+), 19 deletions(-) rename kernel/{sched/check_sanity/test => data/readylist}/tests/H2K_bestwait/Makefile (100%) rename kernel/{sched/check_sanity/test => data/readylist}/tests/H2K_bestwait/Makefile.inc (100%) rename kernel/{sched/check_sanity/test => data/readylist}/tests/H2K_bestwait/test.c (100%) rename kernel/{sched/check_sanity/test => data/readylist}/tests/Makefile (70%) rename kernel/{sched/check_sanity/test => data/readylist}/tests/Makefile.inc (100%) rename kernel/data/readylist/{test => tests/readylist}/Makefile (100%) rename kernel/data/readylist/{test => tests/readylist}/Makefile.inc (100%) rename kernel/data/readylist/{test => tests/readylist}/test.c (100%) delete mode 100644 kernel/sched/check_sanity/test/Makefile delete mode 100644 kernel/sched/check_sanity/test/Makefile.inc diff --git a/kernel/data/readylist/readylist.spec b/kernel/data/readylist/readylist.spec index 937f46872..9cf0d8865 100644 --- a/kernel/data/readylist/readylist.spec +++ b/kernel/data/readylist/readylist.spec @@ -4,6 +4,26 @@ .. module:: readylist +Overview +-------- + +The readylist API is split into two groups: + +* **Base functions** (:c:func:`H2K_ready_append`, :c:func:`H2K_ready_insert`, + :c:func:`H2K_ready_remove`) — manipulate the ready list without touching the + hardware BESTWAIT comparator. Used at mid-reschedule sites where a following + :c:func:`H2K_dosched()` call on the same HW thread will re-arm BESTWAIT. + +* **Arming variants** (:c:func:`H2K_ready_append_arm`, :c:func:`H2K_ready_insert_arm`, + :c:func:`H2K_ready_remove_arm`) — manipulate the ready list AND arm the hardware + BESTWAIT comparator with the new best ready priority. Used at wake/sleep-transition + sites where the thread is switched to immediately, or at :c:func:`H2K_ready_getbest()` + to ensure BESTWAIT is always re-armed after removing the best thread. + +The BESTWAIT comparator is a hardware mechanism that raises a reschedule interrupt +whenever any HW thread's STID.PRIO is strictly worse (higher number) than the armed +BESTWAIT value. + H2K_kg.ready and H2K_kg.ready_valids ------------------------------------ @@ -200,6 +220,81 @@ more elements in the ring, we call :c:func:`H2K_ready_clear_prio()` with the thread's priority. +H2K_ready_append_arm +-------------------- + +.. c:function:: static inline void H2K_ready_append_arm(H2K_thread_context *thread) + + :param thread: the thread to add + +Description +~~~~~~~~~~~ + +Appends the thread to the ready list and arms the hardware BESTWAIT comparator. + +Functionality +~~~~~~~~~~~~~ + +Calls :c:func:`H2K_ready_append()` to add the thread to the ready list, then +calls :c:func:`H2K_set_bestwait()` with the result of :c:func:`H2K_ready_best_prio()` +to arm the hardware reschedule-interrupt comparator with the best ready priority. + +Used at wake/sleep-transition sites where a thread is being placed on the ready +list and will be switched to immediately or returned without a following :c:func:`H2K_dosched()` +call on the same HW thread. The BESTWAIT arm ensures the hardware comparator is active to +trigger a reschedule interrupt if a running thread's priority becomes worse than +the newly-ready thread's priority. + + +H2K_ready_insert_arm +-------------------- + +.. c:function:: static inline void H2K_ready_insert_arm(H2K_thread_context *thread) + + :param thread: the thread to add + +Description +~~~~~~~~~~~ + +Inserts the thread to the ready list and arms the hardware BESTWAIT comparator. + +Functionality +~~~~~~~~~~~~~ + +Calls :c:func:`H2K_ready_insert()` to add the thread to the ready list, then +calls :c:func:`H2K_set_bestwait()` with the result of :c:func:`H2K_ready_best_prio()` +to arm the hardware reschedule-interrupt comparator with the best ready priority. + +Used at wake/sleep-transition sites where a thread is being inserted at the head +of the ready list (higher priority within the same priority level) and will be +switched to immediately without a following :c:func:`H2K_dosched()` call. + + +H2K_ready_remove_arm +-------------------- + +.. c:function:: static inline void H2K_ready_remove_arm(H2K_thread_context *thread) + + :param thread: the thread to remove + +Description +~~~~~~~~~~~ + +Removes the thread from the ready list and arms the hardware BESTWAIT comparator. + +Functionality +~~~~~~~~~~~~~ + +Calls :c:func:`H2K_ready_remove()` to remove the thread from the ready list, then +calls :c:func:`H2K_set_bestwait()` with the result of :c:func:`H2K_ready_best_prio()` +to arm the hardware reschedule-interrupt comparator with the best ready priority. + +Used in :c:func:`H2K_ready_getbest()` to ensure BESTWAIT is always re-armed after +removing the best thread from the ready list. Also used in :c:func:`H2K_resched()` +to immediately close the disarmed window after a hardware reschedule interrupt +fires (which resets BESTWAIT to 0x1FF). + + H2K_ready_getbest ----------------- @@ -211,7 +306,7 @@ H2K_ready_getbest Description ~~~~~~~~~~~ -Removes the best priority thread from the ready list. +Removes the best priority thread from the ready list and re-arms BESTWAIT. Functionality ~~~~~~~~~~~~~ @@ -222,7 +317,9 @@ We call :c:func:`H2K_ready_best_prio()` to obtain the priority of the best prior We then get the thread pointed to by the H2K_kg.ready pointer at the correct priority. -This thread is removed from the ready list by calling :c:func:`H2K_ready_remove()`, and returned. +This thread is removed from the ready list by calling :c:func:`H2K_ready_remove_arm()`, +which also re-arms BESTWAIT with the new best priority (or 0x1FF if no threads remain), +and the thread is returned. @@ -232,8 +329,11 @@ This thread is removed from the ready list by calling :c:func:`H2K_ready_remove( Testing ------- +Base Functions (H2K_ready_append, H2K_ready_insert, H2K_ready_remove, H2K_ready_getbest) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Samples -~~~~~~~ +^^^^^^^ * Input: H2K_kg.ready_valids * Input: H2K_kg.ready array @@ -244,7 +344,7 @@ Samples Important Cases -~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^ * H2K_ready_getbest when ready list is empty * H2K_ready_getbest when ready list has one thread @@ -261,9 +361,15 @@ Important Cases * Check H2K_ready_init clears out randomized values Harness -~~~~~~~ +^^^^^^^ The readylist module is reasonably self-contained, so the test harness will only -use the header file and object file. +use the header file and object file. + +BESTWAIT Arming Functions (H2K_ready_append_arm, H2K_ready_insert_arm, H2K_ready_remove_arm) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The `_arm` variants are tested separately in the H2K_bestwait test suite +(``kernel/data/readylist/tests/H2K_bestwait/test.c``), which validates the +hardware BESTWAIT/SCHEDCFG comparator behavior and the arming discipline. diff --git a/kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile b/kernel/data/readylist/tests/H2K_bestwait/Makefile similarity index 100% rename from kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile rename to kernel/data/readylist/tests/H2K_bestwait/Makefile diff --git a/kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile.inc b/kernel/data/readylist/tests/H2K_bestwait/Makefile.inc similarity index 100% rename from kernel/sched/check_sanity/test/tests/H2K_bestwait/Makefile.inc rename to kernel/data/readylist/tests/H2K_bestwait/Makefile.inc diff --git a/kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c b/kernel/data/readylist/tests/H2K_bestwait/test.c similarity index 100% rename from kernel/sched/check_sanity/test/tests/H2K_bestwait/test.c rename to kernel/data/readylist/tests/H2K_bestwait/test.c diff --git a/kernel/sched/check_sanity/test/tests/Makefile b/kernel/data/readylist/tests/Makefile similarity index 70% rename from kernel/sched/check_sanity/test/tests/Makefile rename to kernel/data/readylist/tests/Makefile index c477007bc..28e4bbadf 100644 --- a/kernel/sched/check_sanity/test/tests/Makefile +++ b/kernel/data/readylist/tests/Makefile @@ -1,4 +1,5 @@ SUBDIRS+=H2K_bestwait +SUBDIRS+=readylist include Makefile.inc diff --git a/kernel/sched/check_sanity/test/tests/Makefile.inc b/kernel/data/readylist/tests/Makefile.inc similarity index 100% rename from kernel/sched/check_sanity/test/tests/Makefile.inc rename to kernel/data/readylist/tests/Makefile.inc diff --git a/kernel/data/readylist/test/Makefile b/kernel/data/readylist/tests/readylist/Makefile similarity index 100% rename from kernel/data/readylist/test/Makefile rename to kernel/data/readylist/tests/readylist/Makefile diff --git a/kernel/data/readylist/test/Makefile.inc b/kernel/data/readylist/tests/readylist/Makefile.inc similarity index 100% rename from kernel/data/readylist/test/Makefile.inc rename to kernel/data/readylist/tests/readylist/Makefile.inc diff --git a/kernel/data/readylist/test/test.c b/kernel/data/readylist/tests/readylist/test.c similarity index 100% rename from kernel/data/readylist/test/test.c rename to kernel/data/readylist/tests/readylist/test.c diff --git a/kernel/sched/check_sanity/test/Makefile b/kernel/sched/check_sanity/test/Makefile deleted file mode 100644 index 370f48df7..000000000 --- a/kernel/sched/check_sanity/test/Makefile +++ /dev/null @@ -1,5 +0,0 @@ - - -SUBDIRS+=tests - -include Makefile.inc diff --git a/kernel/sched/check_sanity/test/Makefile.inc b/kernel/sched/check_sanity/test/Makefile.inc deleted file mode 100644 index 9d275c989..000000000 --- a/kernel/sched/check_sanity/test/Makefile.inc +++ /dev/null @@ -1,6 +0,0 @@ -# Need to define how to get back to the main H2 dir -H2DIR=${UPDIR}../../../.. - -# Everything else defined here -include ${H2DIR}/scripts/Makefile.inc.test - diff --git a/scripts/testlist.v61 b/scripts/testlist.v61 index cacbd074e..6df3a07b4 100644 --- a/scripts/testlist.v61 +++ b/scripts/testlist.v61 @@ -1,6 +1,5 @@ ./kernel/data/intconfig/test ./kernel/data/context/test -./kernel/data/readylist/test ./kernel/data/thread/test ./kernel/error/fatal/test ./kernel/event/error/test @@ -39,7 +38,8 @@ ./kernel/futex/futex/test/tests/multi_wake ./kernel/futex/futex/test/tests/pi ./kernel/futex/futex/test/tests/simple_lock_unlock -./kernel/sched/check_sanity/test/tests/H2K_bestwait +./kernel/data/readylist/tests/H2K_bestwait +./kernel/data/readylist/tests/readylist ./kernel/sched/resched/test ./kernel/sched/switch/test ./kernel/sched/yield/test From cd5e01c774dda431cc09333e470aeab206804920 Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Mon, 20 Jul 2026 00:42:13 -0700 Subject: [PATCH 6/7] readylist.spec: use consistent tilde underlines Signed-off-by: Zeev Belinsky --- kernel/data/readylist/readylist.spec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kernel/data/readylist/readylist.spec b/kernel/data/readylist/readylist.spec index 9cf0d8865..8bbac86db 100644 --- a/kernel/data/readylist/readylist.spec +++ b/kernel/data/readylist/readylist.spec @@ -333,7 +333,7 @@ Base Functions (H2K_ready_append, H2K_ready_insert, H2K_ready_remove, H2K_ready_ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Samples -^^^^^^^ +~~~~~~~ * Input: H2K_kg.ready_valids * Input: H2K_kg.ready array @@ -344,7 +344,7 @@ Samples Important Cases -^^^^^^^^^^^^^^^ +~~~~~~~~~~~~~~~ * H2K_ready_getbest when ready list is empty * H2K_ready_getbest when ready list has one thread @@ -361,7 +361,7 @@ Important Cases * Check H2K_ready_init clears out randomized values Harness -^^^^^^^ +~~~~~~~ The readylist module is reasonably self-contained, so the test harness will only use the header file and object file. From f381eac15dd8770c85497248d97474c8410ebd6c Mon Sep 17 00:00:00 2001 From: Zeev Belinsky Date: Mon, 20 Jul 2026 00:54:30 -0700 Subject: [PATCH 7/7] . Signed-off-by: Zeev Belinsky --- kernel/data/readylist/readylist.h | 2 +- kernel/traps/config/test/test.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/data/readylist/readylist.h b/kernel/data/readylist/readylist.h index 01f9d4f94..334c714bb 100644 --- a/kernel/data/readylist/readylist.h +++ b/kernel/data/readylist/readylist.h @@ -40,7 +40,7 @@ static inline u32_t H2K_ready_any_valid() /* Check whether a thread at a given priority is ready */ static inline u32_t H2K_ready_prio_valid(u32_t prio) { - if (prio > WAITING_PRIO) return 0; + if (prio > MAX_PRIO) return 0; return (H2K_gp->ready_valids[prio >> 6] & (1ULL << (prio & 0x3f))) != 0; } diff --git a/kernel/traps/config/test/test.c b/kernel/traps/config/test/test.c index 1b9267e21..c4f4e639a 100644 --- a/kernel/traps/config/test/test.c +++ b/kernel/traps/config/test/test.c @@ -134,7 +134,7 @@ int main() DPRINTF("SET_PRIO_TRAPMASK\n\n"); /* SET_PRIO_TRAPMASK bad prio */ - ret = H2K_trap_config(CONFIG_VMBLOCK_INIT, vm, SET_PRIO_TRAPMASK, WAITING_PRIO + 1, 0, NULL); + ret = H2K_trap_config(CONFIG_VMBLOCK_INIT, vm, SET_PRIO_TRAPMASK, MAX_PRIO + 1, 0, NULL); if (ret!= 0) FAIL("Missed bad prio"); /* SET_PRIO_TRAPMASK */