Add signal mask support to ppoll(2).
This commit is contained in:
parent
9993a1c0fc
commit
20c1f1d0d4
|
@ -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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -34,6 +34,7 @@ namespace Signal {
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
inline bool IsPending() { return asm_signal_is_pending != 0; }
|
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 DispatchHandler(struct interrupt_context* intctx, void* user);
|
||||||
void ReturnHandler(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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -73,6 +73,7 @@ public:
|
||||||
volatile ThreadState state;
|
volatile ThreadState state;
|
||||||
sigset_t signal_pending;
|
sigset_t signal_pending;
|
||||||
sigset_t signal_mask;
|
sigset_t signal_mask;
|
||||||
|
sigset_t saved_signal_mask;
|
||||||
stack_t signal_stack;
|
stack_t signal_stack;
|
||||||
addr_t kernelstackpos;
|
addr_t kernelstackpos;
|
||||||
size_t kernelstacksize;
|
size_t kernelstacksize;
|
||||||
|
@ -83,6 +84,7 @@ public:
|
||||||
bool pledged_destruction;
|
bool pledged_destruction;
|
||||||
bool force_no_signals;
|
bool force_no_signals;
|
||||||
bool signal_single;
|
bool signal_single;
|
||||||
|
bool has_saved_signal_mask;
|
||||||
Clock execute_clock;
|
Clock execute_clock;
|
||||||
Clock system_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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <timespec.h>
|
#include <timespec.h>
|
||||||
|
@ -38,7 +39,9 @@
|
||||||
#include <sortix/kernel/kthread.h>
|
#include <sortix/kernel/kthread.h>
|
||||||
#include <sortix/kernel/poll.h>
|
#include <sortix/kernel/poll.h>
|
||||||
#include <sortix/kernel/process.h>
|
#include <sortix/kernel/process.h>
|
||||||
|
#include <sortix/kernel/signal.h>
|
||||||
#include <sortix/kernel/syscall.h>
|
#include <sortix/kernel/syscall.h>
|
||||||
|
#include <sortix/kernel/thread.h>
|
||||||
#include <sortix/kernel/time.h>
|
#include <sortix/kernel/time.h>
|
||||||
#include <sortix/kernel/timer.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) )
|
if ( !FetchTimespec(&timeout_ts, user_timeout_ts) )
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
sigset_t oldsigmask;
|
||||||
if ( user_sigmask )
|
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);
|
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];
|
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();
|
Process* process = CurrentProcess();
|
||||||
|
|
||||||
|
@ -222,6 +253,7 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
bool self_woken = false;
|
bool self_woken = false;
|
||||||
bool remote_woken = false;
|
bool remote_woken = false;
|
||||||
bool unexpected_error = false;
|
bool unexpected_error = false;
|
||||||
|
bool deliver_signal = false;
|
||||||
|
|
||||||
Timer timer;
|
Timer timer;
|
||||||
struct poll_timeout pts;
|
struct poll_timeout pts;
|
||||||
|
@ -253,7 +285,11 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Ref<Descriptor> desc = process->GetDescriptor(fds[reqs].fd);
|
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->events = fds[reqs].events | POLL__ONLY_REVENTS;
|
||||||
node->revents = 0;
|
node->revents = 0;
|
||||||
node->wake_mutex = &wakeup_mutex;
|
node->wake_mutex = &wakeup_mutex;
|
||||||
|
@ -275,8 +311,11 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
while ( !(self_woken || remote_woken) )
|
while ( !(self_woken || remote_woken) )
|
||||||
{
|
{
|
||||||
if ( !kthread_cond_wait_signal(&wakeup_cond, &wakeup_mutex) )
|
if ( !kthread_cond_wait_signal(&wakeup_cond, &wakeup_mutex) )
|
||||||
errno = -EINTR,
|
{
|
||||||
|
errno = -EINTR;
|
||||||
self_woken = true;
|
self_woken = true;
|
||||||
|
deliver_signal = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
kthread_mutex_unlock(&wakeup_mutex);
|
kthread_mutex_unlock(&wakeup_mutex);
|
||||||
|
@ -308,6 +347,26 @@ int sys_ppoll(struct pollfd* user_fds, size_t nfds,
|
||||||
|
|
||||||
delete[] nodes;
|
delete[] nodes;
|
||||||
delete[] fds;
|
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;
|
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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* 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;
|
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();
|
Process* process = CurrentProcess();
|
||||||
Thread* thread = CurrentThread();
|
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);
|
ScopedLock lock(&process->signal_lock);
|
||||||
|
|
||||||
// Let the caller know the previous signal mask.
|
// Let the caller know the previous signal mask.
|
||||||
if ( user_oldset )
|
if ( oldset )
|
||||||
{
|
memcpy(oldset, &thread->signal_mask, sizeof(sigset_t));
|
||||||
if ( !CopyToUser(user_oldset, &thread->signal_mask, sizeof(sigset_t)) )
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the current signal mask according to how.
|
// 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 )
|
switch ( how )
|
||||||
{
|
{
|
||||||
case SIG_BLOCK:
|
case SIG_BLOCK:
|
||||||
sigorset(&thread->signal_mask, &thread->signal_mask, &set);
|
sigorset(&thread->signal_mask, &thread->signal_mask, set);
|
||||||
break;
|
break;
|
||||||
case SIG_UNBLOCK:
|
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;
|
break;
|
||||||
|
}
|
||||||
case SIG_SETMASK:
|
case SIG_SETMASK:
|
||||||
memcpy(&thread->signal_mask, &set, sizeof(sigset_t));
|
memcpy(&thread->signal_mask, set, sizeof(sigset_t));
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
return errno = EINVAL, -1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
UpdatePendingSignals(thread);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -563,7 +573,16 @@ retry_another_signal:
|
||||||
// Decide which signal to deliver to the thread.
|
// Decide which signal to deliver to the thread.
|
||||||
int signum = PickImportantSignal(&deliverable_signals);
|
int signum = PickImportantSignal(&deliverable_signals);
|
||||||
if ( !signum )
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Unmark the selected signal as pending.
|
// Unmark the selected signal as pending.
|
||||||
sigdelset(&signal_pending, signum);
|
sigdelset(&signal_pending, signum);
|
||||||
|
@ -764,7 +783,20 @@ retry_another_signal:
|
||||||
|
|
||||||
// Format the ucontext into the stack frame.
|
// Format the ucontext into the stack frame.
|
||||||
stack_frame.ucontext.uc_link = NULL;
|
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));
|
memcpy(&stack_frame.ucontext.uc_stack, &signal_stack, sizeof(signal_stack));
|
||||||
EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, &stopped_regs, intctx);
|
EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, &stopped_regs, intctx);
|
||||||
|
|
||||||
|
@ -787,7 +819,9 @@ retry_another_signal:
|
||||||
goto 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));
|
memcpy(&signal_mask, &new_signal_mask, sizeof(sigset_t));
|
||||||
|
|
||||||
// Update the current alternate signal stack.
|
// Update the current alternate signal stack.
|
||||||
|
@ -818,6 +852,10 @@ retry_another_signal:
|
||||||
if ( (signal_single = signal_count == 1) )
|
if ( (signal_single = signal_count == 1) )
|
||||||
signal_single_frame = (uintptr_t) stack;
|
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.
|
// Run the signal handler by returning to user-space.
|
||||||
return;
|
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
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -96,8 +96,10 @@ Thread::Thread()
|
||||||
pledged_destruction = false;
|
pledged_destruction = false;
|
||||||
force_no_signals = false;
|
force_no_signals = false;
|
||||||
signal_single = false;
|
signal_single = false;
|
||||||
|
has_saved_signal_mask = false;
|
||||||
sigemptyset(&signal_pending);
|
sigemptyset(&signal_pending);
|
||||||
sigemptyset(&signal_mask);
|
sigemptyset(&signal_mask);
|
||||||
|
sigemptyset(&saved_signal_mask);
|
||||||
memset(&signal_stack, 0, sizeof(signal_stack));
|
memset(&signal_stack, 0, sizeof(signal_stack));
|
||||||
signal_stack.ss_flags = SS_DISABLE;
|
signal_stack.ss_flags = SS_DISABLE;
|
||||||
// execute_clock initialized in member constructor.
|
// execute_clock initialized in member constructor.
|
||||||
|
|
Loading…
Reference in New Issue