[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