From 86ef404a1f830cf82538af7eea9eb8285b6ddb70 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 11 Sep 2026 16:10:55 +0200 Subject: [PATCH] test: add more cases for schedTest --- src/schedTest.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/src/schedTest.c b/src/schedTest.c index 707bc8d..68b29a5 100644 --- a/src/schedTest.c +++ b/src/schedTest.c @@ -1254,3 +1254,160 @@ KTEST(threadCreateDefaultsPgidToItsOwnIdWhenCurrentIsTheIdleThread) KT_TRUE(t, threadDiscard(id)); } +KTEST(threadCreateUserDefaultsPgidToItsOwnIdWhenCurrentIsTheIdleThread) +{ + uint64 entry = 0x350000000ull + 0x2000; + uint32 id = threadCreateUser("pgidDefaultUser", entry, elfSlotStackTop(entry)); + KT_NE(t, id, threadInvalidId); + KT_EQU(t, threadAt(id)->pgid, id); + KT_TRUE(t, threadDiscard(id)); +} + +/* + * Thread.uid (sched.h) -- the credential vfs.c's vfsPermitted consults + * alongside a file's own owner uid and mode (see coreTest.c's own + * vfsPermitted coverage for that pure-logic half). Same "ktestRunAll + * always runs as the idle thread" reasoning as the pgid tests immediately + * above applies here too: every plain threadCreate/threadCreateUser call + * exercises the "boot-time thread starts as uid 0" default; the OTHER + * default (a runtime child inheriting a genuinely running, non-root + * parent's uid) can only ever be exercised by a real ring-3 userSpawn, + * which is why user/identtest.c's own inheritance-then-drop demo is this + * feature's live proof instead. currentThreadSetUid's own privilege rule + * (root may become anyone; anyone else only their own current uid) is + * likewise never exercised here on purpose: it can only ever act on + * "whoever is currently running" (see its own doc comment), and mutating + * ktestRunAll's own idle-thread uid away from 0 would permanently corrupt + * every later test AND every boot-time spawnUser call still to come after + * ktestRunAll returns -- a real, one-way privilege drop is exactly the + * kind of state no shared test-suite context may ever touch. + */ + +KTEST(threadCreateDefaultsUidToRootWhenCurrentIsTheIdleThread) +{ + uint32 id = threadCreate("uidDefaultKernel", noopThreadEntry); + KT_NE(t, id, threadInvalidId); + KT_EQU(t, threadAt(id)->uid, 0u); + KT_TRUE(t, threadDiscard(id)); +} + +KTEST(threadCreateUserDefaultsUidToRootWhenCurrentIsTheIdleThread) +{ + uint64 entry = 0x350000000ull + 0x2000; + uint32 id = threadCreateUser("uidDefaultUser", entry, elfSlotStackTop(entry)); + KT_NE(t, id, threadInvalidId); + KT_EQU(t, threadAt(id)->uid, 0u); + KT_TRUE(t, threadDiscard(id)); +} + +KTEST(threadPgidReturnsInvalidForOutOfRangeOrNeverCreatedSlots) +{ + KT_EQU(t, threadPgid(threadCapacity()), threadInvalidId); + KT_EQU(t, threadPgid(threadCapacity() + 1000), threadInvalidId); + + uint32 neverUsed = threadCount(); + if (neverUsed < threadCapacity()) + KT_EQU(t, threadPgid(neverUsed), threadInvalidId); +} + +KTEST(threadPgidReturnsInvalidAfterDiscardOrReap) +{ + uint32 id = threadCreate("pgidGoneAfterDiscard", noopThreadEntry); + KT_NE(t, id, threadInvalidId); + KT_EQU(t, threadPgid(id), id); + + KT_TRUE(t, threadDiscard(id)); + KT_EQU(t, threadPgid(id), threadInvalidId); +} + +KTEST(threadSetPgidRejectsIdleOutOfRangeAndNeverCreatedSlots) +{ + KT_FALSE(t, threadSetPgid(0, 1)); + KT_FALSE(t, threadSetPgid(threadCapacity(), 1)); + KT_FALSE(t, threadSetPgid(threadCapacity() + 1000, 1)); + + uint32 neverUsed = threadCount(); + if (neverUsed < threadCapacity()) + KT_FALSE(t, threadSetPgid(neverUsed, 1)); +} + +KTEST(threadSetPgidChangesGroupOfALiveThread) +{ + uint32 leader = threadCreate("pgidLeader", noopThreadEntry); + uint32 joiner = threadCreate("pgidJoiner", noopThreadEntry); + KT_NE(t, leader, threadInvalidId); + KT_NE(t, joiner, threadInvalidId); + + /* Each started as its own group leader (the KTEST-runs-as-idle default + above) -- explicitly move joiner into leader's group, exactly like a + real setpgid(joinerPid, leaderPid) call. */ + KT_NE(t, threadAt(joiner)->pgid, threadAt(leader)->pgid); + KT_TRUE(t, threadSetPgid(joiner, threadAt(leader)->pgid)); + KT_EQU(t, threadAt(joiner)->pgid, threadAt(leader)->pgid); + + KT_TRUE(t, threadDiscard(leader)); + KT_TRUE(t, threadDiscard(joiner)); +} + +KTEST(threadSetPgidRejectsDeadOrUnusedTarget) +{ + uint32 id = threadCreate("pgidSetOnDead", noopThreadEntry); + KT_NE(t, id, threadInvalidId); + + KT_TRUE(t, threadKill(id)); + KT_FALSE(t, threadSetPgid(id, 12345)); + + KT_TRUE(t, threadReap(id)); + KT_FALSE(t, threadSetPgid(id, 12345)); +} + +KTEST(threadPriorityDefaultsToSchedDefaultWeightForANewThread) +{ + uint32 id = threadCreate("priorityDefault", noopThreadEntry); + KT_NE(t, id, threadInvalidId); + KT_EQU(t, threadPriority(id), schedDefaultWeight); + KT_TRUE(t, threadDiscard(id)); +} + +KTEST(threadPriorityReturnsZeroForOutOfRangeOrNeverCreatedSlots) +{ + KT_EQU(t, threadPriority(threadCapacity()), 0u); + KT_EQU(t, threadPriority(threadCapacity() + 1000), 0u); + + uint32 neverUsed = threadCount(); + if (neverUsed < threadCapacity()) + KT_EQU(t, threadPriority(neverUsed), 0u); +} + +KTEST(threadPriorityReturnsZeroAfterDiscard) +{ + uint32 id = threadCreate("priorityGoneAfterDiscard", noopThreadEntry); + KT_NE(t, id, threadInvalidId); + KT_EQU(t, threadPriority(id), schedDefaultWeight); + + KT_TRUE(t, threadDiscard(id)); + KT_EQU(t, threadPriority(id), 0u); +} + +KTEST(threadSetPriorityRejectsIdleOutOfRangeZeroWeightAndNeverCreatedSlots) +{ + KT_FALSE(t, threadSetPriority(0, 2048)); + KT_FALSE(t, threadSetPriority(threadCapacity(), 2048)); + KT_FALSE(t, threadSetPriority(threadCapacity() + 1000, 2048)); + + uint32 id = threadCreate("priorityRejectZero", noopThreadEntry); + KT_NE(t, id, threadInvalidId); + KT_FALSE(t, threadSetPriority(id, 0)); + KT_EQU(t, threadPriority(id), schedDefaultWeight); + KT_TRUE(t, threadDiscard(id)); + + uint32 neverUsed = threadCount(); + if (neverUsed < threadCapacity()) + KT_FALSE(t, threadSetPriority(neverUsed, 2048)); +} + +KTEST(threadSetPriorityChangesWeightOfALiveThread) +{ + uint32 id = threadCreate("priorityChange", noopThreadEntry); + KT_NE(t, id, threadInvalidId); +