feat: add inherited sessions and desktop session teardown
This commit is contained in:
@@ -159,6 +159,14 @@ namespace montauk::abi {
|
|||||||
return Sched::KillProcess(pid);
|
return Sched::KillProcess(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int Sys_SetSession() {
|
||||||
|
return Sched::CreateSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int Sys_KillSession(int sessionId) {
|
||||||
|
return Sched::KillSession(sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
static int Sys_SetUser(int pid, const char* name) {
|
static int Sys_SetUser(int pid, const char* name) {
|
||||||
if (name == nullptr) return -1;
|
if (name == nullptr) return -1;
|
||||||
auto* target = Sched::GetProcessByPid(pid);
|
auto* target = Sched::GetProcessByPid(pid);
|
||||||
|
|||||||
@@ -359,6 +359,10 @@ namespace montauk::abi {
|
|||||||
return (int64_t)Sys_ProcList((ProcInfo*)frame->arg1, (int)frame->arg2);
|
return (int64_t)Sys_ProcList((ProcInfo*)frame->arg1, (int)frame->arg2);
|
||||||
case SYS_KILL:
|
case SYS_KILL:
|
||||||
return (int64_t)Sys_Kill((int)frame->arg1);
|
return (int64_t)Sys_Kill((int)frame->arg1);
|
||||||
|
case SYS_SETSESSION:
|
||||||
|
return (int64_t)Sys_SetSession();
|
||||||
|
case SYS_KILLSESSION:
|
||||||
|
return (int64_t)Sys_KillSession((int)frame->arg1);
|
||||||
case SYS_DEVLIST:
|
case SYS_DEVLIST:
|
||||||
if ((int64_t)frame->arg2 < 0) return -1;
|
if ((int64_t)frame->arg2 < 0) return -1;
|
||||||
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(DevInfo), true)) return -1;
|
if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(DevInfo), true)) return -1;
|
||||||
|
|||||||
@@ -194,6 +194,8 @@ namespace montauk::abi {
|
|||||||
/* Process.hpp */
|
/* Process.hpp */
|
||||||
static constexpr uint64_t SYS_SETUSER = 92;
|
static constexpr uint64_t SYS_SETUSER = 92;
|
||||||
static constexpr uint64_t SYS_GETUSER = 93;
|
static constexpr uint64_t SYS_GETUSER = 93;
|
||||||
|
static constexpr uint64_t SYS_SETSESSION = 174;
|
||||||
|
static constexpr uint64_t SYS_KILLSESSION = 175;
|
||||||
|
|
||||||
/* Filesystem.hpp */
|
/* Filesystem.hpp */
|
||||||
static constexpr uint64_t SYS_FRENAME = 94;
|
static constexpr uint64_t SYS_FRENAME = 94;
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ namespace Sched {
|
|||||||
processTable[i].environment[0] = '\0';
|
processTable[i].environment[0] = '\0';
|
||||||
processTable[i].environmentLength = 1;
|
processTable[i].environmentLength = 1;
|
||||||
processTable[i].user[0] = '\0';
|
processTable[i].user[0] = '\0';
|
||||||
|
processTable[i].sessionId = -1;
|
||||||
processTable[i].cwd[0] = '\0';
|
processTable[i].cwd[0] = '\0';
|
||||||
processTable[i].runningOnCpu = -1;
|
processTable[i].runningOnCpu = -1;
|
||||||
processTable[i].killPending = false;
|
processTable[i].killPending = false;
|
||||||
@@ -560,6 +561,13 @@ namespace Sched {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process sessions are explicit groups used by supervisors such as
|
||||||
|
// login.elf. A session leader opts in with CreateSession(); all of its
|
||||||
|
// subsequently spawned descendants inherit the same stable ID.
|
||||||
|
proc.sessionId = (parentPrimarySlot >= 0)
|
||||||
|
? processTable[parentPrimarySlot].sessionId
|
||||||
|
: -1;
|
||||||
|
|
||||||
{
|
{
|
||||||
if (parentSlot >= 0 && processTable[parentSlot].cwd[0]) {
|
if (parentSlot >= 0 && processTable[parentSlot].cwd[0]) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@@ -1747,6 +1755,68 @@ namespace Sched {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int CreateSession() {
|
||||||
|
schedLock.Acquire();
|
||||||
|
Process* proc = GetCurrentProcessPtr();
|
||||||
|
if (proc == nullptr) {
|
||||||
|
schedLock.Release();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
proc->sessionId = proc->pid;
|
||||||
|
int sessionId = proc->sessionId;
|
||||||
|
schedLock.Release();
|
||||||
|
return sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
int KillSession(int sessionId) {
|
||||||
|
if (sessionId < 0) return -1;
|
||||||
|
|
||||||
|
int callerPid = GetCurrentPid();
|
||||||
|
int killed = 0;
|
||||||
|
|
||||||
|
// Mark the complete group in one scheduler-lock transaction. New
|
||||||
|
// children inherit sessionId, so a supervisor can repeat this call
|
||||||
|
// until zero is returned to close the small spawn/exit race cleanly.
|
||||||
|
schedLock.Acquire();
|
||||||
|
for (int i = 0; i < MaxProcesses; i++) {
|
||||||
|
Process& primary = processTable[i];
|
||||||
|
if (primary.primarySlot != i || primary.pid == callerPid ||
|
||||||
|
primary.sessionId != sessionId) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto state = primary.state;
|
||||||
|
if (state != ProcessState::Ready && state != ProcessState::Running &&
|
||||||
|
state != ProcessState::Blocked) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
primary.exitCode = 256 + 9; /* killed (SIGKILL) */
|
||||||
|
primary.killPending = true;
|
||||||
|
if (primary.state == ProcessState::Blocked) {
|
||||||
|
primary.state = ProcessState::Ready;
|
||||||
|
readyCount++;
|
||||||
|
primary.waitingForPid = -1;
|
||||||
|
primary.waitingOnObject = nullptr;
|
||||||
|
primary.sleepUntilTick = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < MaxProcesses; j++) {
|
||||||
|
if (j == i || processTable[j].primarySlot != i) continue;
|
||||||
|
if (processTable[j].state == ProcessState::Running) {
|
||||||
|
processTable[j].killPending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
killed++;
|
||||||
|
}
|
||||||
|
schedLock.Release();
|
||||||
|
|
||||||
|
if (killed > 0) {
|
||||||
|
KickOneIdleCpu(Smp::GetCurrentCpuData()
|
||||||
|
? Smp::GetCurrentCpuData()->cpuIndex : -1);
|
||||||
|
}
|
||||||
|
return killed;
|
||||||
|
}
|
||||||
|
|
||||||
int LookupExitCode(int pid) {
|
int LookupExitCode(int pid) {
|
||||||
schedLock.Acquire();
|
schedLock.Acquire();
|
||||||
int code = 0;
|
int code = 0;
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ namespace Sched {
|
|||||||
char environment[EnvironmentBytes]; // NUL-separated NAME=VALUE entries
|
char environment[EnvironmentBytes]; // NUL-separated NAME=VALUE entries
|
||||||
uint32_t environmentLength;
|
uint32_t environmentLength;
|
||||||
char user[32]; // Owner user name (inherited from parent on spawn)
|
char user[32]; // Owner user name (inherited from parent on spawn)
|
||||||
|
int sessionId; // Process-session leader PID (inherited on spawn)
|
||||||
char cwd[256]; // Absolute current working directory
|
char cwd[256]; // Absolute current working directory
|
||||||
|
|
||||||
// Thread-local storage. fsBase is loaded into IA32_FS_BASE when
|
// Thread-local storage. fsBase is loaded into IA32_FS_BASE when
|
||||||
@@ -252,6 +253,12 @@ namespace Sched {
|
|||||||
// Returns 0 on success, -1 on failure.
|
// Returns 0 on success, -1 on failure.
|
||||||
int KillProcess(int pid);
|
int KillProcess(int pid);
|
||||||
|
|
||||||
|
// Start a new process session for the caller, or terminate every process
|
||||||
|
// belonging to a session. KillSession returns the number of live members
|
||||||
|
// it signalled; callers can repeat until it returns zero.
|
||||||
|
int CreateSession();
|
||||||
|
int KillSession(int sessionId);
|
||||||
|
|
||||||
// Find a process by PID (returns nullptr if not found or not alive)
|
// Find a process by PID (returns nullptr if not found or not alive)
|
||||||
Process* GetProcessByPid(int pid);
|
Process* GetProcessByPid(int pid);
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ namespace montauk::abi {
|
|||||||
// User management
|
// User management
|
||||||
static constexpr uint64_t SYS_SETUSER = 92;
|
static constexpr uint64_t SYS_SETUSER = 92;
|
||||||
static constexpr uint64_t SYS_GETUSER = 93;
|
static constexpr uint64_t SYS_GETUSER = 93;
|
||||||
|
static constexpr uint64_t SYS_SETSESSION = 174;
|
||||||
|
static constexpr uint64_t SYS_KILLSESSION = 175;
|
||||||
static constexpr uint64_t SYS_FRENAME = 94;
|
static constexpr uint64_t SYS_FRENAME = 94;
|
||||||
static constexpr uint64_t SYS_GETCWD = 95;
|
static constexpr uint64_t SYS_GETCWD = 95;
|
||||||
static constexpr uint64_t SYS_CHDIR = 96;
|
static constexpr uint64_t SYS_CHDIR = 96;
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ extern "C" {
|
|||||||
#define MTK_SYS_GETENVIRON 171
|
#define MTK_SYS_GETENVIRON 171
|
||||||
#define MTK_SYS_SETENVIRON 172
|
#define MTK_SYS_SETENVIRON 172
|
||||||
#define MTK_SYS_SPAWN_ENV 173
|
#define MTK_SYS_SPAWN_ENV 173
|
||||||
|
#define MTK_SYS_SETSESSION 174
|
||||||
|
#define MTK_SYS_KILLSESSION 175
|
||||||
#define MTK_SYS_CHILDIO_READ 50
|
#define MTK_SYS_CHILDIO_READ 50
|
||||||
#define MTK_SYS_CHILDIO_WRITE 51
|
#define MTK_SYS_CHILDIO_WRITE 51
|
||||||
#define MTK_SYS_CHILDIO_WRITEKEY 52
|
#define MTK_SYS_CHILDIO_WRITEKEY 52
|
||||||
@@ -428,6 +430,14 @@ static inline int mtk_kill(int pid) {
|
|||||||
return (int)_mtk_syscall1(MTK_SYS_KILL, (long)pid);
|
return (int)_mtk_syscall1(MTK_SYS_KILL, (long)pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int mtk_setsession(void) {
|
||||||
|
return (int)_mtk_syscall0(MTK_SYS_SETSESSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mtk_killsession(int session_id) {
|
||||||
|
return (int)_mtk_syscall1(MTK_SYS_KILLSESSION, (long)session_id);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int mtk_proclist(mtk_procinfo *buf, int max) {
|
static inline int mtk_proclist(mtk_procinfo *buf, int max) {
|
||||||
return (int)_mtk_syscall2(MTK_SYS_PROCLIST, (long)buf, (long)max);
|
return (int)_mtk_syscall2(MTK_SYS_PROCLIST, (long)buf, (long)max);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -458,6 +458,12 @@ namespace montauk {
|
|||||||
inline int kill(int pid) {
|
inline int kill(int pid) {
|
||||||
return (int)syscall1(montauk::abi::SYS_KILL, (uint64_t)pid);
|
return (int)syscall1(montauk::abi::SYS_KILL, (uint64_t)pid);
|
||||||
}
|
}
|
||||||
|
inline int setsession() {
|
||||||
|
return (int)syscall0(montauk::abi::SYS_SETSESSION);
|
||||||
|
}
|
||||||
|
inline int killsession(int sessionId) {
|
||||||
|
return (int)syscall1(montauk::abi::SYS_KILLSESSION, (uint64_t)sessionId);
|
||||||
|
}
|
||||||
inline int devlist(montauk::abi::DevInfo* buf, int max) {
|
inline int devlist(montauk::abi::DevInfo* buf, int max) {
|
||||||
return (int)syscall2(montauk::abi::SYS_DEVLIST, (uint64_t)buf, (uint64_t)max);
|
return (int)syscall2(montauk::abi::SYS_DEVLIST, (uint64_t)buf, (uint64_t)max);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,16 @@
|
|||||||
Terminate another process by PID.
|
Terminate another process by PID.
|
||||||
int montauk::kill(int pid);
|
int montauk::kill(int pid);
|
||||||
|
|
||||||
|
.B SYS_SETSESSION (174)
|
||||||
|
Make the calling process the leader of a new process session. Processes
|
||||||
|
spawned afterward inherit the session identifier.
|
||||||
|
int montauk::setsession();
|
||||||
|
|
||||||
|
.B SYS_KILLSESSION (175)
|
||||||
|
Terminate all live processes in a process session. Returns the number of
|
||||||
|
members signalled; repeat until zero to wait for complete teardown.
|
||||||
|
int montauk::killsession(int sessionId);
|
||||||
|
|
||||||
.B SYS_CHDIR (96)
|
.B SYS_CHDIR (96)
|
||||||
Change the calling process's current working directory.
|
Change the calling process's current working directory.
|
||||||
int montauk::chdir(const char* path);
|
int montauk::chdir(const char* path);
|
||||||
|
|||||||
@@ -895,6 +895,11 @@ static bool existing_desktop_running() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void _start() {
|
extern "C" void _start() {
|
||||||
|
// External applications and all of their descendants inherit this stable
|
||||||
|
// desktop-session ID. login.elf uses it to tear down the complete session
|
||||||
|
// after Log Out, Shutdown, or Reboot returns control to the supervisor.
|
||||||
|
montauk::setsession();
|
||||||
|
|
||||||
if (existing_desktop_running()) {
|
if (existing_desktop_running()) {
|
||||||
gui::dialogs::message_box(
|
gui::dialogs::message_box(
|
||||||
"Desktop Already Running",
|
"Desktop Already Running",
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ enum SessionMode {
|
|||||||
SESSION_CONSOLE,
|
SESSION_CONSOLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void terminate_desktop_session(int session_id);
|
||||||
|
|
||||||
struct LoginState {
|
struct LoginState {
|
||||||
gui::Framebuffer fb;
|
gui::Framebuffer fb;
|
||||||
int screen_w, screen_h;
|
int screen_w, screen_h;
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ void launch_session(LoginState* ls) {
|
|||||||
if (pid >= 0) {
|
if (pid >= 0) {
|
||||||
montauk::setuser(pid, ls->username);
|
montauk::setuser(pid, ls->username);
|
||||||
montauk::waitpid(pid);
|
montauk::waitpid(pid);
|
||||||
|
if (ls->session_mode == SESSION_DESKTOP) {
|
||||||
|
terminate_desktop_session(pid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The desktop hands off a graceful power-off by posting a request and
|
// The desktop hands off a graceful power-off by posting a request and
|
||||||
@@ -99,6 +102,21 @@ gui::Rect login_field_rect(const LoginLayout& lo, LoginState* ls, int idx) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void terminate_desktop_session(int session_id) {
|
||||||
|
if (session_id < 0) return;
|
||||||
|
|
||||||
|
// Killing is asynchronous because a member may currently be executing on
|
||||||
|
// another CPU or inside a syscall. Repeat until the kernel observes the
|
||||||
|
// session empty; no member can spawn another process after that point.
|
||||||
|
//
|
||||||
|
|
||||||
|
const int timeout_ms = 2000;
|
||||||
|
for (int waited = 0; waited < timeout_ms; waited++) {
|
||||||
|
if (montauk::killsession(session_id) <= 0) return;
|
||||||
|
montauk::sleep_ms(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LoginField get_field(LoginState* ls, int field) {
|
LoginField get_field(LoginState* ls, int field) {
|
||||||
if (ls->mode == MODE_FIRST_BOOT) {
|
if (ls->mode == MODE_FIRST_BOOT) {
|
||||||
switch (field) {
|
switch (field) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ static void maybe_run_setup_session() {
|
|||||||
if (pid >= 0) {
|
if (pid >= 0) {
|
||||||
montauk::setuser(pid, user);
|
montauk::setuser(pid, user);
|
||||||
montauk::waitpid(pid);
|
montauk::waitpid(pid);
|
||||||
|
terminate_desktop_session(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
montauk::user::clear_session();
|
montauk::user::clear_session();
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ int spawn(const char* path, const char* args); // Spawn child, inheriting
|
|||||||
int waitpid(int pid); // Wait for process to exit
|
int waitpid(int pid); // Wait for process to exit
|
||||||
int kill(int pid); // Kill a process
|
int kill(int pid); // Kill a process
|
||||||
int proclist(ProcInfo* buf, int max); // List all processes (returns count)
|
int proclist(ProcInfo* buf, int max); // List all processes (returns count)
|
||||||
|
int setsession(); // Start a new inherited process session
|
||||||
|
int killsession(int sessionId); // Kill live members; repeat until zero
|
||||||
```
|
```
|
||||||
|
|
||||||
**`ProcInfo` struct:**
|
**`ProcInfo` struct:**
|
||||||
|
|||||||
@@ -125,6 +125,8 @@ namespace montauk::abi {
|
|||||||
// User management
|
// User management
|
||||||
static constexpr uint64_t SYS_SETUSER = 92;
|
static constexpr uint64_t SYS_SETUSER = 92;
|
||||||
static constexpr uint64_t SYS_GETUSER = 93;
|
static constexpr uint64_t SYS_GETUSER = 93;
|
||||||
|
static constexpr uint64_t SYS_SETSESSION = 174;
|
||||||
|
static constexpr uint64_t SYS_KILLSESSION = 175;
|
||||||
static constexpr uint64_t SYS_FRENAME = 94;
|
static constexpr uint64_t SYS_FRENAME = 94;
|
||||||
static constexpr uint64_t SYS_GETCWD = 95;
|
static constexpr uint64_t SYS_GETCWD = 95;
|
||||||
static constexpr uint64_t SYS_CHDIR = 96;
|
static constexpr uint64_t SYS_CHDIR = 96;
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ extern "C" {
|
|||||||
#define MTK_SYS_GETENVIRON 171
|
#define MTK_SYS_GETENVIRON 171
|
||||||
#define MTK_SYS_SETENVIRON 172
|
#define MTK_SYS_SETENVIRON 172
|
||||||
#define MTK_SYS_SPAWN_ENV 173
|
#define MTK_SYS_SPAWN_ENV 173
|
||||||
|
#define MTK_SYS_SETSESSION 174
|
||||||
|
#define MTK_SYS_KILLSESSION 175
|
||||||
#define MTK_SYS_CHILDIO_READ 50
|
#define MTK_SYS_CHILDIO_READ 50
|
||||||
#define MTK_SYS_CHILDIO_WRITE 51
|
#define MTK_SYS_CHILDIO_WRITE 51
|
||||||
#define MTK_SYS_CHILDIO_WRITEKEY 52
|
#define MTK_SYS_CHILDIO_WRITEKEY 52
|
||||||
@@ -423,6 +425,14 @@ static inline int mtk_kill(int pid) {
|
|||||||
return (int)_mtk_syscall1(MTK_SYS_KILL, (long)pid);
|
return (int)_mtk_syscall1(MTK_SYS_KILL, (long)pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int mtk_setsession(void) {
|
||||||
|
return (int)_mtk_syscall0(MTK_SYS_SETSESSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int mtk_killsession(int session_id) {
|
||||||
|
return (int)_mtk_syscall1(MTK_SYS_KILLSESSION, (long)session_id);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int mtk_proclist(mtk_procinfo *buf, int max) {
|
static inline int mtk_proclist(mtk_procinfo *buf, int max) {
|
||||||
return (int)_mtk_syscall2(MTK_SYS_PROCLIST, (long)buf, (long)max);
|
return (int)_mtk_syscall2(MTK_SYS_PROCLIST, (long)buf, (long)max);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -456,6 +456,12 @@ namespace montauk {
|
|||||||
inline int kill(int pid) {
|
inline int kill(int pid) {
|
||||||
return (int)syscall1(montauk::abi::SYS_KILL, (uint64_t)pid);
|
return (int)syscall1(montauk::abi::SYS_KILL, (uint64_t)pid);
|
||||||
}
|
}
|
||||||
|
inline int setsession() {
|
||||||
|
return (int)syscall0(montauk::abi::SYS_SETSESSION);
|
||||||
|
}
|
||||||
|
inline int killsession(int sessionId) {
|
||||||
|
return (int)syscall1(montauk::abi::SYS_KILLSESSION, (uint64_t)sessionId);
|
||||||
|
}
|
||||||
inline int devlist(montauk::abi::DevInfo* buf, int max) {
|
inline int devlist(montauk::abi::DevInfo* buf, int max) {
|
||||||
return (int)syscall2(montauk::abi::SYS_DEVLIST, (uint64_t)buf, (uint64_t)max);
|
return (int)syscall2(montauk::abi::SYS_DEVLIST, (uint64_t)buf, (uint64_t)max);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user