[haiku-commits] r36054 - in haiku/trunk: headers/private/kernel src/system/kernel
- From: ingo_weinhold@xxxxxx
- To: haiku-commits@xxxxxxxxxxxxx
- Date: Tue, 6 Apr 2010 22:23:18 +0200 (CEST)
Author: bonefish
Date: 2010-04-06 22:23:18 +0200 (Tue, 06 Apr 2010)
New Revision: 36054
Changeset: http://dev.haiku-os.org/changeset/36054/haiku
Modified:
haiku/trunk/headers/private/kernel/thread_types.h
haiku/trunk/src/system/kernel/signal.cpp
Log:
* 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.
Modified: haiku/trunk/headers/private/kernel/thread_types.h
===================================================================
--- haiku/trunk/headers/private/kernel/thread_types.h 2010-04-06 19:43:27 UTC
(rev 36053)
+++ haiku/trunk/headers/private/kernel/thread_types.h 2010-04-06 20:23:18 UTC
(rev 36054)
@@ -348,16 +348,34 @@
// 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 */
Modified: haiku/trunk/src/system/kernel/signal.cpp
===================================================================
--- haiku/trunk/src/system/kernel/signal.cpp 2010-04-06 19:43:27 UTC (rev
36053)
+++ haiku/trunk/src/system/kernel/signal.cpp 2010-04-06 20:23:18 UTC (rev
36054)
@@ -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 @@
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 @@
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 @@
}
-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 @@
}
+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;
@@ -793,6 +807,15 @@
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)
{
return sigaction_etc(-1, signal, act, oldAction);
@@ -854,40 +877,57 @@
/*! 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;
+ 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;
+ }
+ }
+ }
- update_current_thread_signals_flag();
+ if ((pendingSignals & ~blockedSignals) != 0) {
+ // Non-blocked signals are pending -- return to let
them be handled.
+ return B_INTERRUPTED;
+ }
- 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;
- }
+ // 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();
}
-
- return B_INTERRUPTED;
}
/*! 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 @@
}
-int
-sigpending(sigset_t *set)
+static status_t
+sigpending_internal(sigset_t *set)
{
struct thread *thread = thread_get_current_thread();
@@ -961,7 +1001,7 @@
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 @@
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 @@
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 @@
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;
Other related posts:
- » [haiku-commits] r36054 - in haiku/trunk: headers/private/kernel src/system/kernel - ingo_weinhold