mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Add signal mask support to ppoll(2).
This commit is contained in:
parent
9993a1c0fc
commit
20c1f1d0d4
5 changed files with 131 additions and 29 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2018 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -34,6 +34,7 @@ namespace Signal {
|
|||
|
||||
void Init();
|
||||
inline bool IsPending() { return asm_signal_is_pending != 0; }
|
||||
void UpdateMask(int how, const sigset_t* set, sigset_t* oldset);
|
||||
void DispatchHandler(struct interrupt_context* intctx, void* user);
|
||||
void ReturnHandler(struct interrupt_context* intctx, void* user);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011-2016, 2018 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -73,6 +73,7 @@ public:
|
|||
volatile ThreadState state;
|
||||
sigset_t signal_pending;
|
||||
sigset_t signal_mask;
|
||||
sigset_t saved_signal_mask;
|
||||
stack_t signal_stack;
|
||||
addr_t kernelstackpos;
|
||||
size_t kernelstacksize;
|
||||
|
@ -83,6 +84,7 @@ public:
|
|||
bool pledged_destruction;
|
||||
bool force_no_signals;
|
||||
bool signal_single;
|
||||
bool has_saved_signal_mask;
|
||||
Clock execute_clock;
|
||||
Clock system_clock;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2014, 2015 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2012, 2014, 2015, 2018 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <timespec.h>
|
||||
|
@ -38,7 +39,9 @@
|
|||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/poll.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
#include <sortix/kernel/signal.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/thread.h>
|
||||
#include <sortix/kernel/time.h>
|
||||
#include <sortix/kernel/timer.h>
|
||||
|
||||
|
@ -202,14 +205,42 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
|||
if ( !FetchTimespec(&timeout_ts, user_timeout_ts) )
|
||||
return -1;
|
||||
|
||||
sigset_t oldsigmask;
|
||||
if ( user_sigmask )
|
||||
return errno = ENOSYS, -1;
|
||||
{
|
||||
sigset_t sigmask;
|
||||
if ( !CopyFromUser(&sigmask, user_sigmask, sizeof(sigset_t)) )
|
||||
return -1;
|
||||
Signal::UpdateMask(SIG_SETMASK, &sigmask, &oldsigmask);
|
||||
if ( Signal::IsPending() )
|
||||
{
|
||||
// The pending signal might only be pending with the temporary
|
||||
// signal mask, so don't restore it. Instead ask for the real signal
|
||||
// mask to be restored after the signal has been processed.
|
||||
Thread* thread = CurrentThread();
|
||||
thread->has_saved_signal_mask = true;
|
||||
memcpy(&thread->saved_signal_mask, &oldsigmask, sizeof(sigset_t));
|
||||
assert(Signal::IsPending());
|
||||
return errno = EINTR, -1;
|
||||
}
|
||||
}
|
||||
|
||||
struct pollfd* fds = CopyFdsFromUser(user_fds, nfds);
|
||||
if ( !fds ) { return -1; }
|
||||
if ( !fds )
|
||||
{
|
||||
if ( user_sigmask )
|
||||
Signal::UpdateMask(SIG_SETMASK, &oldsigmask, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
PollNode* nodes = new PollNode[nfds];
|
||||
if ( !nodes ) { delete[] fds; return -1; }
|
||||
if ( !nodes )
|
||||
{
|
||||
delete[] fds;
|
||||
if ( user_sigmask )
|
||||
Signal::UpdateMask(SIG_SETMASK, &oldsigmask, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Process* process = CurrentProcess();
|
||||
|
||||
|
@ -222,6 +253,7 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
|||
bool self_woken = false;
|
||||
bool remote_woken = false;
|
||||
bool unexpected_error = false;
|
||||
bool deliver_signal = false;
|
||||
|
||||
Timer timer;
|
||||
struct poll_timeout pts;
|
||||
|
@ -253,7 +285,11 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
|||
continue;
|
||||
}
|
||||
Ref<Descriptor> desc = process->GetDescriptor(fds[reqs].fd);
|
||||
if ( !desc ) { self_woken = unexpected_error = true; break; }
|
||||
if ( !desc )
|
||||
{
|
||||
self_woken = unexpected_error = true;
|
||||
break;
|
||||
}
|
||||
node->events = fds[reqs].events | POLL__ONLY_REVENTS;
|
||||
node->revents = 0;
|
||||
node->wake_mutex = &wakeup_mutex;
|
||||
|
@ -275,8 +311,11 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
|||
while ( !(self_woken || remote_woken) )
|
||||
{
|
||||
if ( !kthread_cond_wait_signal(&wakeup_cond, &wakeup_mutex) )
|
||||
errno = -EINTR,
|
||||
{
|
||||
errno = -EINTR;
|
||||
self_woken = true;
|
||||
deliver_signal = true;
|
||||
}
|
||||
}
|
||||
|
||||
kthread_mutex_unlock(&wakeup_mutex);
|
||||
|
@ -308,6 +347,26 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
|||
|
||||
delete[] nodes;
|
||||
delete[] fds;
|
||||
|
||||
if ( 0 <= ret )
|
||||
errno = 0;
|
||||
|
||||
if ( user_sigmask )
|
||||
{
|
||||
if ( !deliver_signal )
|
||||
Signal::UpdateMask(SIG_SETMASK, &oldsigmask, NULL);
|
||||
else
|
||||
{
|
||||
// The pending signal might only be pending with the temporary
|
||||
// signal mask, so don't restore it. Instead ask for the real signal
|
||||
// mask to be restored after the signal has been processed.
|
||||
assert(Signal::IsPending());
|
||||
Thread* thread = CurrentThread();
|
||||
thread->has_saved_signal_mask = true;
|
||||
memcpy(&thread->saved_signal_mask, &oldsigmask, sizeof(sigset_t));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011-2016, 2018 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -189,7 +189,9 @@ int sys_sigpending(sigset_t* set)
|
|||
return CopyToUser(set, &thread->signal_pending, sizeof(sigset_t)) ? 0 : -1;
|
||||
}
|
||||
|
||||
int sys_sigprocmask(int how, const sigset_t* user_set, sigset_t* user_oldset)
|
||||
namespace Signal {
|
||||
|
||||
void UpdateMask(int how, const sigset_t* set, sigset_t* oldset)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Thread* thread = CurrentThread();
|
||||
|
@ -199,38 +201,46 @@ int sys_sigprocmask(int how, const sigset_t* user_set, sigset_t* user_oldset)
|
|||
ScopedLock lock(&process->signal_lock);
|
||||
|
||||
// Let the caller know the previous signal mask.
|
||||
if ( user_oldset )
|
||||
{
|
||||
if ( !CopyToUser(user_oldset, &thread->signal_mask, sizeof(sigset_t)) )
|
||||
return -1;
|
||||
}
|
||||
if ( oldset )
|
||||
memcpy(oldset, &thread->signal_mask, sizeof(sigset_t));
|
||||
|
||||
// Update the current signal mask according to how.
|
||||
if ( user_set )
|
||||
if ( set )
|
||||
{
|
||||
sigset_t set;
|
||||
if ( !CopyFromUser(&set, user_set, sizeof(sigset_t)) )
|
||||
return -1;
|
||||
|
||||
switch ( how )
|
||||
{
|
||||
case SIG_BLOCK:
|
||||
sigorset(&thread->signal_mask, &thread->signal_mask, &set);
|
||||
sigorset(&thread->signal_mask, &thread->signal_mask, set);
|
||||
break;
|
||||
case SIG_UNBLOCK:
|
||||
signotset(&set, &set);
|
||||
sigandset(&thread->signal_mask, &thread->signal_mask, &set);
|
||||
{
|
||||
sigset_t notset;
|
||||
signotset(¬set, set);
|
||||
sigandset(&thread->signal_mask, &thread->signal_mask, ¬set);
|
||||
break;
|
||||
}
|
||||
case SIG_SETMASK:
|
||||
memcpy(&thread->signal_mask, &set, sizeof(sigset_t));
|
||||
memcpy(&thread->signal_mask, set, sizeof(sigset_t));
|
||||
break;
|
||||
default:
|
||||
return errno = EINVAL, -1;
|
||||
};
|
||||
|
||||
UpdatePendingSignals(thread);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Signal
|
||||
|
||||
int sys_sigprocmask(int how, const sigset_t* user_set, sigset_t* user_oldset)
|
||||
{
|
||||
if ( how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK )
|
||||
return errno = EINVAL, -1;
|
||||
sigset_t set, oldset;
|
||||
if ( user_set && !CopyFromUser(&set, user_set, sizeof(sigset_t)) )
|
||||
return -1;
|
||||
Signal::UpdateMask(
|
||||
how, user_set ? &set : NULL, user_oldset ? &oldset : NULL);
|
||||
if ( user_oldset && !CopyToUser(user_oldset, &oldset, sizeof(sigset_t)) )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -563,7 +573,16 @@ retry_another_signal:
|
|||
// Decide which signal to deliver to the thread.
|
||||
int signum = PickImportantSignal(&deliverable_signals);
|
||||
if ( !signum )
|
||||
{
|
||||
if ( has_saved_signal_mask )
|
||||
{
|
||||
memcpy(&signal_mask, &saved_signal_mask, sizeof(sigset_t));
|
||||
has_saved_signal_mask = false;
|
||||
UpdatePendingSignals(this);
|
||||
goto retry_another_signal;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Unmark the selected signal as pending.
|
||||
sigdelset(&signal_pending, signum);
|
||||
|
@ -764,7 +783,20 @@ retry_another_signal:
|
|||
|
||||
// Format the ucontext into the stack frame.
|
||||
stack_frame.ucontext.uc_link = NULL;
|
||||
memcpy(&stack_frame.ucontext.uc_sigmask, &signal_mask, sizeof(signal_mask));
|
||||
if ( has_saved_signal_mask )
|
||||
{
|
||||
// If a system call temporarily set another signal mask, it wants us to
|
||||
// deliver signals for that temporary signal masks, however we must
|
||||
// restore the original saved signal mask in that case.
|
||||
memcpy(&stack_frame.ucontext.uc_sigmask, &saved_signal_mask,
|
||||
sizeof(saved_signal_mask));
|
||||
// 'has_saved_signal_mask' is set to false below when it's actually
|
||||
// delivered. This handles the case where the signal delivery fails and
|
||||
// and instead turns into another (we still want to restore the right
|
||||
// saved mask in that case).
|
||||
}
|
||||
else
|
||||
memcpy(&stack_frame.ucontext.uc_sigmask, &signal_mask, sizeof(signal_mask));
|
||||
memcpy(&stack_frame.ucontext.uc_stack, &signal_stack, sizeof(signal_stack));
|
||||
EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, &stopped_regs, intctx);
|
||||
|
||||
|
@ -787,7 +819,9 @@ retry_another_signal:
|
|||
goto retry_another_signal;
|
||||
}
|
||||
|
||||
// Update the current signal mask.
|
||||
// Update the current signal mask. UpdatePendingSignals isn't called because
|
||||
// sa_mask was or'd onto the current signal mask, only blocking signals, so
|
||||
// nothing new can be delivered.
|
||||
memcpy(&signal_mask, &new_signal_mask, sizeof(sigset_t));
|
||||
|
||||
// Update the current alternate signal stack.
|
||||
|
@ -818,6 +852,10 @@ retry_another_signal:
|
|||
if ( (signal_single = signal_count == 1) )
|
||||
signal_single_frame = (uintptr_t) stack;
|
||||
|
||||
// If there was a saved signal mask, it will be restored once the signal
|
||||
// handler complete, so forget it was ever saved.
|
||||
has_saved_signal_mask = false;
|
||||
|
||||
// Run the signal handler by returning to user-space.
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011-2016, 2018 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -96,8 +96,10 @@ Thread::Thread()
|
|||
pledged_destruction = false;
|
||||
force_no_signals = false;
|
||||
signal_single = false;
|
||||
has_saved_signal_mask = false;
|
||||
sigemptyset(&signal_pending);
|
||||
sigemptyset(&signal_mask);
|
||||
sigemptyset(&saved_signal_mask);
|
||||
memset(&signal_stack, 0, sizeof(signal_stack));
|
||||
signal_stack.ss_flags = SS_DISABLE;
|
||||
// execute_clock initialized in member constructor.
|
||||
|
|
Loading…
Reference in a new issue