Prevent orphan processes from becoming zombies.
This commit is contained in:
parent
44d4807fc4
commit
fc637c8880
|
@ -469,7 +469,7 @@ void set_hostname()
|
||||||
free(hostname);
|
free(hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if ( 3 <= argc && !strcmp(argv[1], "--chain") )
|
if ( 3 <= argc && !strcmp(argv[1], "--chain") )
|
||||||
return chain_boot_device(argv[2]);
|
return chain_boot_device(argv[2]);
|
||||||
|
@ -513,33 +513,3 @@ int init_main(int argc, char* argv[])
|
||||||
|
|
||||||
return chain_boot_uuid(root_uuid);
|
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 childlock;
|
||||||
kthread_mutex_t parentlock;
|
kthread_mutex_t parentlock;
|
||||||
kthread_cond_t zombiecond;
|
kthread_cond_t zombiecond;
|
||||||
size_t zombiewaiting;
|
|
||||||
bool iszombie;
|
bool iszombie;
|
||||||
bool nozombify;
|
bool nozombify;
|
||||||
int exit_code;
|
int exit_code;
|
||||||
|
@ -190,6 +189,7 @@ public:
|
||||||
private:
|
private:
|
||||||
void OnLastThreadExit();
|
void OnLastThreadExit();
|
||||||
void LastPrayer();
|
void LastPrayer();
|
||||||
|
void WaitedFor();
|
||||||
void NotifyMemberExit(Process* child);
|
void NotifyMemberExit(Process* child);
|
||||||
void NotifyChildExit(Process* child, bool zombify);
|
void NotifyChildExit(Process* child, bool zombify);
|
||||||
void NotifyNewZombies();
|
void NotifyNewZombies();
|
||||||
|
|
|
@ -127,7 +127,6 @@ Process::Process()
|
||||||
childlock = KTHREAD_MUTEX_INITIALIZER;
|
childlock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
parentlock = KTHREAD_MUTEX_INITIALIZER;
|
parentlock = KTHREAD_MUTEX_INITIALIZER;
|
||||||
zombiecond = KTHREAD_COND_INITIALIZER;
|
zombiecond = KTHREAD_COND_INITIALIZER;
|
||||||
zombiewaiting = 0;
|
|
||||||
iszombie = false;
|
iszombie = false;
|
||||||
nozombify = false;
|
nozombify = false;
|
||||||
exit_code = -1;
|
exit_code = -1;
|
||||||
|
@ -323,29 +322,24 @@ void Process::LastPrayer()
|
||||||
if ( init->firstchild )
|
if ( init->firstchild )
|
||||||
init->firstchild->prevsibling = process;
|
init->firstchild->prevsibling = process;
|
||||||
init->firstchild = process;
|
init->firstchild = process;
|
||||||
|
process->nozombify = true;
|
||||||
}
|
}
|
||||||
// Since we have no more children (they are with init now), we don't
|
// 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
|
// have to worry about new zombie processes showing up, so just collect
|
||||||
// those that are left. Then we satisfiy the invariant !zombiechild that
|
// those that are left. Then we satisfiy the invariant !zombiechild that
|
||||||
// applies on process termination.
|
// applies on process termination.
|
||||||
bool hadzombies = zombiechild;
|
|
||||||
while ( zombiechild )
|
while ( zombiechild )
|
||||||
{
|
{
|
||||||
ScopedLock zombiechildlock(&zombiechild->parentlock);
|
|
||||||
ScopedLock initlock(&init->childlock);
|
|
||||||
Process* zombie = zombiechild;
|
Process* zombie = zombiechild;
|
||||||
zombiechild = zombie->nextsibling;
|
zombiechild = zombie->nextsibling;
|
||||||
zombie->prevsibling = NULL;
|
zombie->nextsibling = NULL;
|
||||||
zombie->nextsibling = init->zombiechild;
|
if ( zombiechild )
|
||||||
if ( init->zombiechild )
|
zombiechild->prevsibling = NULL;
|
||||||
init->zombiechild->prevsibling = zombie;
|
zombie->nozombify = true;
|
||||||
init->zombiechild = zombie;
|
zombie->WaitedFor();
|
||||||
}
|
}
|
||||||
kthread_mutex_unlock(&childlock);
|
kthread_mutex_unlock(&childlock);
|
||||||
|
|
||||||
if ( hadzombies )
|
|
||||||
init->NotifyNewZombies();
|
|
||||||
|
|
||||||
iszombie = true;
|
iszombie = true;
|
||||||
|
|
||||||
bool zombify = !nozombify;
|
bool zombify = !nozombify;
|
||||||
|
@ -365,15 +359,20 @@ void Process::LastPrayer()
|
||||||
|
|
||||||
// If nobody is waiting for us, then simply commit suicide.
|
// If nobody is waiting for us, then simply commit suicide.
|
||||||
if ( !zombify )
|
if ( !zombify )
|
||||||
|
WaitedFor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Process::WaitedFor()
|
||||||
{
|
{
|
||||||
|
kthread_mutex_lock(&parentlock);
|
||||||
|
parent = NULL;
|
||||||
|
kthread_mutex_unlock(&parentlock);
|
||||||
kthread_mutex_lock(&groupparentlock);
|
kthread_mutex_lock(&groupparentlock);
|
||||||
bool in_limbo = groupfirst && (grouplimbo = true);
|
bool in_limbo = groupfirst && (grouplimbo = true);
|
||||||
kthread_mutex_unlock(&groupparentlock);
|
kthread_mutex_unlock(&groupparentlock);
|
||||||
|
|
||||||
if ( !in_limbo )
|
if ( !in_limbo )
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Process::ResetAddressSpace()
|
void Process::ResetAddressSpace()
|
||||||
{
|
{
|
||||||
|
@ -451,7 +450,6 @@ void Process::NotifyNewZombies()
|
||||||
{
|
{
|
||||||
ScopedLock lock(&childlock);
|
ScopedLock lock(&childlock);
|
||||||
DeliverSignal(SIGCHLD);
|
DeliverSignal(SIGCHLD);
|
||||||
if ( zombiewaiting )
|
|
||||||
kthread_cond_broadcast(&zombiecond);
|
kthread_cond_broadcast(&zombiecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -474,10 +472,10 @@ pid_t Process::Wait(pid_t thepid, int* status_ptr, int options)
|
||||||
// target process has the correct parent.
|
// target process has the correct parent.
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for ( Process* p = firstchild; !found && p; p = p->nextsibling )
|
for ( Process* p = firstchild; !found && p; p = p->nextsibling )
|
||||||
if ( p->pid == thepid )
|
if ( p->pid == thepid && !p->nozombify )
|
||||||
found = true;
|
found = true;
|
||||||
for ( Process* p = zombiechild; !found && p; p = p->nextsibling )
|
for ( Process* p = zombiechild; !found && p; p = p->nextsibling )
|
||||||
if ( p->pid == thepid )
|
if ( p->pid == thepid && !p->nozombify )
|
||||||
found = true;
|
found = true;
|
||||||
if ( !found )
|
if ( !found )
|
||||||
return errno = ECHILD, -1;
|
return errno = ECHILD, -1;
|
||||||
|
@ -487,16 +485,13 @@ pid_t Process::Wait(pid_t thepid, int* status_ptr, int options)
|
||||||
while ( !zombie )
|
while ( !zombie )
|
||||||
{
|
{
|
||||||
for ( zombie = zombiechild; zombie; zombie = zombie->nextsibling )
|
for ( zombie = zombiechild; zombie; zombie = zombie->nextsibling )
|
||||||
if ( thepid == -1 || thepid == zombie->pid )
|
if ( (thepid == -1 || thepid == zombie->pid) && !zombie->nozombify )
|
||||||
break;
|
break;
|
||||||
if ( zombie )
|
if ( zombie )
|
||||||
break;
|
break;
|
||||||
if ( options & WNOHANG )
|
if ( options & WNOHANG )
|
||||||
return 0;
|
return 0;
|
||||||
zombiewaiting++;
|
if ( !kthread_cond_wait_signal(&zombiecond, &childlock) )
|
||||||
unsigned long r = kthread_cond_wait_signal(&zombiecond, &childlock);
|
|
||||||
zombiewaiting--;
|
|
||||||
if ( !r )
|
|
||||||
return errno = EINTR, -1;
|
return errno = EINTR, -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,13 +516,7 @@ pid_t Process::Wait(pid_t thepid, int* status_ptr, int options)
|
||||||
if ( status < 0 )
|
if ( status < 0 )
|
||||||
status = WCONSTRUCT(WNATURE_SIGNALED, 128 + SIGKILL, SIGKILL);
|
status = WCONSTRUCT(WNATURE_SIGNALED, 128 + SIGKILL, SIGKILL);
|
||||||
|
|
||||||
kthread_mutex_lock(&zombie->groupparentlock);
|
zombie->WaitedFor();
|
||||||
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;
|
|
||||||
|
|
||||||
if ( status_ptr )
|
if ( status_ptr )
|
||||||
*status_ptr = status;
|
*status_ptr = status;
|
||||||
|
|
Loading…
Reference in New Issue