diff --git a/nwnss-audit.md b/nwnss-audit.md index 54068d4..b713802 100644 --- a/nwnss-audit.md +++ b/nwnss-audit.md @@ -120,7 +120,7 @@ still stay original and remain listed, because later imports may rely on them. | AUDITED | `src/nwnss/library/misc/rand.c` | PORT | nwnss.rand, nwnss.namespace | No original provider found beyond rand.h/libNSS.imp/callers; seed-deterministic PRNG port checked in 0700/0701/0718; also provides xStdlib.h rand/random/srand/srandom/initstate/setstate wrappers; libsodium only initializes default state before explicit seeding. | | AUDITED | `src/nwnss/library/misc/rbpTree.c` | PORT | nwnss.rbpTree | No original provider found beyond rbpTree.h/libNSS.imp/callers; CLRS-style algorithmic port checked against header contract in 0703 and strengthened in 0705 with explicit red/black, parent-link, binary-search-order, black-height, and Coin3D-style insertion/deletion stress coverage. Coin3D rbptree.cpp was checked only as an external BSD-licensed CLRS comparison and was not imported. | | AUDITED | `src/nwnss/library/os/currentTime.c` | PORT | nwnss.utc | No userspace original provider exists after checking `public_core/library/utc` and `public_core/sharedsrc`; `public_core/nsslnxlib/nssLnxDummy.c` has a kernel jiffies-oriented `GetCurrentTime`, while `public_core/library/utc/gethres.386` documents the high-resolution timer unit as 100 microseconds. The userspace port keeps `GetCurrentTime()` on a monotonic centisecond/HZ=100 scale and now exposes `GetHighResolutionTimer()` on the documented 1/10000-second scale for checker/compression callers; covered by nwnss.utc. | -| AUDITED | `src/nwnss/library/os/delay.c` | ORIG+FIX/PORT | nwnss.schedule, nwnss.snooze | Scheduler functions kept as functions, not macros; checked in 0688-0690. | +| AUDITED | `src/nwnss/library/os/delay.c` | ORIG+FIX/PORT | nwnss.schedule, nwnss.snooze | Scheduler functions kept as userspace functions, not macros; original `ZOS_YieldThread`/sleep/schedule lock-boundary behavior rechecked against `nssOSAPIs.h`, and userspace yield now drops/reacquires MPKNSS when owned so other threads can run without the global lock held. | | AUDITED | `src/nwnss/library/os/nebEventPort.c` | PORT | nwnss.neb | Explicit NEB/nebus service port; checked in 0683-0685. | | AUDITED | `src/nwnss/library/os/pssmpk.c` | PORT | nwnss.pssmpk | pthread owner semantics checked/fixed in 0692. | | AUDITED | `src/nwnss/library/stdlib/strtol.c` + `include/nwnss/library/xStdlib.h` | PORT + ORIG+FIX header | nwnss.stdlib | No LB_strtol original/sharedsrc found after full NSS/nss-common search; Novell/POSIX strtol semantics mapped to host libc and hardened in 0708. | @@ -644,7 +644,7 @@ even if it already compiles or has indirect test coverage. | AUDITED | ORIG+FIX/PORT | nwnss.alarm | `src/nwnss/library/os/alarm.c` | Compared with original `public_core/library/os/alarm.c`; alarm wheel/one-shot/cyclic logic kept. Userspace port removes kernel timer semaphore/work callback re-arm, adds typed callbacks and include-path/HZ compatibility; tests cover immediate/delayed/canceled one-shots, cyclic requeue and alarm stop. | | AUDITED | ORIG+FIX | nwnss.config | `src/nwnss/library/os/config.c` | Compared with original `public_core/library/os/config.c`; Config initializer and startup-derived hash/tick fields kept. Differences are linux/module.h removal, include-path normalization and whitespace cleanup; tests cover defaults, hash masks, tick conversions and LV purge defaults. | | AUDITED | PORT | nwnss.utc | `src/nwnss/library/os/currentTime.c` | No userspace original provider exists after checking `public_core/library/utc` and `public_core/sharedsrc`; `public_core/nsslnxlib/nssLnxDummy.c` has a kernel jiffies-oriented `GetCurrentTime`, while `public_core/library/utc/gethres.386` documents the high-resolution timer unit as 100 microseconds. The userspace port keeps `GetCurrentTime()` on a monotonic centisecond/HZ=100 scale and now exposes `GetHighResolutionTimer()` on the documented 1/10000-second scale for checker/compression callers; covered by nwnss.utc. | -| AUDITED | ORIG+FIX/PORT | nwnss.schedule, nwnss.snooze | `src/nwnss/library/os/delay.c` | Scheduler functions kept as functions, not macros; checked in 0688-0690. | +| AUDITED | ORIG+FIX/PORT | nwnss.schedule, nwnss.snooze | `src/nwnss/library/os/delay.c` | Compared with original `public_core/library/os/delay.c` and the original scheduler macros in `shared/sdk/internal/nssOSAPIs.h`; userspace keeps the scheduler API as real functions. `LB_delay`, `ZOS_Sleep`, `ZOS_ScheduleWorkToDo` and now `ZOS_YieldThread` preserve the original MPKNSS scheduling boundary by dropping/reacquiring the global lock when the current thread owns it; tests cover locked delay, schedule callbacks outside the lock and yield allowing another thread through the lock boundary. | | AUDITED | ORIG+FIX | nwnss.inst | `src/nwnss/library/os/inst.c` | Compared with original `public_core/library/os/inst.c`; instrumentation harvest/reset/init logic kept. Differences are linux/module.h removal and include-path normalization; tests cover file/cache/Linux/BST counter harvest/reset and cyclic init wiring. | | AUDITED | ORIG+FIX | nwnss.mailbox | `src/nwnss/library/os/mailbox.c` | Compared with original `public_core/library/os/mailbox.c`; mbInit/mbSetHigh behavior kept. Differences are procdefs/include-path normalization and whitespace cleanup; tests cover empty/full/FIFO, peek/drop, next/give and wraparound behavior. | | AUDITED | PORT | nwnss.neb | `src/nwnss/library/os/nebEventPort.c` | Explicit NEB/nebus service port; checked in 0683-0685. | diff --git a/src/nwnss/library/os/delay.c b/src/nwnss/library/os/delay.c index 7c3c142..e744823 100644 --- a/src/nwnss/library/os/delay.c +++ b/src/nwnss/library/os/delay.c @@ -86,7 +86,19 @@ THREAD kCurrentThread(void) void ZOS_YieldThread(void) { + BOOL hadLock = MPKNSS_I_OWN_SPINLOCK(); + + if (hadLock) + { + MPKNSS_UNLOCK(); + } + sched_yield(); + + if (hadLock) + { + MPKNSS_LOCK(); + } } void CYieldUntilIdle(void) diff --git a/tests/nwnss/schedule/test_nwnss_schedule.c b/tests/nwnss/schedule/test_nwnss_schedule.c index aac06bd..79e927c 100644 --- a/tests/nwnss/schedule/test_nwnss_schedule.c +++ b/tests/nwnss/schedule/test_nwnss_schedule.c @@ -3,6 +3,9 @@ #include #include +#include +#include + #define CHECK(expr) do { if (!(expr)) return __LINE__; } while (0) extern LONG Delayed; @@ -11,6 +14,19 @@ static int scheduled_called; static int scheduled_saw_lock; static void *scheduled_arg; +static volatile int yield_waiter_state; + +static void *yield_waiter(void *arg) +{ + (void)arg; + + yield_waiter_state = 1; + MPKNSS_LOCK(); + yield_waiter_state = 2; + MPKNSS_UNLOCK(); + return NULL; +} + static void scheduled_callback(void *arg) { scheduled_called++; @@ -23,6 +39,8 @@ int main(void) LONG before; zWorkProc_s work; THREAD self; + pthread_t waiter; + int spins; MPKNSS_INIT_LOCK(); @@ -51,6 +69,20 @@ int main(void) ZOS_WakeUp(self); Continue(self); + yield_waiter_state = 0; + CHECK(MPKNSS_LOCK()); + CHECK(pthread_create(&waiter, NULL, yield_waiter, NULL) == 0); + for (spins = 0; spins < 100000 && yield_waiter_state == 0; ++spins) + { + sched_yield(); + } + CHECK(yield_waiter_state == 1); + ZOS_YieldThread(); + CHECK(MPKNSS_I_OWN_SPINLOCK()); + CHECK(yield_waiter_state == 2); + CHECK(MPKNSS_UNLOCK()); + CHECK(pthread_join(waiter, NULL) == 0); + CHECK(ZOS_ScheduleWorkToDo(NULL) == zERR_BAD_PARAMETER_VALUE); CHECK(ZOS_CancelWorkToDo(NULL) == zOK);