The Pedigree Project 0.1
textio-regressions.cc
1/*
2 * Copyright (c) 2026, Pedigree Developers
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted.
6 */
7
8#include "pedigree/kernel/Atomic.h"
9#include "pedigree/kernel/Log.h"
10#include "pedigree/kernel/process/Process.h"
11#include "pedigree/kernel/process/Scheduler.h"
12#include "pedigree/kernel/process/Thread.h"
13
14#include "modules/system/console/TextIO.h"
15
16namespace {
17struct TextIoCreatorContext {
18 explicit TextIoCreatorContext(TextIO* textio) : textio(textio), initialised(false) {}
19
20 TextIO* textio;
21 Atomic<bool> initialised;
22};
23
24int initialiseTextIo(void* parameter) {
25 TextIoCreatorContext* context = reinterpret_cast<TextIoCreatorContext*>(parameter);
26 context->initialised = context->textio->initialise(true);
27 return 0;
28}
29
30int terminateProcess(void* parameter) {
31 reinterpret_cast<Process*>(parameter)->kill();
32}
33} // namespace
34
35bool runTextIoFlipLifetimeRegression() {
36 NOTICE("QEMU-CONCURRENCY-TEST: BEGIN textio-flip-kernel-owner");
37
38 Process* kernelProcess = Scheduler::instance().getKernelProcess();
39 Process* creatorProcess = new Process(kernelProcess);
40 TextIO* textio = new TextIO(String("textio-lifetime-probe"), 0, nullptr, nullptr);
41 TextIoCreatorContext context(textio);
42
44 new Thread(creatorProcess, initialiseTextIo, &context, nullptr, false, true, true);
45 creator->setName("TextIO disposable creator");
46 if (!creator->start() || !creator->joinForCompletion() || !context.initialised) {
47 FATAL("QEMU TextIO lifetime probe could not initialise its terminal");
48 }
49
50 // The terminal outlives the process which requested it. Its worker must not
51 // join that process's exit rendezvous or become owned by its reaper.
52 if (creatorProcess->getNumThreads() != 0) {
53 delete textio;
54 delete creatorProcess;
55 FATAL("QEMU TextIO flip worker remained owned by its disposable creator process");
56 }
57
58 Thread* terminator =
59 new Thread(creatorProcess, terminateProcess, creatorProcess, nullptr, false, true, true);
60 terminator->setName("TextIO disposable process terminator");
61 if (!terminator->start() || !creatorProcess->waitUntilTerminationReapable()) {
62 FATAL("QEMU TextIO lifetime probe could not reap its disposable creator process");
63 }
64 delete creatorProcess;
65
66 if (!textio->initialise(false)) {
67 FATAL("QEMU TextIO lifetime probe could not restart its surviving flip worker");
68 }
69 textio->writeStr("", 0);
70 delete textio;
71
72 NOTICE("QEMU-CONCURRENCY-TEST: PASS textio-flip-kernel-owner");
73 return true;
74}
size_t getNumThreads()
Definition Process.cc:1380
bool waitUntilTerminationReapable()
Definition Process.cc:2270
static Scheduler & instance()
Definition Scheduler.h:96
bool initialise(bool bClear=true)
Definition TextIO.cc:139
void writeStr(const char *s, size_t len)
Definition TextIO.cc:492
bool start()
Definition Thread.cc:751