sortix-mirror/sortix/signal.cpp

245 lines
5.9 KiB
C++

/******************************************************************************
COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011.
This file is part of Sortix.
Sortix is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
Sortix is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along
with Sortix. If not, see <http://www.gnu.org/licenses/>.
signal.cpp
Classes and functions making it easier to handle Unix signals.
******************************************************************************/
#include <sortix/kernel/platform.h>
#include <libmaxsi/memory.h>
#include <sortix/kernel/panic.h>
#include "signal.h"
using namespace Maxsi;
namespace Sortix
{
const int PRIORITY_NORMAL = 0;
const int PRIORITY_HIGH = 1;
const int PRIORITY_STOP = 2;
const int PRIORITY_CORE = 3;
const int PRIORITY_KILL = 4;
const int PRIORITIES[Maxsi::Signal::NUMSIGNALS] =
{
PRIORITY_NORMAL, // unused
PRIORITY_NORMAL, // SIGHUP
PRIORITY_NORMAL, // SIGINT
PRIORITY_NORMAL, // SIGQUIT
PRIORITY_CORE, // SIGILL
PRIORITY_CORE, // SIGTRAP
PRIORITY_CORE, // SIGABRT
PRIORITY_CORE, // SIGEMT
PRIORITY_CORE, // SIGFPE
PRIORITY_KILL, // SIGKILL
PRIORITY_CORE, // SIGBUS
PRIORITY_CORE, // SIGSEGV
PRIORITY_CORE, // SIGSYS
PRIORITY_NORMAL, // SIGPIPE
PRIORITY_NORMAL, // SIGALRM
PRIORITY_NORMAL, // SIGTERM
PRIORITY_NORMAL, // SIGUSR1
PRIORITY_NORMAL, // SIGUSR2
PRIORITY_NORMAL, // SIGCHLD
PRIORITY_HIGH, // SIGPWR
PRIORITY_NORMAL, // SIGWINCH
PRIORITY_NORMAL, // SIGURG
PRIORITY_NORMAL, // obsolete
PRIORITY_STOP, // SIGSTOP
PRIORITY_STOP, // SIGTSTP
PRIORITY_STOP, // SIGCONT
PRIORITY_STOP, // SIGTTIN
PRIORITY_STOP, // SIGTTOU
PRIORITY_NORMAL, // SIGVTALRM
PRIORITY_NORMAL, // obsolete
PRIORITY_CORE, // SIGXCPU
PRIORITY_CORE, // SIGXFSZ
PRIORITY_NORMAL, // SIGCORE
PRIORITY_NORMAL, // SIGLWP
PRIORITY_NORMAL, // SIGAIO
};
// Returns true of the exact ordering of this signal version others aren't
// important - if it returns false, then this signal will be put in the
// queue according to priority, instead of being merged into another signal
// with the same signum.
bool Unifiable(int /*signum*/)
{
return true;
}
// Returns whether a specific signal is more important to deliver than
// another. This is used to schedule signals.
int CompareSignalPriority(int siga, int sigb)
{
int prioa = PRIORITY_NORMAL;
int priob = PRIORITY_NORMAL;
if ( siga < Maxsi::Signal::NUMSIGNALS ) { prioa = PRIORITIES[siga]; }
if ( sigb < Maxsi::Signal::NUMSIGNALS ) { priob = PRIORITIES[sigb]; }
if ( prioa < priob ) { return -1; } else
if ( prioa > priob ) { return 1; }
return 0;
}
SignalQueue::SignalQueue()
{
queue = NULL;
}
SignalQueue::~SignalQueue()
{
while ( queue )
{
Signal* todelete = queue;
queue = queue->nextsignal;
delete todelete;
}
}
// Queues the signal and schedules it for processing.
bool SignalQueue::Push(int signum)
{
ASSERT(0 <= signum && signum < 128);
if ( Unifiable(signum) )
{
for ( Signal* signal = queue; signal != NULL; signal = signal->nextsignal )
{
if ( signal->signum != signum ) { continue; }
signal->numpending++;
return true;
}
}
Signal* signal = new Signal;
if ( !signal ) { return false; }
signal->signum = signum;
signal->numpending = 1;
signal->nextsignal = NULL;
signal->returncode = 128 + signum;
Insert(signal);
return true;
}
// Insert the signal in O(N), which is pretty fast for small Ns.
void SignalQueue::Insert(Signal* signal)
{
if ( !queue )
{
queue = signal;
last = signal;
return;
}
// If the signal is to be inserted last, then just do it quickly.
if ( last != NULL && 0 <= CompareSignalPriority(last->signum, signal->signum) )
{
last->nextsignal = signal;
signal->nextsignal = NULL;
last = signal;
return;
}
// Check if the signal should be inserted first.
if ( queue != NULL && CompareSignalPriority(queue->signum, signal->signum) < 0 )
{
signal->nextsignal = queue;
queue = signal;
return;
}
// Find where the signal should be inserted.
for ( Signal* tmp = queue; tmp != NULL; tmp = tmp->nextsignal )
{
Signal* next = tmp->nextsignal;
if ( next != NULL && CompareSignalPriority(next->signum, signal->signum) < 0 )
{
tmp->nextsignal = signal;
signal->nextsignal = next;
return;
}
if ( next == NULL )
{
tmp->nextsignal = signal;
signal->nextsignal = NULL;
last = signal;
return;
}
}
}
// Given the stack of currently processing signals, return a new signal if
// it is more important to handle at this point.
Signal* SignalQueue::Pop(Signal* current)
{
if ( queue == NULL ) { return NULL; }
bool returnqueue = false;
// If we are currently handling no signal, then just return the first.
if ( current == NULL ) { returnqueue = true; }
// If we are handling a signal, only override it with another if it is
// more important.
else if ( CompareSignalPriority(current->signum, queue->signum) < 0 )
{
returnqueue = true;
}
if ( returnqueue )
{
Signal* result = queue;
queue = queue->nextsignal;
result->nextsignal = NULL;
return result;
}
return NULL;
}
Signal* Signal::Fork()
{
Signal* clone = new Signal();
if ( !clone ) { return NULL; }
Memory::Copy(clone, this, sizeof(Signal));
Signal* nextsignalclone = NULL;
if ( nextsignal )
{
nextsignalclone = nextsignal->Fork();
if ( !nextsignalclone ) { delete clone; return NULL; }
}
clone->nextsignal = nextsignalclone;
return clone;
}
}