mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 15:08:21 +00:00
signal: support the stopping of processes
This commit is contained in:
+84
-13
@@ -139,9 +139,12 @@ void signal_pending(struct thread_t *thread, sigset_t *sigset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void signal_signalthread(struct thread_t *thread, int signal, bool urgent) {
|
void signal_signalthread(struct thread_t *thread, int signal, bool urgent) {
|
||||||
|
//bool notignorable = signal == SIGKILL || signal == SIGSTOP || signal == SIGCONT;
|
||||||
PROCESS_ENTER(thread->proc);
|
PROCESS_ENTER(thread->proc);
|
||||||
THREAD_ENTER(thread);
|
THREAD_ENTER(thread);
|
||||||
|
|
||||||
|
// TODO kill/stop/continue entire process if default actions call for it etc
|
||||||
|
|
||||||
sigset_t *sigset = urgent ? &thread->signals.urgent : &thread->signals.pending;
|
sigset_t *sigset = urgent ? &thread->signals.urgent : &thread->signals.pending;
|
||||||
SIGNAL_SETON(sigset, signal);
|
SIGNAL_SETON(sigset, signal);
|
||||||
|
|
||||||
@@ -162,6 +165,10 @@ void signal_signalproc(struct proc_t *proc, int signal) {
|
|||||||
PROCESS_ENTER(proc);
|
PROCESS_ENTER(proc);
|
||||||
void *address = proc->signals.actions[signal].address;
|
void *address = proc->signals.actions[signal].address;
|
||||||
bool notignored = address != SIG_IGN && ((address == SIG_DFL && defaultactions[signal] != ACTION_IGN) || address != SIG_DFL);
|
bool notignored = address != SIG_IGN && ((address == SIG_DFL && defaultactions[signal] != ACTION_IGN) || address != SIG_DFL);
|
||||||
|
bool notignorable = signal == SIGKILL || signal == SIGSTOP || signal == SIGCONT;
|
||||||
|
bool threadcontinued = false;
|
||||||
|
bool isdefaultaction = address == SIG_DFL;
|
||||||
|
bool shouldstop = (isdefaultaction && defaultactions[signal] == ACTION_STOP) || signal == SIGSTOP;
|
||||||
|
|
||||||
for (int i = 0; i < proc->threadtablesize; ++i) {
|
for (int i = 0; i < proc->threadtablesize; ++i) {
|
||||||
if (proc->threads[i] == NULL || (proc->threads[i]->flags & SCHED_THREAD_FLAGS_DEAD))
|
if (proc->threads[i] == NULL || (proc->threads[i]->flags & SCHED_THREAD_FLAGS_DEAD))
|
||||||
@@ -169,28 +176,69 @@ void signal_signalproc(struct proc_t *proc, int signal) {
|
|||||||
|
|
||||||
THREAD_ENTER(proc->threads[i]);
|
THREAD_ENTER(proc->threads[i]);
|
||||||
|
|
||||||
// sigcont will wake up all the threads or unset sigstop as pending
|
if (SIGNAL_GET(&proc->threads[i]->signals.mask, signal) == 0 || notignorable) {
|
||||||
if (signal == SIGCONT) {
|
|
||||||
// TODO this
|
|
||||||
} else if (SIGNAL_GET(&proc->threads[i]->signals.mask, signal) == 0 || signal == SIGKILL || signal == SIGSTOP) {
|
|
||||||
SIGNAL_SETON(&proc->threads[i]->signals.pending, signal);
|
SIGNAL_SETON(&proc->threads[i]->signals.pending, signal);
|
||||||
if (notignored) {
|
if (notignored || notignorable) {
|
||||||
sched_wakeup(proc->threads[i], SCHED_WAKEUP_REASON_INTERRUPTED);
|
int reason = SCHED_WAKEUP_REASON_INTERRUPTED;
|
||||||
|
if (proc->threads[i]->signals.stopped && (signal == SIGCONT || signal == SIGKILL)) {
|
||||||
|
// thread is stopped and we have to wake it up
|
||||||
|
proc->threads[i]->signals.stopped = false;
|
||||||
|
reason = 0; // wake it up from the non interruptible sleep
|
||||||
|
threadcontinued = true;
|
||||||
|
} else if (signal == SIGCONT) {
|
||||||
|
// thread is not stopped, ignore SIGCONT
|
||||||
|
SIGNAL_SETOFF(&proc->threads[i]->signals.pending, signal);
|
||||||
|
goto threadleave;
|
||||||
|
}
|
||||||
|
|
||||||
|
sched_wakeup(proc->threads[i], reason);
|
||||||
// TODO ipi if running isn't self
|
// TODO ipi if running isn't self
|
||||||
}
|
}
|
||||||
THREAD_LEAVE(proc->threads[i]);
|
|
||||||
PROCESS_LEAVE(proc);
|
// if we are stopping or continuing, this will be sent to all individual threads
|
||||||
MUTEX_RELEASE(&proc->mutex);
|
// XXX possible race condition where a thread will change the process mask or the action of stopping signals
|
||||||
return;
|
// after it was sent to everyone
|
||||||
|
if ((shouldstop || signal == SIGCONT) == false) {
|
||||||
|
THREAD_LEAVE(proc->threads[i]);
|
||||||
|
PROCESS_LEAVE(proc);
|
||||||
|
MUTEX_RELEASE(&proc->mutex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
threadleave:
|
||||||
THREAD_LEAVE(proc->threads[i]);
|
THREAD_LEAVE(proc->threads[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tell the parent that a child stopped
|
||||||
|
// TODO when stopping make sure that a thread was actually stopped
|
||||||
|
if ((notignorable || notignored) && defaultactions[signal] == ACTION_STOP) {
|
||||||
|
proc->status = 0x7f;
|
||||||
|
proc->status |= signal << 8;
|
||||||
|
proc->signals.stopunwaited = true;
|
||||||
|
if ((proc->parent->signals.actions[SIGCHLD].flags & SA_NOCLDSTOP) == 0) {
|
||||||
|
signal_signalproc(proc->parent, SIGCHLD);
|
||||||
|
}
|
||||||
|
semaphore_signal(&proc->parent->waitsem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tell the parent that a child continued
|
||||||
|
if (threadcontinued) {
|
||||||
|
proc->status = 0xffff;
|
||||||
|
proc->signals.continueunwaited = true;
|
||||||
|
if ((proc->parent->signals.actions[SIGCHLD].flags & SA_NOCLDSTOP) == 0) {
|
||||||
|
signal_signalproc(proc->parent, SIGCHLD);
|
||||||
|
}
|
||||||
|
semaphore_signal(&proc->parent->waitsem);
|
||||||
|
}
|
||||||
|
|
||||||
MUTEX_RELEASE(&proc->mutex);
|
MUTEX_RELEASE(&proc->mutex);
|
||||||
|
|
||||||
// there wasn't any thread with it unmasked, so set it as pending for the whole process
|
// if its ignorable and there wasn't any thread with it unmasked, set it as pending for the whole process
|
||||||
|
// not ignorable signals will be sent to all threads individually
|
||||||
SIGNAL_SETON(&proc->signals.pending, signal);
|
if (notignorable == false && (threadcontinued || shouldstop) == false) {
|
||||||
|
SIGNAL_SETON(&proc->signals.pending, signal);
|
||||||
|
}
|
||||||
|
|
||||||
PROCESS_LEAVE(proc);
|
PROCESS_LEAVE(proc);
|
||||||
}
|
}
|
||||||
@@ -200,10 +248,12 @@ bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uin
|
|||||||
bool retry = false;
|
bool retry = false;
|
||||||
proc_t *proc = thread->proc;
|
proc_t *proc = thread->proc;
|
||||||
|
|
||||||
|
bool intstatus = interrupt_set(false);
|
||||||
PROCESS_ENTER(proc);
|
PROCESS_ENTER(proc);
|
||||||
THREAD_ENTER(thread);
|
THREAD_ENTER(thread);
|
||||||
|
|
||||||
if (SIGNAL_GET(&proc->signals.pending, SIGKILL) || SIGNAL_GET(&thread->signals.pending, SIGKILL)) {
|
if (SIGNAL_GET(&proc->signals.pending, SIGKILL) || SIGNAL_GET(&thread->signals.pending, SIGKILL)) {
|
||||||
|
// TODO terminate entire program
|
||||||
THREAD_LEAVE(thread);
|
THREAD_LEAVE(thread);
|
||||||
PROCESS_LEAVE(proc);
|
PROCESS_LEAVE(proc);
|
||||||
proc->status = SIGKILL;
|
proc->status = SIGKILL;
|
||||||
@@ -262,12 +312,32 @@ bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uin
|
|||||||
goto leave;
|
goto leave;
|
||||||
case ACTION_CORE:
|
case ACTION_CORE:
|
||||||
case ACTION_TERM:
|
case ACTION_TERM:
|
||||||
|
// TODO terminate entire program
|
||||||
proc->status = signal;
|
proc->status = signal;
|
||||||
THREAD_LEAVE(thread);
|
THREAD_LEAVE(thread);
|
||||||
PROCESS_LEAVE(proc);
|
PROCESS_LEAVE(proc);
|
||||||
interrupt_set(true);
|
interrupt_set(true);
|
||||||
sched_threadexit();
|
sched_threadexit();
|
||||||
case ACTION_STOP:
|
case ACTION_STOP:
|
||||||
|
// TODO what if a thread unmasks a stop signal?
|
||||||
|
// check if sigcont is not pending for the thread (SIGCONT is always sent to the thread)
|
||||||
|
if (SIGNAL_GET(&thread->signals.pending, SIGCONT)) {
|
||||||
|
retry = true;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
// if not, just sleep. the sigcont won't be sent until THREAD_LEAVE and preparesleep is protecting it from a lost wakeup
|
||||||
|
sched_preparesleep(false);
|
||||||
|
thread->signals.stopped = true;
|
||||||
|
THREAD_LEAVE(thread);
|
||||||
|
PROCESS_LEAVE(proc);
|
||||||
|
sched_yield();
|
||||||
|
interrupt_set(intstatus);
|
||||||
|
// make sure a SIGCONT happened
|
||||||
|
__assert(SIGNAL_GET(&thread->signals.pending, SIGCONT));
|
||||||
|
__assert(thread->signals.stopped == false);
|
||||||
|
// the stopped variable is already set by the signaling function
|
||||||
|
// see if theres any other signal to deal with (such as the SIGCONT handler)
|
||||||
|
return true;
|
||||||
default:
|
default:
|
||||||
__assert(!"unsupported signal action");
|
__assert(!"unsupported signal action");
|
||||||
}
|
}
|
||||||
@@ -335,5 +405,6 @@ bool signal_check(struct thread_t *thread, context_t *context, bool syscall, uin
|
|||||||
leave:
|
leave:
|
||||||
THREAD_LEAVE(thread);
|
THREAD_LEAVE(thread);
|
||||||
PROCESS_LEAVE(proc);
|
PROCESS_LEAVE(proc);
|
||||||
|
interrupt_set(intstatus);
|
||||||
return retry;
|
return retry;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user