Files
NX2navi/runtime/kernel.h
chrg6 745d48bc8c Free released recording copies outside their lock, skip the yield's lock and scans when nobody waits for a core, and wait instead of spinning before a paced frame.
Found by profiling a play session and reading the kernel and the command recording:
- nvn_api_cmd.c: a released recording copy had its pins uncounted (a walk over every op) and was freed while copy_lock was held exclusively; the main-loop thread waited for that lock 2.8% of its time. The copies are now chained under the lock and freed after it. The walks over a recording's records test a mask of the five op kinds that name pins before calling op_pins.
- kernel.c: SleepThread(0) took the kernel lock and computed the caller's inherited priority, a scan over every blocked thread, also when no thread waited for a core, which is nearly always. It now yields at once then. A wait without a timeout no longer reads the clock.
- nvn_api_obj.c sleep_until: the wait for a paced frame's slot slept coarsely and left the last 1 to 2 ms to a yield loop; the high-resolution wait now takes all but its own margin.
- input.c: the keyboard scan (a system call per key) is reused for reads within a millisecond.
- nvn_api_core.c: the read-lock observer's commit-point address is 1.2.1's and is now only compared there.
- kernel_probe.c: the probe expected three virtual cores and wait type 3 to be refused; the kernel has six cores and implements the 64-bit wait. It now checks both as they are, counts a core number past the cores as a clash without unbalancing core 0, and --probe-kernel passes again.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
(cherry picked from commit a3dbd63878d7d6de096ceb4c25988192b4bce738)
2026-11-09 20:48:10 -05:00

43 lines
2.1 KiB
C

// Kernel internals shared by kernel.c, svc.c and the kernel probe (kernel_probe.c). Not part of the host.h contract.
#pragma once
#include "host.h"
// Horizon kernel results (module 1).
#define KERN_R_OUT_OF_RESOURCE 0xCE01u
#define KERN_R_INVALID_STATE_MEM 0xD401u
#define KERN_R_BAD_HANDLE 0xE401u
#define KERN_R_TIMEOUT 0xEA01u
#define KERN_R_CANCELLED 0xEC01u
#define KERN_R_INVALID_ENUM 0xF001u
#define KERN_R_BAD_STATE 0xFA01u
#define KERN_H_CURRENT_THREAD 0xFFFF8000u
#define KERN_WAITERS_BIT 0x40000000u
// Fiber overrides, linked as HOST_OVERRIDE entries in kernel.c.
#define KERN_SYM_INITIALIZE_FIBER "_ZN2nn2os15InitializeFiberEPNS0_9FiberTypeEPFS2_PvES3_S3_mi"
#define KERN_SYM_FINALIZE_FIBER "_ZN2nn2os13FinalizeFiberEPNS0_9FiberTypeE"
#define KERN_SYM_SWITCH_TO_FIBER "_ZN2nn2os13SwitchToFiberEPNS0_9FiberTypeE"
#define KERN_SYM_GET_CURRENT_FIBER "_ZN2nn2os15GetCurrentFiberEv"
void kern_fiber_initialize(Cpu *c);
void kern_fiber_finalize(Cpu *c);
void kern_fiber_switch(Cpu *c);
void kern_fiber_current(Cpu *c);
uint64_t kern_threads_created(void);
void kern_seed_tls(void); // put the running thread's TLS where the SDK looks for it (TLR+0x1F0)
// The guest frame-pointer chain from c->x[29] to stderr.
void kern_backtrace(const Cpu *c);
// ---- probe support
enum { KERN_WAIT_NONE, KERN_WAIT_LOCK, KERN_WAIT_CONDVAR, KERN_WAIT_ADDRESS, KERN_WAIT_SYNC };
#define KERN_THREAD_EXITED 100
int kern_thread_state(uint32_t handle); // KERN_WAIT_*, KERN_THREAD_EXITED, or -1 for a bad handle
void kern_core_stats(int *held_now, int *held_max); // virtual-core holders now and the most ever at once
void kern_core_stats_reset(void);
int kern_cores(void); // the virtual cores that run threads: 6, or NX2NAVI_CORES
extern volatile int kern_test_cv_old_order; // WaitProcessWideKeyAtomic: release the lock before setting
// the key (the old order, the negative control)
extern void (*volatile kern_test_cv_hook)(void); // called right after the lock release, holding the kernel lock
extern void (*volatile svc_test_exit_hook)(unsigned code); // svc 0x07 calls it instead of ExitProcess (probes)