Implement sending signals to process groups.

This commit is contained in:
Jonas 'Sortie' Termansen 2013-06-12 01:35:31 +02:00
parent be0ece3fe0
commit b6349e21cb
3 changed files with 65 additions and 54 deletions

View File

@ -77,7 +77,6 @@ public:
class Process
{
friend void Process__OnLastThreadExit(void*);
friend void Process__LastPrayerFinalize(void*);
public:
Process();
@ -177,6 +176,7 @@ public:
void Exit(int status);
pid_t Wait(pid_t pid, int* status, int options);
bool DeliverSignal(int signum);
bool DeliverGroupSignal(int signum);
void OnThreadDestruction(Thread* thread);
int GetParentProcessId();
void AddChildProcess(Process* child);
@ -192,7 +192,7 @@ private:
CPU::InterruptRegisters* regs);
void OnLastThreadExit();
void LastPrayer();
void LastPrayerFinalize();
void NotifyMemberExit(Process* child);
void NotifyChildExit(Process* child, bool zombify);
void NotifyNewZombies();
void DeleteTimers();

View File

@ -341,41 +341,14 @@ void Process::LastPrayer()
iszombie = true;
// If this is a process group leader of a group containing other processes,
// then we have to wait until we are the only member and then terminate.
kthread_mutex_lock(&groupchildlock);
bool group_leader = group == this;
kthread_mutex_unlock(&groupchildlock);
if ( group_leader )
{
grouplimbo = true;
NotifyLeftProcessGroup();
return;
}
LastPrayerFinalize();
}
void Process__LastPrayerFinalize(void* user)
{
return ((Process*) user)->LastPrayerFinalize();
}
void Process::NotifyLeftProcessGroup()
{
ScopedLock parentlock(&groupparentlock);
if ( !grouplimbo )
return;
if ( groupprev || groupnext )
return;
grouplimbo = false;
Worker::Schedule(Process__LastPrayerFinalize, this);
}
void Process::LastPrayerFinalize()
{
bool zombify = !nozombify;
// Remove ourself from our process group.
kthread_mutex_lock(&groupchildlock);
if ( group )
group->NotifyMemberExit(this);
kthread_mutex_unlock(&groupchildlock);
// This class instance will be destroyed by our parent process when it
// has received and acknowledged our death.
kthread_mutex_lock(&parentlock);
@ -385,7 +358,14 @@ void Process::LastPrayerFinalize()
// If nobody is waiting for us, then simply commit suicide.
if ( !zombify )
delete this;
{
kthread_mutex_lock(&groupparentlock);
bool in_limbo = groupfirst || (grouplimbo = true);
kthread_mutex_unlock(&groupparentlock);
if ( !in_limbo )
delete this;
}
}
void Process::ResetAddressSpace()
@ -403,6 +383,33 @@ void Process::ResetAddressSpace()
segments = NULL;
}
void Process::NotifyMemberExit(Process* child)
{
assert(child->group == this);
kthread_mutex_lock(&groupparentlock);
if ( child->groupprev )
child->groupprev->groupnext = child->groupnext;
else
groupfirst = child->groupnext;
if ( child->groupnext )
child->groupnext->groupprev = child->groupprev;
kthread_cond_signal(&groupchildleft);
kthread_mutex_unlock(&groupparentlock);
child->group = NULL;
NotifyLeftProcessGroup();
}
void Process::NotifyLeftProcessGroup()
{
ScopedLock parentlock(&groupparentlock);
if ( !grouplimbo || groupfirst )
return;
grouplimbo = false;
delete this;
}
void Process::NotifyChildExit(Process* child, bool zombify)
{
kthread_mutex_lock(&childlock);
@ -493,22 +500,6 @@ pid_t Process::Wait(pid_t thepid, int* status, int options)
if ( zombiechild )
zombiechild->prevsibling = NULL;
// Remove zombie from its process group.
kthread_mutex_lock(&zombie->groupchildlock);
kthread_mutex_lock(&zombie->group->groupparentlock);
assert(zombie->group);
if ( zombie->groupprev )
zombie->groupprev->groupnext = zombie->groupnext;
else
zombie->group->groupfirst = zombie->groupnext;
if ( zombie->groupnext )
zombie->groupnext->groupprev = zombie->groupprev;
kthread_cond_signal(&zombie->group->groupchildleft);
kthread_mutex_unlock(&zombie->group->groupparentlock);
zombie->group->NotifyLeftProcessGroup();
zombie->group = NULL;
kthread_mutex_unlock(&zombie->groupchildlock);
thepid = zombie->pid;
// It is safe to access these clocks directly as the child process is no
@ -524,8 +515,13 @@ pid_t Process::Wait(pid_t thepid, int* status, int options)
if ( status )
*status = exitstatus;
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.
delete zombie;
if ( !in_limbo )
delete zombie;
return thepid;
}
@ -564,6 +560,16 @@ bool Process::DeliverSignal(int signum)
return errno = EINIT, false;
}
bool Process::DeliverGroupSignal(int signum)
{
ScopedLock lock(&groupparentlock);
if ( !groupfirst )
return errno = ESRCH, false;
for ( Process* iter = groupfirst; iter; iter = iter->groupnext )
iter->DeliverSignal(signum);
return true;
}
void Process::AddChildProcess(Process* child)
{
ScopedLock mylock(&childlock);

View File

@ -274,6 +274,9 @@ namespace Sortix
// Protect the system idle process.
if ( !pid ) { errno = EPERM; return -1; }
// TODO: Implement that pid == -1 means all processes!
bool process_group = pid < 0 ? (pid = -pid, true) : false;
// If we kill our own process, deliver the signal to this thread.
Thread* currentthread = CurrentThread();
if ( currentthread->process->pid == pid )
@ -287,7 +290,9 @@ namespace Sortix
// TODO: Check for permission.
// TODO: Check for zombies.
return process->DeliverSignal(signum) ? 0 : -1;
return process_group ?
process->DeliverGroupSignal(signum) ? 0 : -1 :
process->DeliverSignal(signum) ? 0 : -1;
}
int SysRaise(int signum)