diff --git a/zion/include/zcall.h b/zion/include/zcall.h index 2cc1a4c..efe5d16 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -10,6 +10,7 @@ z_err_t SysCall1(uint64_t code, const void* req); SYS1(ProcessExit, uint64_t, code); SYS5(ProcessSpawn, z_cap_t, proc_cap, z_cap_t, bootstrap_cap, z_cap_t*, new_proc_cap, z_cap_t*, new_vmas_cap, z_cap_t*, new_bootstrap_cap); +SYS2(ProcessWait, z_cap_t, proc_cap, z_err_t*, exit_code); SYS2(ThreadCreate, z_cap_t, proc_cap, z_cap_t*, thread_cap); SYS4(ThreadStart, z_cap_t, thread_cap, uint64_t, entry, uint64_t, arg1, diff --git a/zion/include/ztypes.h b/zion/include/ztypes.h index 0798688..f25df71 100644 --- a/zion/include/ztypes.h +++ b/zion/include/ztypes.h @@ -12,6 +12,7 @@ typedef uint64_t z_err_t; // Process Calls. const uint64_t kZionProcessExit = 0x1; const uint64_t kZionProcessSpawn = 0x2; +const uint64_t kZionProcessWait = 0x3; // Thread Calls. const uint64_t kZionThreadCreate = 0x10; diff --git a/zion/interrupt/interrupt.cpp b/zion/interrupt/interrupt.cpp index 2d9e8f5..8b6c114 100644 --- a/zion/interrupt/interrupt.cpp +++ b/zion/interrupt/interrupt.cpp @@ -79,7 +79,7 @@ extern "C" void interrupt_divide_by_zero(InterruptFrame* frame) { StackUnwind(frame->rbp); if (IsUserSpace(frame->rip)) { - gScheduler->CurrentProcess().Exit(); + gScheduler->CurrentProcess().Exit(glcr::INTERNAL); UNREACHABLE } panic("DIV0"); @@ -91,7 +91,7 @@ extern "C" void interrupt_invalid_opcode(InterruptFrame* frame) { StackUnwind(frame->rbp); if (IsUserSpace(frame->rip)) { - gScheduler->CurrentProcess().Exit(); + gScheduler->CurrentProcess().Exit(glcr::INTERNAL); UNREACHABLE } panic("INVALID OPCODE"); @@ -117,7 +117,7 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) { StackUnwind(frame->rbp); if (IsUserSpace(frame->rip)) { - gScheduler->CurrentProcess().Exit(); + gScheduler->CurrentProcess().Exit(glcr::INTERNAL); UNREACHABLE } panic("GP"); @@ -159,7 +159,7 @@ extern "C" void interrupt_page_fault(InterruptFrame* frame) { StackUnwind(frame->rbp); if (IsUserSpace(frame->rip)) { - gScheduler->CurrentProcess().Exit(); + gScheduler->CurrentProcess().Exit(glcr::INTERNAL); UNREACHABLE } @@ -170,7 +170,7 @@ extern "C" void isr_fpe_fault(); extern "C" void interrupt_fpe_fault(InterruptFrame* frame) { dbgln("Floating point exception."); if (IsUserSpace(frame->rip)) { - gScheduler->CurrentProcess().Exit(); + gScheduler->CurrentProcess().Exit(glcr::INTERNAL); UNREACHABLE } panic("Floating point exception"); diff --git a/zion/object/process.cpp b/zion/object/process.cpp index 407f051..ac53c97 100644 --- a/zion/object/process.cpp +++ b/zion/object/process.cpp @@ -59,10 +59,11 @@ uint64_t Process::AddExistingCapability(const glcr::RefPtr& cap) { return caps_.AddExistingCapability(cap); } -void Process::Exit() { +void Process::Exit(uint64_t exit_code) { // TODO: Check this state elsewhere to ensure that we don't for instance // create a running thread on a finished process. state_ = CLEANUP; + exit_code_ = exit_code; for (uint64_t i = 0; i < threads_.size(); i++) { if (!threads_[i]->IsDying()) { diff --git a/zion/object/process.h b/zion/object/process.h index 45555aa..9c44876 100644 --- a/zion/object/process.h +++ b/zion/object/process.h @@ -57,10 +57,11 @@ class Process : public KernelObject { uint64_t AddExistingCapability(const glcr::RefPtr& cap); State GetState() { return state_; } + uint64_t exit_code() { return exit_code_; } // This stops all of the processes threads (they will no longer be scheduled) // and flags the process for cleanup. - void Exit(); + void Exit(uint64_t code); // This *should not* be called from a thread that belongs to this process. // Rather it should be called from the cleanup thread. @@ -76,6 +77,7 @@ class Process : public KernelObject { uint64_t id_; glcr::RefPtr vmas_; State state_; + uint64_t exit_code_ = -1; uint64_t next_thread_id_ = 0; diff --git a/zion/syscall/process.cpp b/zion/syscall/process.cpp index 05048be..15d427f 100644 --- a/zion/syscall/process.cpp +++ b/zion/syscall/process.cpp @@ -9,7 +9,7 @@ z_err_t ProcessExit(ZProcessExitReq* req) { auto curr_thread = gScheduler->CurrentThread(); dbgln("Exit code: {}", static_cast(req->code)); - curr_thread->process().Exit(); + curr_thread->process().Exit(req->code); panic("Returned from thread exit"); return glcr::UNIMPLEMENTED; } @@ -39,3 +39,17 @@ z_err_t ProcessSpawn(ZProcessSpawnReq* req) { return glcr::OK; } + +z_err_t ProcessWait(ZProcessWaitReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto cap = curr_proc.GetCapability(req->proc_cap); + RET_ERR(ValidateCapability(cap, kZionPerm_Read)); + + auto proc = cap->obj(); + if (proc->id() == curr_proc.id()) { + return glcr::INVALID_ARGUMENT; + } + proc->GetThread(0)->Wait(); + *req->exit_code = proc->exit_code(); + return glcr::OK; +} diff --git a/zion/syscall/process.h b/zion/syscall/process.h index 0540253..a65a567 100644 --- a/zion/syscall/process.h +++ b/zion/syscall/process.h @@ -4,3 +4,4 @@ z_err_t ProcessExit(ZProcessExitReq* req); z_err_t ProcessSpawn(ZProcessSpawnReq* req); +z_err_t ProcessWait(ZProcessWaitReq* req); diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index 52b0f81..ac260a5 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -53,6 +53,7 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) { // syscall/process.h CASE(ProcessExit); CASE(ProcessSpawn); + CASE(ProcessWait); // syscall/thread.h CASE(ThreadCreate); CASE(ThreadStart);