mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Prevent orphan processes from becoming zombies.
This commit is contained in:
parent
44d4807fc4
commit
fc637c8880
3 changed files with 26 additions and 67 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue