diff --git a/init/init.c++ b/init/init.c++ index 64f10a8d..c0cdccb5 100644 --- a/init/init.c++ +++ b/init/init.c++ @@ -469,7 +469,7 @@ void set_hostname() free(hostname); } -int init_main(int argc, char* argv[]) +int main(int argc, char* argv[]) { if ( 3 <= argc && !strcmp(argv[1], "--chain") ) return chain_boot_device(argv[2]); @@ -513,33 +513,3 @@ int init_main(int argc, char* argv[]) return chain_boot_uuid(root_uuid); } - -int main(int argc, char* argv[]) -{ - if ( getpid() == 1 ) - { - pid_t direct_child_pid = fork(); - if ( direct_child_pid < 0 ) - error(2, errno, "fork"); - if ( direct_child_pid ) - { - int status; - while ( true ) - { - pid_t child_pid = waitpid(-1, &status, 0); - if ( child_pid < 0 ) - error(2, errno, "waitpid"); - if ( child_pid == direct_child_pid ) - break; - } - int exit_value = WEXITSTATUS(status); - // TODO: Broadcast SIGKILL and wait for all processes to finish. - while ( 0 < waitpid(-1, &status, WNOHANG) ) - { - } - return exit_value; - } - } - - return init_main(argc, argv); -} diff --git a/kernel/include/sortix/kernel/process.h b/kernel/include/sortix/kernel/process.h index f87aa90e..dc3329ff 100644 --- a/kernel/include/sortix/kernel/process.h +++ b/kernel/include/sortix/kernel/process.h @@ -129,7 +129,6 @@ private: kthread_mutex_t childlock; kthread_mutex_t parentlock; kthread_cond_t zombiecond; - size_t zombiewaiting; bool iszombie; bool nozombify; int exit_code; @@ -190,6 +189,7 @@ public: private: void OnLastThreadExit(); void LastPrayer(); + void WaitedFor(); void NotifyMemberExit(Process* child); void NotifyChildExit(Process* child, bool zombify); void NotifyNewZombies(); diff --git a/kernel/process.cpp b/kernel/process.cpp index 82e83761..824bc7bd 100644 --- a/kernel/process.cpp +++ b/kernel/process.cpp @@ -127,7 +127,6 @@ Process::Process() childlock = KTHREAD_MUTEX_INITIALIZER; parentlock = KTHREAD_MUTEX_INITIALIZER; zombiecond = KTHREAD_COND_INITIALIZER; - zombiewaiting = 0; iszombie = false; nozombify = false; exit_code = -1; @@ -323,29 +322,24 @@ void Process::LastPrayer() if ( init->firstchild ) init->firstchild->prevsibling = process; init->firstchild = process; + process->nozombify = true; } // Since we have no more children (they are with init now), we don't // have to worry about new zombie processes showing up, so just collect // those that are left. Then we satisfiy the invariant !zombiechild that // applies on process termination. - bool hadzombies = zombiechild; while ( zombiechild ) { - ScopedLock zombiechildlock(&zombiechild->parentlock); - ScopedLock initlock(&init->childlock); Process* zombie = zombiechild; zombiechild = zombie->nextsibling; - zombie->prevsibling = NULL; - zombie->nextsibling = init->zombiechild; - if ( init->zombiechild ) - init->zombiechild->prevsibling = zombie; - init->zombiechild = zombie; + zombie->nextsibling = NULL; + if ( zombiechild ) + zombiechild->prevsibling = NULL; + zombie->nozombify = true; + zombie->WaitedFor(); } kthread_mutex_unlock(&childlock); - if ( hadzombies ) - init->NotifyNewZombies(); - iszombie = true; bool zombify = !nozombify; @@ -365,14 +359,19 @@ void Process::LastPrayer() // If nobody is waiting for us, then simply commit suicide. if ( !zombify ) - { - kthread_mutex_lock(&groupparentlock); - bool in_limbo = groupfirst && (grouplimbo = true); - kthread_mutex_unlock(&groupparentlock); + WaitedFor(); +} - if ( !in_limbo ) - delete this; - } +void Process::WaitedFor() +{ + kthread_mutex_lock(&parentlock); + parent = NULL; + kthread_mutex_unlock(&parentlock); + kthread_mutex_lock(&groupparentlock); + bool in_limbo = groupfirst && (grouplimbo = true); + kthread_mutex_unlock(&groupparentlock); + if ( !in_limbo ) + delete this; } void Process::ResetAddressSpace() @@ -451,8 +450,7 @@ void Process::NotifyNewZombies() { ScopedLock lock(&childlock); DeliverSignal(SIGCHLD); - if ( zombiewaiting ) - kthread_cond_broadcast(&zombiecond); + kthread_cond_broadcast(&zombiecond); } pid_t Process::Wait(pid_t thepid, int* status_ptr, int options) @@ -474,10 +472,10 @@ pid_t Process::Wait(pid_t thepid, int* status_ptr, int options) // target process has the correct parent. bool found = false; for ( Process* p = firstchild; !found && p; p = p->nextsibling ) - if ( p->pid == thepid ) + if ( p->pid == thepid && !p->nozombify ) found = true; for ( Process* p = zombiechild; !found && p; p = p->nextsibling ) - if ( p->pid == thepid ) + if ( p->pid == thepid && !p->nozombify ) found = true; if ( !found ) return errno = ECHILD, -1; @@ -487,16 +485,13 @@ pid_t Process::Wait(pid_t thepid, int* status_ptr, int options) while ( !zombie ) { for ( zombie = zombiechild; zombie; zombie = zombie->nextsibling ) - if ( thepid == -1 || thepid == zombie->pid ) + if ( (thepid == -1 || thepid == zombie->pid) && !zombie->nozombify ) break; if ( zombie ) break; if ( options & WNOHANG ) return 0; - zombiewaiting++; - unsigned long r = kthread_cond_wait_signal(&zombiecond, &childlock); - zombiewaiting--; - if ( !r ) + if ( !kthread_cond_wait_signal(&zombiecond, &childlock) ) return errno = EINTR, -1; } @@ -521,13 +516,7 @@ pid_t Process::Wait(pid_t thepid, int* status_ptr, int options) if ( status < 0 ) status = WCONSTRUCT(WNATURE_SIGNALED, 128 + SIGKILL, SIGKILL); - kthread_mutex_lock(&zombie->groupparentlock); - bool in_limbo = zombie->groupfirst && (zombie->grouplimbo = true); - kthread_mutex_unlock(&zombie->groupparentlock); - - // And so, the process was fully deleted. - if ( !in_limbo ) - delete zombie; + zombie->WaitedFor(); if ( status_ptr ) *status_ptr = status;