20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/linker/KernelElf.h"
22#include "pedigree/kernel/machine/Machine.h"
23#include "pedigree/kernel/panic.h"
24#include "pedigree/kernel/process/Process.h"
25#include "pedigree/kernel/process/Scheduler.h"
26#include "pedigree/kernel/process/Thread.h"
27#include "pedigree/kernel/processor/Processor.h"
28#include "pedigree/kernel/processor/SyscallManager.h"
29#include "pedigree/kernel/utilities/ZombieQueue.h"
32#include "PosixSubsystem.h"
33#include "PosixSyscallManager.h"
36#include "modules/Module.h"
39#include "modules/system/vfs/MountView.h"
40#include "modules/system/vfs/VFS.h"
41#include "net-syscalls.h"
42#include "process-accounting.h"
43#include "signal-syscalls.h"
44#include "system-syscalls.h"
46#if X64 && PEDIGREE_VM_REMAP_TESTS
47extern "C" bool x64RemapCoreRegression();
50#if !HOSTED && PEDIGREE_VM_OWNERSHIP_SMOKE_TESTS
51extern bool runVmMappedOwnershipRegressions();
53#if !HOSTED && PEDIGREE_MEMORY_LOCK_TESTS
54extern bool runMemoryLockRegressions();
56#if !HOSTED && PEDIGREE_REMAP_FILE_PAGES_TESTS
57extern bool runRemapFilePagesRegressions();
59#if !HOSTED && PEDIGREE_PROCESS_MEMORY_TESTS
60extern bool processMemoryBackendRegression();
61extern bool processVmRegression();
63#if !HOSTED && PEDIGREE_UTS_NAMESPACE_TESTS
64extern bool utsNamespaceRegression();
70static RamFs* g_pRunFilesystem = 0;
71static RamFs* g_pDevShmFilesystem =
nullptr;
72static SysFs* g_pSysFs =
nullptr;
77enum class PosixTerminalLifetimeState {
83static PosixTerminalLifetimeState g_PosixTerminalLifetime = PosixTerminalLifetimeState::Unowned;
86 return manager.shutdown();
91struct TerminalDrainStats {
93 : syntheticOwners(0), zeroThreadProcesses(0), threadedProcesses(0), zombies(0) {}
95 size_t syntheticOwners;
96 size_t zeroThreadProcesses;
97 size_t threadedProcesses;
101int terminalProcessExit(
void* parameter) {
107void drainPosixProcesses(TerminalDrainStats& stats) {
115 if (state == Process::Active || state == Process::Suspended) {
123 if (currentState == Process::Active || currentState == Process::Suspended) {
124 panic(
"POSIX shutdown could not reserve its active terminal exit owner");
129 ++stats.threadedProcesses;
131 ++stats.zeroThreadProcesses;
136 panic(
"POSIX shutdown found a process without its subsystem");
139 new Thread(process.get(), terminalProcessExit, subsystem,
nullptr,
false,
true,
true);
140 ownerIdentity->setName(
"POSIX terminal exit owner");
141 reservation.
install(ownerIdentity);
145 panic(
"POSIX shutdown lost its reserved terminal exit owner");
147 if (!owner->start()) {
148 panic(
"POSIX shutdown could not start its reserved terminal exit owner");
150 ++stats.syntheticOwners;
158 panic(
"POSIX shutdown attempted to reap its own exit owner");
161 Process* processIdentity = process.get();
172 if (!ZombieQueue::instance().drain()) {
173 panic(
"POSIX shutdown could not drain process destruction");
179 if (!ZombieQueue::instance().drain()) {
180 panic(
"POSIX shutdown could not complete its final process drain");
186static bool terminalQuiesce() {
187 if (g_PosixTerminalLifetime == PosixTerminalLifetimeState::Quiesced) {
190 if (g_PosixTerminalLifetime != PosixTerminalLifetimeState::HookOwned) {
201 if (!g_PosixSyscallManager.closeAdmission()) {
205#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
206 NOTICE(
"HOSTED-POSIX-SHUTDOWN: PHASE syscall-admission-closed");
210 TerminalDrainStats stats;
212 drainPosixProcesses(stats);
213#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
214 NOTICE(
"HOSTED-POSIX-SHUTDOWN: PHASE initial-process-drain-complete");
219 if (!g_PosixSyscallManager.finishShutdown()) {
223#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
224 NOTICE(
"HOSTED-POSIX-SHUTDOWN: PHASE syscall-handler-drain-complete");
231 drainPosixProcesses(stats);
233 if (maps.swapSnapshot().active) {
234 const auto swapStatus = maps.deactivateSwap(SwapStore::instance().endpointId());
235 if (swapStatus != SwapStatus::Success) {
236 WARNING(
"POSIX shutdown could not drain swap; storage retained (status "
237 <<
static_cast<size_t>(swapStatus) <<
")");
241#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
242 NOTICE(
"HOSTED-POSIX-SHUTDOWN: PHASE final-process-drain-complete");
247 posix_stop_accounting();
261 Filesystem* backings[] = {g_pProcFs, g_pDevShmFilesystem, g_pDevFs, g_pRunFilesystem, g_pSysFs};
262 for (
auto* backing : backings)
263 if (backing && !view->detachBackingForShutdown(backing))
266 g_PosixTerminalLifetime = PosixTerminalLifetimeState::Quiesced;
268#if THREADS && HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
269 NOTICE(
"HOSTED-POSIX-SHUTDOWN: PASS terminal-drain synthetic="
270 << stats.syntheticOwners <<
" zero-thread=" << stats.zeroThreadProcesses
271 <<
" threaded=" << stats.threadedProcesses <<
" zombies=" << stats.zombies);
277#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
278extern "C" EXPORTED_PUBLIC
bool posixDuplicateInitRollbackPreservesProcessForTest(
281 const bool duplicateRejected = !duplicate.initialise();
282 if (!retireUnownedSyscallRegistrations(duplicate)) {
288 process->getType() == Process::Posix && process->getState() == Process::Active;
293 if (!g_PosixSyscallManager.initialise()) {
297 g_pDevFs =
new DevFs();
303 g_pSysFs =
new SysFs();
304 if (!g_pSysFs || !g_pSysFs->
initialise(
nullptr))
307 g_pRunFilesystem =
new RamFs;
309 g_pDevShmFilesystem =
new RamFs;
310 if (!g_pDevShmFilesystem || !g_pDevShmFilesystem->
initialise(
nullptr))
312 g_pUnixSocketBacking = g_pRunFilesystem;
329 g_PosixTerminalLifetime = PosixTerminalLifetimeState::HookOwned;
335 if (!view->createBootContext(bootstrap))
337 auto context = bootstrap.reference();
341 } attachments[] = {{
"/dev", g_pDevFs}, {
"/dev/shm", g_pDevShmFilesystem},
342 {
"/run", g_pRunFilesystem}, {
"/proc", g_pProcFs},
343 {
"/sys", g_pSysFs}, {
"/tmp", scratchfs}};
345 options.requireDirectory =
true;
346 options.crossFinalMount =
false;
347 for (
const auto& attachment : attachments) {
348 if (!attachment.backing)
352 ERROR(
"failed to resolve attachment for " << attachment.path);
354 if (!view->attach(context, covered, attachment.backing)) {
355 ERROR(
"failed to finalize attachment for " << attachment.path);
360 pedigree_std::move(bootstrap)))
363#if X64 && PEDIGREE_VM_REMAP_TESTS
364 NOTICE(
"VM-REMAP-CORE: BEGIN");
365 if (!x64RemapCoreRegression()) {
366 FATAL(
"VM-REMAP-CORE: FAIL");
368 NOTICE(
"VM-REMAP-CORE: PASS");
370#if !HOSTED && PEDIGREE_VM_OWNERSHIP_SMOKE_TESTS
371 if (!runVmMappedOwnershipRegressions()) {
372 FATAL(
"QEMU mapped ownership regression failed");
375#if !HOSTED && PEDIGREE_MEMORY_LOCK_TESTS
376 if (!runMemoryLockRegressions()) {
377 FATAL(
"Memory-lock residency regression failed");
380#if !HOSTED && PEDIGREE_REMAP_FILE_PAGES_TESTS
381 if (!runRemapFilePagesRegressions()) {
382 FATAL(
"File-offset remapping regression failed");
385#if !HOSTED && PEDIGREE_PROCESS_MEMORY_TESTS
386 if (!processMemoryBackendRegression() || !processVmRegression()) {
387 FATAL(
"Process-memory copy regression failed");
390#if !HOSTED && PEDIGREE_UTS_NAMESPACE_TESTS
391 if (!utsNamespaceRegression()) {
392 FATAL(
"UTS namespace lifecycle regression failed");
395#if !HOSTED && PEDIGREE_AFFINITY_TESTS
396 extern bool runAffinityRegressions();
397 if (!runAffinityRegressions()) {
398 FATAL(
"Scheduler affinity regression failed");
401#if !HOSTED && PEDIGREE_CHILD_WAIT_TESTS
402 extern bool runChildWaitRegressions();
403 if (!runChildWaitRegressions()) {
404 FATAL(
"Child wait regression failed");
407#if !HOSTED && PEDIGREE_PTRACE_TESTS
408 extern bool runPtraceFrameRegressions();
409 if (!runPtraceFrameRegressions()) {
410 FATAL(
"Tracing frame regression failed");
416static void destroy() {
417 if (g_PosixTerminalLifetime == PosixTerminalLifetimeState::HookOwned) {
419 panic(
"POSIX terminal quiesce ownership could not be released safely.");
423 if (!terminalQuiesce()) {
424 panic(
"POSIX syscall handlers could not be retired safely.");
426 }
else if (g_PosixTerminalLifetime == PosixTerminalLifetimeState::Unowned) {
429 if (!retireUnownedSyscallRegistrations(g_PosixSyscallManager)) {
430 panic(
"Partial POSIX syscall handlers could not be retired safely.");
434 if (g_pProcFs && !
VFS::instance().unregisterFilesystem(g_pProcFs,
false)) {
435 panic(
"POSIX shutdown could not retire procfs");
437 if (g_pDevFs && !
VFS::instance().unregisterFilesystem(g_pDevFs,
false)) {
438 panic(
"POSIX shutdown could not retire devfs");
440 if (g_pSysFs && !
VFS::instance().unregisterFilesystem(g_pSysFs,
false)) {
441 panic(
"POSIX shutdown could not retire sysfs");
443 if (g_pDevShmFilesystem && !
VFS::instance().unregisterFilesystem(g_pDevShmFilesystem,
false)) {
444 panic(
"POSIX shutdown could not retire shmfs");
446 if (g_pRunFilesystem && !
VFS::instance().unregisterFilesystem(g_pRunFilesystem,
false)) {
447 panic(
"POSIX shutdown could not retire runfs");
450 g_pUnixSocketBacking =
nullptr;
451 delete g_pRunFilesystem;
452 delete g_pDevShmFilesystem;
456 g_pRunFilesystem =
nullptr;
457 g_pDevShmFilesystem =
nullptr;
463MODULE_INFO_RUNTIME_PINNED(
"posix", &init, &destroy,
"console",
"network-stack",
"mountroot",
466MODULE_OPTIONAL_DEPENDS(
"ps2mouse",
"gfx-deps",
"virtio-rng");
Memory-mapped file interface.
virtual bool initialise(Disk *pDisk)
static KernelElf & instance()
static void setShutdownPhase(ShutdownPhase phase, const char *detail=nullptr)
static MemoryMapManager & instance()
void exit(int code, ExitCause cause=ExitCause::Normal) NORETURN
virtual bool initialise(Disk *pDisk)
void install(Thread *owner)
bool waitUntilTerminationReapableForTerminalCoordinator()
MUST_USE_RESULT bool acquireThread(ThreadLease &lease, size_t n)
TerminalOwnerReservation reserveTerminalOwner()
ReaperClaim tryClaimReaper()
static ProcessorInformation & information()
static ExecutionContext executionContext()
virtual bool initialise(Disk *pDisk) override
static Scheduler & instance()
MUST_USE_RESULT bool acquireProcess(ProcessLease &lease, size_t n)
void waitUntilProcessRemoved(Process *expected)
bool initialise(Disk *) override
Filesystem * getFilesystemAt(const String &path) const
String registerFilesystem(Filesystem *pFs, const String &preferredStableName)
bool createDirectory(const String &path, uint32_t mask, File *pStartNode=0)
void EXPORTED_PUBLIC panic(const char *msg) NORETURN