* Added some comments to the thread flags.
* Added new thread flag THREAD_FLAGS_ALWAYS_RESTART_SYSCALL. If set, it forces syscall restart even when a signal handler without SA_RESTART was invoked. * Fixed sigwait(): If one of requested signals wasn't already pending it would never wake up. Also, the syscall always needs to be restarted, if interrupted by another signal. * Renamed a bunch of the POSIX signal function implementations which did return an error code directly (instead via errno). Added correct POSIX functions where needed. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@36054 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
8c3082077f
commit
2be99447d8
@ -348,16 +348,34 @@ struct thread_queue {
|
||||
|
||||
// bits for the thread::flags field
|
||||
#define THREAD_FLAGS_SIGNALS_PENDING 0x0001
|
||||
// unblocked signals are pending (computed flag for optimization purposes)
|
||||
#define THREAD_FLAGS_DEBUG_THREAD 0x0002
|
||||
// forces the thread into the debugger as soon as possible (set by
|
||||
// debug_thread())
|
||||
#define THREAD_FLAGS_DEBUGGER_INSTALLED 0x0004
|
||||
// a debugger is installed for the current team (computed flag for
|
||||
// optimization purposes)
|
||||
#define THREAD_FLAGS_BREAKPOINTS_DEFINED 0x0008
|
||||
// hardware breakpoints are defined for the current team (computed flag for
|
||||
// optimization purposes)
|
||||
#define THREAD_FLAGS_BREAKPOINTS_INSTALLED 0x0010
|
||||
// breakpoints are currently installed for the thread (i.e. the hardware is
|
||||
// actually set up to trigger debug events for them)
|
||||
#define THREAD_FLAGS_64_BIT_SYSCALL_RETURN 0x0020
|
||||
// set by 64 bit return value syscalls
|
||||
#define THREAD_FLAGS_RESTART_SYSCALL 0x0040
|
||||
// set by handle_signals(), if the current syscall shall be restarted
|
||||
#define THREAD_FLAGS_DONT_RESTART_SYSCALL 0x0080
|
||||
#define THREAD_FLAGS_SYSCALL_RESTARTED 0x0100
|
||||
#define THREAD_FLAGS_SYSCALL 0x0200
|
||||
// Note: Set only for certain syscalls.
|
||||
// explicitly disables automatic syscall restarts (e.g. resume_thread())
|
||||
#define THREAD_FLAGS_ALWAYS_RESTART_SYSCALL 0x0100
|
||||
// force syscall restart, even if a signal handler without SA_RESTART was
|
||||
// invoked (e.g. sigwait())
|
||||
#define THREAD_FLAGS_SYSCALL_RESTARTED 0x0200
|
||||
// the current syscall has been restarted
|
||||
#define THREAD_FLAGS_SYSCALL 0x0400
|
||||
// the thread is currently in a syscall; set/reset only for certain
|
||||
// functions (e.g. ioctl()) to allow inner functions to discriminate
|
||||
// whether e.g. parameters where passed from userland or kernel
|
||||
|
||||
|
||||
#endif /* _KERNEL_THREAD_TYPES_H */
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <ksignal.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
@ -23,6 +24,7 @@
|
||||
#include <kscheduler.h>
|
||||
#include <sem.h>
|
||||
#include <syscall_restart.h>
|
||||
#include <syscall_utils.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
#include <tracing.h>
|
||||
@ -331,9 +333,12 @@ handle_signals(struct thread *thread)
|
||||
|
||||
thread->user_thread->pending_signals = 0;
|
||||
|
||||
bool restart = (atomic_and(&thread->flags,
|
||||
~THREAD_FLAGS_DONT_RESTART_SYSCALL)
|
||||
& THREAD_FLAGS_DONT_RESTART_SYSCALL) == 0;
|
||||
uint32 restartFlags = atomic_and(&thread->flags,
|
||||
~THREAD_FLAGS_DONT_RESTART_SYSCALL);
|
||||
bool alwaysRestart
|
||||
= (restartFlags & THREAD_FLAGS_ALWAYS_RESTART_SYSCALL) != 0;
|
||||
bool restart = alwaysRestart
|
||||
|| (restartFlags & THREAD_FLAGS_DONT_RESTART_SYSCALL) == 0;
|
||||
|
||||
T(HandleSignals(signalMask));
|
||||
|
||||
@ -475,8 +480,10 @@ handle_signals(struct thread *thread)
|
||||
if (debugSignal && !notify_debugger(thread, signal, handler, false))
|
||||
continue;
|
||||
|
||||
if (!restart || (handler->sa_flags & SA_RESTART) == 0)
|
||||
if (!restart
|
||||
|| ((!alwaysRestart && handler->sa_flags & SA_RESTART) == 0)) {
|
||||
atomic_and(&thread->flags, ~THREAD_FLAGS_RESTART_SYSCALL);
|
||||
}
|
||||
|
||||
T(ExecuteSignalHandler(signal, handler));
|
||||
|
||||
@ -702,8 +709,8 @@ has_signals_pending(void *_thread)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sigprocmask(int how, const sigset_t *set, sigset_t *oldSet)
|
||||
static int
|
||||
sigprocmask_internal(int how, const sigset_t *set, sigset_t *oldSet)
|
||||
{
|
||||
struct thread *thread = thread_get_current_thread();
|
||||
sigset_t oldMask = atomic_get(&thread->sig_block_mask);
|
||||
@ -735,11 +742,18 @@ sigprocmask(int how, const sigset_t *set, sigset_t *oldSet)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sigprocmask(int how, const sigset_t *set, sigset_t *oldSet)
|
||||
{
|
||||
RETURN_AND_SET_ERRNO(sigprocmask_internal(how, set, oldSet));
|
||||
}
|
||||
|
||||
|
||||
/*! \brief sigaction() for the specified thread.
|
||||
A \a threadID is < 0 specifies the current thread.
|
||||
*/
|
||||
int
|
||||
sigaction_etc(thread_id threadID, int signal, const struct sigaction *act,
|
||||
static status_t
|
||||
sigaction_etc_internal(thread_id threadID, int signal, const struct sigaction *act,
|
||||
struct sigaction *oldAction)
|
||||
{
|
||||
struct thread *thread;
|
||||
@ -792,6 +806,15 @@ sigaction_etc(thread_id threadID, int signal, const struct sigaction *act,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sigaction_etc(thread_id threadID, int signal, const struct sigaction *act,
|
||||
struct sigaction *oldAction)
|
||||
{
|
||||
RETURN_AND_SET_ERRNO(sigaction_etc_internal(threadID, signal, act,
|
||||
oldAction));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sigaction(int signal, const struct sigaction *act, struct sigaction *oldAction)
|
||||
{
|
||||
@ -854,40 +877,57 @@ set_alarm(bigtime_t time, uint32 mode)
|
||||
/*! Wait for the specified signals, and return the signal retrieved in
|
||||
\a _signal.
|
||||
*/
|
||||
int
|
||||
sigwait(const sigset_t *set, int *_signal)
|
||||
static status_t
|
||||
sigwait_internal(const sigset_t *set, int *_signal)
|
||||
{
|
||||
struct thread *thread = thread_get_current_thread();
|
||||
sigset_t requestedSignals = *set & BLOCKABLE_SIGNALS;
|
||||
|
||||
while (!has_signals_pending(thread)) {
|
||||
thread_prepare_to_block(thread, B_CAN_INTERRUPT,
|
||||
THREAD_BLOCK_TYPE_SIGNAL, NULL);
|
||||
thread_block();
|
||||
}
|
||||
struct thread* thread = thread_get_current_thread();
|
||||
|
||||
int signalsPending = atomic_get(&thread->sig_pending) & *set;
|
||||
|
||||
update_current_thread_signals_flag();
|
||||
|
||||
if (signalsPending) {
|
||||
// select the lowest pending signal to return in _signal
|
||||
for (int signal = 1; signal < NSIG; signal++) {
|
||||
if ((SIGNAL_TO_MASK(signal) & signalsPending) != 0) {
|
||||
*_signal = signal;
|
||||
return B_OK;
|
||||
while (true) {
|
||||
sigset_t pendingSignals = atomic_get(&thread->sig_pending);
|
||||
sigset_t blockedSignals = atomic_get(&thread->sig_block_mask);
|
||||
sigset_t pendingRequestedSignals = pendingSignals & requestedSignals;
|
||||
if ((pendingRequestedSignals) != 0) {
|
||||
// select the lowest pending signal to return in _signal
|
||||
for (int signal = 1; signal < NSIG; signal++) {
|
||||
if ((SIGNAL_TO_MASK(signal) & pendingSignals) != 0) {
|
||||
atomic_and(&thread->sig_pending, ~SIGNAL_TO_MASK(signal));
|
||||
*_signal = signal;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return B_INTERRUPTED;
|
||||
if ((pendingSignals & ~blockedSignals) != 0) {
|
||||
// Non-blocked signals are pending -- return to let them be handled.
|
||||
return B_INTERRUPTED;
|
||||
}
|
||||
|
||||
// No signals yet. Set the signal block mask to not include the
|
||||
// requested mask and wait until we're interrupted.
|
||||
atomic_set(&thread->sig_block_mask,
|
||||
blockedSignals & ~(requestedSignals & BLOCKABLE_SIGNALS));
|
||||
|
||||
while (!has_signals_pending(thread)) {
|
||||
thread_prepare_to_block(thread, B_CAN_INTERRUPT,
|
||||
THREAD_BLOCK_TYPE_SIGNAL, NULL);
|
||||
thread_block();
|
||||
}
|
||||
|
||||
// restore the original block mask
|
||||
atomic_set(&thread->sig_block_mask, blockedSignals);
|
||||
|
||||
update_current_thread_signals_flag();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! Replace the current signal block mask and wait for any event to happen.
|
||||
Before returning, the original signal block mask is reinstantiated.
|
||||
*/
|
||||
int
|
||||
sigsuspend(const sigset_t *mask)
|
||||
static status_t
|
||||
sigsuspend_internal(const sigset_t *mask)
|
||||
{
|
||||
T(SigSuspend(*mask));
|
||||
|
||||
@ -918,8 +958,8 @@ sigsuspend(const sigset_t *mask)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
sigpending(sigset_t *set)
|
||||
static status_t
|
||||
sigpending_internal(sigset_t *set)
|
||||
{
|
||||
struct thread *thread = thread_get_current_thread();
|
||||
|
||||
@ -961,7 +1001,7 @@ _user_sigprocmask(int how, const sigset_t *userSet, sigset_t *userOldSet)
|
||||
sizeof(sigset_t)) < B_OK))
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
status = sigprocmask(how, userSet ? &set : NULL,
|
||||
status = sigprocmask_internal(how, userSet ? &set : NULL,
|
||||
userOldSet ? &oldSet : NULL);
|
||||
|
||||
// copy old set if asked for
|
||||
@ -1009,9 +1049,14 @@ _user_sigwait(const sigset_t *userSet, int *_userSignal)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
int signal;
|
||||
status_t status = sigwait(&set, &signal);
|
||||
if (status < B_OK)
|
||||
return syscall_restart_handle_post(status);
|
||||
status_t status = sigwait_internal(&set, &signal);
|
||||
if (status == B_INTERRUPTED) {
|
||||
// make sure we'll be restarted
|
||||
struct thread* thread = thread_get_current_thread();
|
||||
atomic_or(&thread->flags,
|
||||
THREAD_FLAGS_ALWAYS_RESTART_SYSCALL | THREAD_FLAGS_RESTART_SYSCALL);
|
||||
return status;
|
||||
}
|
||||
|
||||
return user_memcpy(_userSignal, &signal, sizeof(int));
|
||||
}
|
||||
@ -1027,7 +1072,7 @@ _user_sigsuspend(const sigset_t *userMask)
|
||||
if (user_memcpy(&mask, userMask, sizeof(sigset_t)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
return sigsuspend(&mask);
|
||||
return sigsuspend_internal(&mask);
|
||||
}
|
||||
|
||||
|
||||
@ -1042,7 +1087,7 @@ _user_sigpending(sigset_t *userSet)
|
||||
if (!IS_USER_ADDRESS(userSet))
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
status = sigpending(&set);
|
||||
status = sigpending_internal(&set);
|
||||
if (status == B_OK
|
||||
&& user_memcpy(userSet, &set, sizeof(sigset_t)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
Loading…
x
Reference in New Issue
Block a user