[haiku-commits] r41560 - in haiku/branches/developer/bonefish/signals: headers/private/kernel headers/private/system src/system/kernel src/system/libroot/posix/signal

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 18 May 2011 03:27:29 +0200 (CEST)

Author: bonefish
Date: 2011-05-18 03:27:28 +0200 (Wed, 18 May 2011)
New Revision: 41560
Changeset: https://dev.haiku-os.org/changeset/41560
Ticket: https://dev.haiku-os.org/ticket/5679

Modified:
   haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h
   
haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h
   haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h
   haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp
   haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp
   
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/kill.c
   
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/raise.c
   
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/signal/send_signal.c
Log:
* PendingSignals:
  - Renamed HighestSignalPriority() and DequeueSignal() parameter blocked to
    nonBlocked and inverted semantics.
  - _GetHighestPrioritySignal(): Fixed return value in case we found an unqueued
    signal.
* Thread::AllPendingSignals(): Now returns the signals pending for this thread
  or for the team.
* handle_signals(): Also handle team signals.
* is_team_signal_blocked(): Added Team* team parameter. The function now checks
  whether all of the team's threads block the signal.
* send_signal_to_team_locked(): Actually send the signal to the team.
* sigwait_internal(): Also handle team signals.
* Added "bool toThread" parameter to _kern_send_signal(). If the given ID is
  >= 0, toThread determines whether the target is a thread or a team.
* kill(): Changed semantics to be more POSIX compliant: An ID >= 0 targets a
  team now, not a thread. This breaks BeOS compatibility. send_signal() works
  as before, though.
* raise(): Use send_signal() instead of kill() to get POSIX semantics.

This aligns the handling of signals sent to processes with required POSIX
semantics: A signal sent to a process is handled by any thread in the process
that does't block the signal (addresses #5679).


Modified: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h  
2011-05-17 23:02:44 UTC (rev 41559)
+++ haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h  
2011-05-18 01:27:28 UTC (rev 41560)
@@ -1,5 +1,7 @@
 /*
- * Copyright 2003-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx All rights 
reserved.
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Copyright 2003-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx
+ * All rights reserved.
  * Distributed under the terms of the MIT License.
  */
 #ifndef _KERNEL_SIGNAL_H
@@ -40,19 +42,20 @@
 struct Signal : BReferenceable, DeferredDeletable,
        DoublyLinkedListLinkImpl<Signal> {
 public:
-                                                               Signal(int32 
number) : fNumber(number) {}
+                                                               Signal() {}
+                                                               Signal(uint32 
number) : fNumber(number) {}
 
-                       void                            SetTo(int32 number)
+                       void                            SetTo(uint32 number)
                                                                        { 
fNumber = number; }
 
-                       int32                           Number() const { return 
fNumber; }
+                       uint32                          Number() const { return 
fNumber; }
                        int32                           Priority() const;
 
 protected:
        virtual void                            LastReferenceReleased();
 
 private:
-                       int                                     fNumber;
+                       uint32                          fNumber;
 };
 
 
@@ -64,7 +67,8 @@
                                                                        { 
return fQueuedSignalsMask
                                                                                
| fUnqueuedSignalsMask; }
 
-                       int32                           
HighestSignalPriority(sigset_t blocked) const;
+                       int32                           
HighestSignalPriority(sigset_t nonBlocked)
+                                                                       const;
 
                        void                            Clear();
                        void                            AddSignal(int32 signal)
@@ -75,13 +79,14 @@
                                                                        { 
RemoveSignals(SIGNAL_TO_MASK(signal)); }
                        void                            RemoveSignals(sigset_t 
mask);
 
-                       Signal*                         DequeueSignal(sigset_t 
blocked, Signal& buffer);
+                       Signal*                         DequeueSignal(sigset_t 
nonBlocked,
+                                                                       Signal& 
buffer);
 
 private:
                        typedef DoublyLinkedList<Signal> SignalList;
 
 private:
-                       int32                           
_GetHighestPrioritySignal(sigset_t blocked,
+                       int32                           
_GetHighestPrioritySignal(sigset_t nonBlocked,
                                                                        
Signal*& _queuedSignal,
                                                                        int32& 
_unqueuedSignal) const;
                        void                            
_UpdateQueuedSignalMask();
@@ -105,7 +110,7 @@
 #endif
 
 bool handle_signals(Thread *thread);
-bool is_team_signal_blocked(int signal);
+bool is_team_signal_blocked(Team* team, int signal);
 
 status_t send_signal_to_thread(thread_id threadID, uint32 signal, uint32 
flags);
 status_t send_signal_to_team_locked(Team* team, uint32 signal, uint32 flags);
@@ -117,7 +122,7 @@
 
 void update_current_thread_signals_flag();
 
-status_t _user_send_signal(pid_t tid, uint sig);
+status_t _user_send_signal(int32 id, uint32 signal, bool toThread);
 status_t _user_sigprocmask(int how, const sigset_t *set, sigset_t *oldSet);
 status_t _user_sigaction(int sig, const struct sigaction *newAction,
        struct sigaction *oldAction);

Modified: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h
===================================================================
--- 
haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 
    2011-05-17 23:02:44 UTC (rev 41559)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 
    2011-05-18 01:27:28 UTC (rev 41560)
@@ -310,12 +310,22 @@
                                                                        const 
char* const* otherArgs,
                                                                        int 
otherArgCount);
 
+                       sigset_t                        PendingSignals() const
+                                                                       { 
return fPendingSignals.AllSignals(); }
+
+                       void                            AddPendingSignal(int 
signal)
+                                                                       { 
fPendingSignals.AddSignal(signal); }
                        void                            RemovePendingSignal(int 
signal)
                                                                        { 
fPendingSignals.RemoveSignal(signal); }
                        void                            
RemovePendingSignals(sigset_t mask)
                                                                        { 
fPendingSignals.RemoveSignals(mask); }
                        void                            ResetSignals();
 
+       inline  int32                           HighestPendingSignalPriority(
+                                                                       
sigset_t nonBlocked) const;
+       inline  Signal*                         DequeuePendingSignal(sigset_t 
nonBlocked,
+                                                                       Signal& 
buffer);
+
                        struct sigaction&       SignalActionFor(int32 signal)
                                                                        { 
return fSignalActions[signal - 1]; }
                        void                            
InheritSignalActions(Team* parent);
@@ -329,7 +339,8 @@
                        char                            fArgs[64];
                                                                        // 
contents for the team_info::args field
 
-                       PendingSignals          fPendingSignals; // protected 
by scheduler lock
+                       BKernel::PendingSignals fPendingSignals;
+                                                                       // 
protected by scheduler lock
                        struct sigaction        fSignalActions[MAX_SIGNO];
                                                                        // 
protected by fLock
 };
@@ -358,7 +369,7 @@
 
        sigset_t                sig_block_mask; // protected by scheduler lock,
                                                                        // only 
modified by the thread itself
-       sigset_t                sig_temp_enabled;       // protected by 
scheduler lock
+       sigset_t                sig_temp_enabled;       // only accessed by 
this thread
        addr_t                  signal_stack_base;              // only 
accessed by this thread
        size_t                  signal_stack_size;              // only 
accessed by this thread
        bool                    signal_stack_enabled;   // only accessed by 
this thread
@@ -471,8 +482,7 @@
 
                        sigset_t                        ThreadPendingSignals() 
const
                                                                        { 
return fPendingSignals.AllSignals(); }
-                       sigset_t                        AllPendingSignals() 
const
-                                                                       { 
return fPendingSignals.AllSignals(); }
+       inline  sigset_t                        AllPendingSignals() const;
                        void                            AddPendingSignal(int 
signal)
                                                                        { 
fPendingSignals.AddSignal(signal); }
                        void                            RemovePendingSignal(int 
signal)
@@ -481,6 +491,11 @@
                                                                        { 
fPendingSignals.RemoveSignals(mask); }
                        void                            ResetSignals();
 
+       inline  int32                           HighestPendingSignalPriority(
+                                                                       
sigset_t nonBlocked) const;
+       inline  Signal*                         DequeuePendingSignal(sigset_t 
nonBlocked,
+                                                                       Signal& 
buffer);
+
                        bool                            Lock()
                                                                        { 
mutex_lock(&fLock); return true; }
                        bool                            TryLock()
@@ -496,7 +511,8 @@
 private:
                        mutex                           fLock;
 
-                       PendingSignals          fPendingSignals; // protected 
by scheduler lock
+                       BKernel::PendingSignals fPendingSignals;
+                                                                       // 
protected by scheduler lock
 };
 
 
@@ -592,6 +608,41 @@
 };
 
 
+inline int32
+Team::HighestPendingSignalPriority(sigset_t nonBlocked) const
+{
+       return fPendingSignals.HighestSignalPriority(nonBlocked);
+}
+
+
+inline Signal*
+Team::DequeuePendingSignal(sigset_t nonBlocked, Signal& buffer)
+{
+       return fPendingSignals.DequeueSignal(nonBlocked, buffer);
+}
+
+
+inline sigset_t
+Thread::AllPendingSignals() const
+{
+       return fPendingSignals.AllSignals() | team->PendingSignals();
+}
+
+
+inline int32
+Thread::HighestPendingSignalPriority(sigset_t nonBlocked) const
+{
+       return fPendingSignals.HighestSignalPriority(nonBlocked);
+}
+
+
+inline Signal*
+Thread::DequeuePendingSignal(sigset_t nonBlocked, Signal& buffer)
+{
+       return fPendingSignals.DequeueSignal(nonBlocked, buffer);
+}
+
+
 }      // namespace BKernel
 
 using BKernel::Team;

Modified: 
haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h 
2011-05-17 23:02:44 UTC (rev 41559)
+++ haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h 
2011-05-18 01:27:28 UTC (rev 41560)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2004-2010, Haiku Inc. All rights reserved.
+ * Copyright 2004-2011, Haiku, Inc. All rights reserved.
  * Distributed under the terms of the MIT License.
  */
 #ifndef _SYSTEM_SYSCALLS_H
@@ -198,7 +198,7 @@
 extern status_t                _kern_setgroups(int groupCount, const gid_t* 
groupList);
 
 // signal functions
-extern status_t                _kern_send_signal(pid_t tid, uint sig);
+extern status_t                _kern_send_signal(int32 id, uint32 signal, bool 
toThread);
 extern status_t                _kern_sigprocmask(int how, const sigset_t *set,
                                                sigset_t *oldSet);
 extern status_t                _kern_sigaction(int sig, const struct sigaction 
*action,

Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp      
2011-05-17 23:02:44 UTC (rev 41559)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp      
2011-05-18 01:27:28 UTC (rev 41560)
@@ -93,9 +93,6 @@
 };
 
 
-static status_t deliver_signal(Thread *thread, uint signal, uint32 flags);
-
-
 // #pragma mark - Signal
 
 
@@ -133,18 +130,18 @@
 }
 
 
-/*!    Of the signals not it \a blocked returns the priority of that with the
+/*!    Of the signals in \a nonBlocked returns the priority of that with the
        highest priority.
-       \param blocked The mask with the blocked signals.
+       \param nonBlocked The mask with the non-blocked signals.
        \return The priority of the highest priority non-blocked signal, or, if 
all
                signals are blocked, \c -1.
 */
 int32
-PendingSignals::HighestSignalPriority(sigset_t blocked) const
+PendingSignals::HighestSignalPriority(sigset_t nonBlocked) const
 {
        Signal* queuedSignal;
        int32 unqueuedSignal;
-       return _GetHighestPrioritySignal(blocked, queuedSignal, unqueuedSignal);
+       return _GetHighestPrioritySignal(nonBlocked, queuedSignal, 
unqueuedSignal);
 }
 
 
@@ -203,22 +200,21 @@
 }
 
 
-/*!    Removes and returns a signal not in \a blocked that has the highest
-       priority.
+/*!    Removes and returns a signal in \a nonBlocked that has the highest 
priority.
        The caller gets a reference to the returned signal, if any.
-       \param blocked The mask of blocked signals.
+       \param nonBlocked The mask of non-blocked signals.
        \param buffer If the signal is not queued this buffer is returned. In 
this
                case the method acquires a reference to \a buffer, so that the 
caller
                gets a reference also in this case.
        \return The removed signal or \c NULL, if all signals are blocked.
 */
 Signal*
-PendingSignals::DequeueSignal(sigset_t blocked, Signal& buffer)
+PendingSignals::DequeueSignal(sigset_t nonBlocked, Signal& buffer)
 {
        // find the signal with the highest priority
        Signal* queuedSignal;
        int32 unqueuedSignal;
-       if (_GetHighestPrioritySignal(blocked, queuedSignal, unqueuedSignal) < 
0)
+       if (_GetHighestPrioritySignal(nonBlocked, queuedSignal, unqueuedSignal) 
< 0)
                return NULL;
 
        // if it is a queued signal, dequeue it
@@ -240,7 +236,7 @@
 
 /*!    Of the signals not it \a blocked returns the priority of that with the
        highest priority.
-       \param blocked The mask with the blocked signals.
+       \param blocked The mask with the non-blocked signals.
        \param _queuedSignal If the found signal is a queued signal, the 
variable
                will be set to that signal, otherwise to \c NULL.
        \param _unqueuedSignal If the found signal is an unqueued signal, the
@@ -249,11 +245,9 @@
                signals are blocked, \c -1.
 */
 int32
-PendingSignals::_GetHighestPrioritySignal(sigset_t blocked,
+PendingSignals::_GetHighestPrioritySignal(sigset_t nonBlocked,
        Signal*& _queuedSignal, int32& _unqueuedSignal) const
 {
-       sigset_t nonBlocked = ~blocked;
-
        // check queued signals
        Signal* queuedSignal = NULL;
        int32 queuedPriority = -1;
@@ -301,7 +295,7 @@
 
        _queuedSignal = NULL;
        _unqueuedSignal = unqueuedSignal;
-       return queuedPriority;
+       return unqueuedPriority;
 }
 
 
@@ -326,28 +320,29 @@
 namespace SignalTracing {
 
 
-class HandleSignals : public AbstractTraceEntry {
+class HandleSignal : public AbstractTraceEntry {
        public:
-               HandleSignals(uint32 signals)
+               HandleSignal(uint32 signal)
                        :
-                       fSignals(signals)
+                       fSignal(signal)
                {
                        Initialized();
                }
 
                virtual void AddDump(TraceOutput& out)
                {
-                       out.Print("signal handle:  0x%lx", fSignals);
+                       out.Print("signal handle:  %" B_PRIu32 " (%s)" , 
fSignal,
+                               fSignal < NSIG ? kSignalInfos[fSignal].name : 
"invalid");
                }
 
        private:
-               uint32          fSignals;
+               uint32          fSignal;
 };
 
 
 class ExecuteSignalHandler : public AbstractTraceEntry {
        public:
-               ExecuteSignalHandler(int signal, struct sigaction* handler)
+               ExecuteSignalHandler(uint32 signal, struct sigaction* handler)
                        :
                        fSignal(signal),
                        fHandler((void*)handler->sa_handler)
@@ -357,12 +352,14 @@
 
                virtual void AddDump(TraceOutput& out)
                {
-                       out.Print("signal exec handler: signal: %d, handler: 
%p",
-                               fSignal, fHandler);
+                       out.Print("signal exec handler: signal: %" B_PRIu32 " 
(%s), "
+                               "handler: %p", fSignal,
+                               fSignal < NSIG ? kSignalInfos[fSignal].name : 
"invalid",
+                               fHandler);
                }
 
        private:
-               int             fSignal;
+               uint32  fSignal;
                void*   fHandler;
 };
 
@@ -513,7 +510,7 @@
 static void
 update_thread_signals_flag(Thread* thread)
 {
-       sigset_t mask = ~thread->sig_block_mask | thread->sig_temp_enabled;
+       sigset_t mask = ~thread->sig_block_mask;
        if ((thread->AllPendingSignals() & mask) != 0)
                atomic_or(&thread->flags, THREAD_FLAGS_SIGNALS_PENDING);
        else
@@ -532,6 +529,20 @@
 }
 
 
+/*!    Updates all of the given team's threads' Thread::flags fields according 
to
+       what signals are pending.
+       The caller must hold the scheduler lock.
+*/
+static void
+update_team_threads_signal_flag(Team* team)
+{
+       for (Thread* thread = team->thread_list; thread != NULL;
+                       thread = thread->team_next) {
+               update_thread_signals_flag(thread);
+       }
+}
+
+
 /*!    Notifies the user debugger about a signal to be handled.
 
        The caller must not hold any locks.
@@ -544,10 +555,10 @@
                ignored.
 */
 static bool
-notify_debugger(Thread* thread, int signal, struct sigaction& handler,
+notify_debugger(Thread* thread, Signal* signal, struct sigaction& handler,
        bool deadly)
 {
-       uint64 signalMask = SIGNAL_TO_MASK(signal);
+       uint64 signalMask = SIGNAL_TO_MASK(signal->Number());
 
        // first check the ignore signal masks the debugger specified for the 
thread
        InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
@@ -563,10 +574,42 @@
        threadDebugInfoLocker.Unlock();
 
        // deliver the event
-       return user_debug_handle_signal(signal, &handler, deadly);
+       return user_debug_handle_signal(signal->Number(), &handler, deadly);
 }
 
 
+/*!    Removes and returns a signal with the highest priority in \a nonBlocked 
that
+       is pending in the given thread or its team.
+       After dequeuing the signal the Thread::flags field of the affected 
threads
+       are updated.
+       The caller gets a reference to the returned signal, if any.
+       The caller must hold the scheduler lock.
+       \param thread The thread.
+       \param nonBlocked The mask of non-blocked signals.
+       \param buffer If the signal is not queued this buffer is returned. In 
this
+               case the method acquires a reference to \a buffer, so that the 
caller
+               gets a reference also in this case.
+       \return The removed signal or \c NULL, if all signals are blocked.
+*/
+static Signal*
+dequeue_thread_or_team_signal(Thread* thread, sigset_t nonBlocked,
+       Signal& buffer)
+{
+       Team* team = thread->team;
+       Signal* signal;
+       if (team->HighestPendingSignalPriority(nonBlocked)
+                       > thread->HighestPendingSignalPriority(nonBlocked)) {
+               signal = team->DequeuePendingSignal(nonBlocked, buffer);
+               update_team_threads_signal_flag(team);
+       } else {
+               signal = thread->DequeuePendingSignal(nonBlocked, buffer);
+               update_thread_signals_flag(thread);
+       }
+
+       return signal;
+}
+
+
 /*! Actually handles the signal -- i.e. the thread will exit, a custom signal
        handler is prepared, or whatever the signal demands.
        Interrupts must be enabled.
@@ -581,35 +624,25 @@
 {
        Team* team = thread->team;
 
-       // get the pending signals that need to be handled
+       TeamLocker teamLocker(team);
        InterruptsSpinLocker schedulerLocker(gSchedulerLock);
 
-       uint32 signalMask = thread->AllPendingSignals()
-               & (~thread->sig_block_mask | thread->sig_temp_enabled);
-       thread->sig_temp_enabled = 0;
+       // If userland requested to defer signals, we check now, if this is
+       // possible.
+       sigset_t nonBlockedMask = thread->sig_temp_enabled != 0
+               ? thread->sig_temp_enabled : ~thread->sig_block_mask;
+       sigset_t signalMask = thread->AllPendingSignals() & nonBlockedMask;
 
-       schedulerLocker.Unlock();
-
-       // If SIGKILL[THR] are pending, we ignore other signals.
-       // Otherwise check, if the thread shall stop for debugging.
-       if ((signalMask & KILL_SIGNALS) != 0) {
-               signalMask &= KILL_SIGNALS;
-       } else if ((atomic_get(&thread->debug_info.flags) & B_THREAD_DEBUG_STOP)
-                       != 0) {
-               user_debug_stop_thread();
-       }
-
-       if (signalMask == 0)
-               return false;
-
        if (thread->user_thread->defer_signals > 0
-               && (signalMask & NON_DEFERRABLE_SIGNALS) == 0) {
+               && (signalMask & NON_DEFERRABLE_SIGNALS) == 0
+               && thread->sig_temp_enabled == 0) {
                thread->user_thread->pending_signals = signalMask;
                return false;
        }
 
        thread->user_thread->pending_signals = 0;
 
+       // determine syscall restart behavior
        uint32 restartFlags = atomic_and(&thread->flags,
                ~THREAD_FLAGS_DONT_RESTART_SYSCALL);
        bool alwaysRestart
@@ -617,40 +650,65 @@
        bool restart = alwaysRestart
                || (restartFlags & THREAD_FLAGS_DONT_RESTART_SYSCALL) == 0;
 
-       T(HandleSignals(signalMask));
+       // Loop until we've handled all signals.
+       bool initialIteration = true;
+       while (true) {
+               if (initialIteration) {
+                       initialIteration = false;
+               } else {
+                       teamLocker.Lock();
+                       schedulerLocker.Lock();
 
-       for (int32 i = 0; i < NSIG; i++) {
-               bool debugSignal;
-               int32 signal = i + 1;
+                       signalMask = thread->AllPendingSignals() & 
nonBlockedMask;
+               }
 
-// TODO: Move below and also check the team's pending signals.
-               if ((signalMask & SIGNAL_TO_MASK(signal)) == 0)
+               // Unless SIGKILL[THR] are pending, check, if the thread shall 
stop for
+               // debugging.
+               if ((signalMask & KILL_SIGNALS) == 0
+                       && (atomic_get(&thread->debug_info.flags) & 
B_THREAD_DEBUG_STOP)
+                               != 0) {
+                       schedulerLocker.Unlock();
+                       teamLocker.Unlock();
+
+                       user_debug_stop_thread();
                        continue;
+               }
 
-               // clear the signal that we will handle
-               TeamLocker teamLocker(team);
-               schedulerLocker.Lock();
+               // We're done, if there aren't any pending signals anymore.
+               if ((signalMask & nonBlockedMask) == 0)
+                       break;
 
-// TODO: Might be a pending team signal.
-               thread->RemovePendingSignal(signal);
-               update_current_thread_signals_flag();
+               // get pending non-blocked thread or team signal with the 
highest
+               // priority
+               Signal stackSignal;
+               Signal* signal = dequeue_thread_or_team_signal(thread, 
nonBlockedMask,
+                       stackSignal);
+               ASSERT(signal != NULL);
+               BReference<Signal> signalReference(signal, true);
 
                schedulerLocker.Unlock();
 
-               struct sigaction handler = team->SignalActionFor(signal);
+               // get the action for the signal
+               struct sigaction handler = 
team->SignalActionFor(signal->Number());
 
                if ((handler.sa_flags & SA_ONESHOT) != 0
                        && handler.sa_handler != SIG_IGN && handler.sa_handler 
!= SIG_DFL) {
-                       team->SignalActionFor(signal).sa_handler = SIG_DFL;
+                       team->SignalActionFor(signal->Number()).sa_handler = 
SIG_DFL;
                }
 
+               T(HandleSignal(signal->Number()));
+
                teamLocker.Unlock();
 
-               debugSignal = !(~atomic_get(&team->debug_info.flags)
-                               & (B_TEAM_DEBUG_SIGNALS | 
B_TEAM_DEBUG_DEBUGGER_INSTALLED));
+               // debug the signal, if a debugger is installed and the signal 
debugging
+               // flag is set
+               bool debugSignal = (~atomic_get(&team->debug_info.flags)
+                               & (B_TEAM_DEBUG_DEBUGGER_INSTALLED | 
B_TEAM_DEBUG_SIGNALS))
+                       != 0;
 
-               TRACE(("Thread 0x%lx received signal %s\n", thread->id,
-                       kSignalInfos[signal].name));
+               // handle the signal
+               TRACE(("Thread %" B_PRId32 " received signal %s\n", thread->id,
+                       kSignalInfos[signal->Number()].name));
 
                if (handler.sa_handler == SIG_IGN) {
                        // signal is to be ignored
@@ -662,7 +720,7 @@
                        continue;
                } else if (handler.sa_handler == SIG_DFL) {
                        // default signal behaviour
-                       switch (signal) {
+                       switch (signal->Number()) {
                                case SIGCHLD:
                                case SIGWINCH:
                                case SIGURG:
@@ -682,7 +740,8 @@
                                                team->LockTeamAndParent(false);
 
                                                team_set_job_control_state(team,
-                                                       
JOB_CONTROL_STATE_CONTINUED, signal, false);
+                                                       
JOB_CONTROL_STATE_CONTINUED, signal->Number(),
+                                                       false);
 
                                                team->UnlockTeamAndParent();
 
@@ -706,12 +765,10 @@
                                                team->LockTeamAndParent(false);
 
                                                team_set_job_control_state(team,
-                                                       
JOB_CONTROL_STATE_STOPPED, signal, false);
+                                                       
JOB_CONTROL_STATE_STOPPED, signal->Number(), false);
 
                                                // send a SIGCHLD to the parent 
(if it does have
                                                // SA_NOCLDSTOP defined)
-                                               // TODO: We should send the 
signal to the team, not the
-                                               // thread.
                                                Team* parentTeam = team->parent;
 
                                                struct sigaction& parentHandler
@@ -734,7 +791,7 @@
                                        // the main thread first, since the 
signal will kill this
                                        // thread only.
                                        if (thread != team->main_thread)
-                                               send_signal_to_team(team->id, 
SIGKILL, 0);
+                                               send_signal_to_thread(team->id, 
SIGKILL, 0);
                                case SIGQUIT:
                                case SIGPOLL:
                                case SIGPROF:
@@ -742,19 +799,20 @@
                                case SIGVTALRM:
                                case SIGXCPU:
                                case SIGXFSZ:
-                                       TRACE(("Shutting down thread 0x%lx due 
to signal #%ld\n",
-                                               thread->id, signal));
+                                       TRACE(("Shutting down thread %" 
B_PRId32 " due to signal %"
+                                               B_PRIu32 "\n", thread->id, 
signal->Number()));
                                case SIGKILL:
                                case SIGKILLTHR:
                                default:
                                        // if the thread exited normally, the 
exit reason is already set
                                        if (thread->exit.reason != 
THREAD_RETURN_EXIT) {
                                                thread->exit.reason = 
THREAD_RETURN_INTERRUPTED;
-                                               thread->exit.signal = 
(uint16)signal;
+                                               thread->exit.signal = 
(uint16)signal->Number();
                                        }
 
                                        // notify the debugger
-                                       if (debugSignal && signal != SIGKILL && 
signal != SIGKILLTHR
+                                       if (debugSignal && signal->Number() != 
SIGKILL
+                                               && signal->Number() != 
SIGKILLTHR
                                                && !notify_debugger(thread, 
signal, handler, true))
                                                continue;
 
@@ -774,7 +832,7 @@
                        atomic_and(&thread->flags, 
~THREAD_FLAGS_RESTART_SYSCALL);
                }
 
-               T(ExecuteSignalHandler(signal, &handler));
+               T(ExecuteSignalHandler(signal->Number(), &handler));
 
                TRACE(("### Setting up custom signal handler frame...\n"));
 
@@ -786,37 +844,58 @@
                if ((handler.sa_flags & SA_NOMASK) == 0) {
                        // Update the block mask while the signal handler is 
running - it
                        // will be automatically restored when the signal frame 
is left.
-                       thread->sig_block_mask |= (handler.sa_mask | 
SIGNAL_TO_MASK(signal))
-                               & BLOCKABLE_SIGNALS;
+                       thread->sig_block_mask
+                               |= (handler.sa_mask | 
SIGNAL_TO_MASK(signal->Number()))
+                                       & BLOCKABLE_SIGNALS;
                }
 
                update_current_thread_signals_flag();
 
                schedulerLocker.Unlock();
 
-               arch_setup_signal_frame(thread, &handler, signal, blockMask);
+               arch_setup_signal_frame(thread, &handler, signal->Number(), 
blockMask);
 
+               // Reset sig_temp_enabled. It would have been set by
+               // sigsuspend_internal().
+               thread->sig_temp_enabled = 0;
+
                return false;
        }
 
-       // clear syscall restart thread flag, if we're not supposed to restart 
the
-       // syscall
-       if (!restart)
+       // We have not handled any signal (respectively only ignored ones).
+
+       // If sig_temp_enabled is non-null, we came from a sigsuspend(). Not 
having
+       // handled any signal, we should restart the syscall.
+       if (thread->sig_temp_enabled != 0) {
+               thread->sig_temp_enabled = 0;
+               restart = true;
+               atomic_or(&thread->flags, THREAD_FLAGS_RESTART_SYSCALL);
+       } else if (!restart) {
+               // clear syscall restart thread flag, if we're not supposed to 
restart
+               // the syscall
                atomic_and(&thread->flags, ~THREAD_FLAGS_RESTART_SYSCALL);
+       }
 
        return false;
 }
 
 
-/*!    Checks whether the given signal is blocked for the process.
-       The caller must hold the scheduler lock.
+/*!    Checks whether the given signal is blocked for the given team (i.e. all 
of
+       its threads).
+       The caller must hold the team's lock and the scheduler lock.
 */
 bool
-is_team_signal_blocked(int signal)
+is_team_signal_blocked(Team* team, int signal)
 {
-// TODO: Check the team, not the current thread!
-       return (thread_get_current_thread()->sig_block_mask
-               & SIGNAL_TO_MASK(signal)) != 0;
+       sigset_t mask = SIGNAL_TO_MASK(signal);
+
+       for (Thread* thread = team->thread_list; thread != NULL;
+                       thread = thread->team_next) {
+               if ((thread->sig_block_mask & mask) == 0)
+                       return false;
+       }
+
+       return true;
 }
 
 
@@ -1017,16 +1096,96 @@
 {
        T(SendSignal(team->id, signal, flags));
 
-       // TODO: Actually send the signal to the team!
-       if (team->main_thread == NULL)
-               return B_BAD_TEAM_ID;
+       if ((flags & B_CHECK_PERMISSION) != 0) {
+               // TODO: check permission
+       }
 
-       status_t error = deliver_signal(team->main_thread, signal, flags);
-       if (error != B_OK)
-               return error;
+       if (signal == 0)
+               return B_OK;
 
+       if (team == team_get_kernel_team()) {
+               // signals to the kernel team are ignored
+               return B_NOT_ALLOWED;
+       }
+
+       InterruptsSpinLocker schedulerLocker(gSchedulerLock);
+
+       team->AddPendingSignal(signal);
+
+       switch (signal) {
+               case SIGKILL:
+               case SIGKILLTHR:
+               {
+                       // Also add a SIGKILLTHR to the main thread's signals 
and wake it
+                       // up/interrupt it, so we get this over with as soon as 
possible
+                       // (only the main thread shuts down the team).
+                       Thread* mainThread = team->main_thread;
+                       if (mainThread != NULL) {
+                               mainThread->AddPendingSignal(SIGKILLTHR);
+
+                               // wake up main thread
+                               if (mainThread->state == B_THREAD_SUSPENDED)
+                                       
scheduler_enqueue_in_run_queue(mainThread);
+                               else
+                                       thread_interrupt(mainThread, true);
+                       }
+                       break;
+               }
+
+               case SIGCONT:
+                       // wake up any suspended threads
+                       for (Thread* thread = team->thread_list; thread != NULL;
+                                       thread = thread->team_next) {
+                               if (thread->state == B_THREAD_SUSPENDED) {
+                                       scheduler_enqueue_in_run_queue(thread);
+
+                                       // don't restart syscall, if requested
+                                       if ((flags & 
SIGNAL_FLAG_DONT_RESTART_SYSCALL) != 0) {
+                                               atomic_or(&thread->flags,
+                                                       
THREAD_FLAGS_DONT_RESTART_SYSCALL);
+                                       }
+                               }
+
+                               // remove any pending stop signals
+                               thread->RemovePendingSignals(STOP_SIGNALS);
+                       }
+
+                       // remove any pending team stop signals
+                       team->RemovePendingSignals(STOP_SIGNALS);
+                       break;
+
+               case SIGSTOP:
+               case SIGTSTP:
+               case SIGTTIN:
+               case SIGTTOU:
+                       // send the stop signal to all threads
+                       // TODO: Is that correct or should we only target the 
main thread?
+                       for (Thread* thread = team->thread_list; thread != NULL;
+                                       thread = thread->team_next) {
+                               thread->AddPendingSignal(signal);
+                       }
+
+                       // remove the stop signal from the team again
+                       team->RemovePendingSignal(signal);
+
+                       // fall through to interrupt threads
+               default:
+                       // Interrupt all interruptibly waiting threads, if the 
signal is
+                       // not masked.
+                       for (Thread* thread = team->thread_list; thread != NULL;
+                                       thread = thread->team_next) {
+                               sigset_t nonBlocked = ~thread->sig_block_mask
+                                       | SIGNAL_TO_MASK(SIGCHLD);
+                               if ((thread->AllPendingSignals() & nonBlocked) 
!= 0)
+                                       thread_interrupt(thread, false);
+                       }
+                       break;
+       }
+
+       update_team_threads_signal_flag(team);
+
        if ((flags & B_DO_NOT_RESCHEDULE) == 0)
-               scheduler_reschedule_if_necessary();
+               scheduler_reschedule_if_necessary_locked();
 
        return B_OK;
 }
@@ -1134,25 +1293,31 @@
 int
 send_signal_etc(pid_t id, uint signal, uint32 flags)
 {
-       if (signal < 0 || signal > MAX_SIGNO)
+       if (signal > MAX_SIGNO)
                return B_BAD_VALUE;
 
        // If id is > 0, send the signal to the respective thread.
        if (id > 0)
                return send_signal_to_thread(id, signal, flags);
 
-       // send a signal to the specified process group (the absolute value of 
the
-       // id)
+       // If id == 0, send the signal to the current thread.
+       if (id == 0) {
+               return send_signal_to_thread(thread_get_current_thread_id(), 
signal,
+                       flags);
+       }
 
-       // TODO: Handle -1 correctly: The signal shall be sent to all teams the
-       // calling team has permission to send signals to.
-       if (id == 0 || id == -1) {
-               // send a signal to the current team
-               id = thread_get_current_thread()->team->id;
-       } else
-               id = -id;
+       // If id == -1, send the signal to all teams the calling team has 
permission
+       // to send signals to.
+       if (id == -1) {
+               // TODO: Implement correctly!
+               // currently only send to the current team
+               return 
send_signal_to_team(thread_get_current_thread()->team->id,
+                       signal, flags);
+       }
 
-       return send_signal_to_process_group(id, signal, flags);
+       // Send a signal to the specified process group (the absolute value of 
the
+       // id).
+       return send_signal_to_process_group(-id, signal, flags);
 }
 
 
@@ -1208,8 +1373,7 @@
 }
 
 
-/*!    \brief sigaction() for the specified thread.
-       A \a threadID is < 0 specifies the current thread.
+/*!    \brief Like sigaction(), but returning the error instead of setting 
errno.
 */
 static status_t
 sigaction_internal(int signal, const struct sigaction* act,
@@ -1292,7 +1456,7 @@
        Thread* thread = thread_get_current_thread();
        bigtime_t remainingTime = 0;
 
-       ASSERT(B_ONE_SHOT_RELATIVE_ALARM == B_ONE_SHOT_RELATIVE_TIMER);
+       STATIC_ASSERT(B_ONE_SHOT_RELATIVE_ALARM == B_ONE_SHOT_RELATIVE_TIMER);
                // just to be sure no one changes the headers some day
 
        TRACE(("set_alarm: thread = %p\n", thread));
@@ -1334,20 +1498,20 @@
        InterruptsSpinLocker schedulerLocker(gSchedulerLock);
 
        while (true) {
-               sigset_t blockedSignals = thread->sig_block_mask;
                sigset_t pendingSignals = thread->AllPendingSignals();
                if ((pendingSignals & requestedSignals) != 0) {
-                       // select the lowest pending signal to return in _signal
-                       for (int signal = 1; signal < NSIG; signal++) {
-                               if ((SIGNAL_TO_MASK(signal) & pendingSignals) 
!= 0) {
-                                       thread->RemovePendingSignal(signal);
-                                       update_current_thread_signals_flag();
-                                       *_signal = signal;
-                                       return B_OK;
-                               }
-                       }
+                       // get signal with the highest priority
+                       Signal stackSignal;
+                       Signal* signal = dequeue_thread_or_team_signal(thread,
+                               requestedSignals, stackSignal);
+                       ASSERT(signal != NULL);
+                       BReference<Signal> signalReference(signal, true);
+
+                       *_signal = signal->Number();
+                       return B_OK;
                }
 
+               sigset_t blockedSignals = thread->sig_block_mask;
                if ((pendingSignals & ~blockedSignals) != 0) {
                        // Non-blocked signals are pending -- return to let 
them be handled.
                        return B_INTERRUPTED;
@@ -1383,17 +1547,19 @@
        Before returning, the original signal block mask is reinstantiated.
 */
 static status_t
-sigsuspend_internal(const sigset_t* mask)
+sigsuspend_internal(const sigset_t* _mask)
 {
-       T(SigSuspend(*mask));
+       sigset_t mask = *_mask & BLOCKABLE_SIGNALS;
 
+       T(SigSuspend(mask));
+
        Thread* thread = thread_get_current_thread();
 
        InterruptsSpinLocker schedulerLocker(gSchedulerLock);
 
        // Set the new block mask and block until interrupted.
        sigset_t oldMask = thread->sig_block_mask;
-       thread->sig_block_mask = *mask & BLOCKABLE_SIGNALS;
+       thread->sig_block_mask = mask & BLOCKABLE_SIGNALS;
 
        while (!has_signals_pending(thread)) {
                thread_prepare_to_block(thread, B_CAN_INTERRUPT,
@@ -1404,7 +1570,9 @@
        // restore the original block mask
        thread->sig_block_mask = oldMask;
 
-       thread->sig_temp_enabled = ~*mask;
+       thread->sig_temp_enabled = ~mask;
+               // guaranteed to be non-0 (due to BLOCKABLE_SIGNALS), will be 
used and
+               // reset by handle_signals()
 
        update_current_thread_signals_flag();
 
@@ -1457,10 +1625,39 @@
 }
 
 
+/*!    Sends a signal to a thread, process, or process group.
+       \param id Specifies the ID of the target:
+               - \code id > 0 \endcode: If \a toThread is \c true, the target 
is the
+                       thread with ID \a id, otherwise the team with the ID \a 
id.
+               - \code id == 0 \endcode: If toThread is \c true, the target is 
the
+                       current thread, otherwise the current team.
+               - \code id == -1 \endcode: The target are all teams the current 
team has
+                       permission to send signals to. Currently not 
implemented correctly.
+               - \code id < -1 \endcode: The target are is the process group 
with ID
+                       \c -id.
+       \param signal The signal number. \c 0 to just perform checks, but not
+               actually send any signal.
+       \param toThread If \c true, implies BeOS's \c send_signal() semantics, 
i.e.
+               if \code id >= 0 \endcode the target is a thread, not a team. If
+               \c false, the function has POSIX \c kill() semantics, i.e. if
+               \code id >= 0 \endcode the target is a team.
+*/
 status_t
-_user_send_signal(pid_t team, uint signal)
+_user_send_signal(int32 id, uint32 signal, bool toThread)
 {
-       return send_signal_etc(team, signal, B_CHECK_PERMISSION);
+       // If toThread == true, delegate to send_signal_etc(). Also do that when
+       // id < 0, since in this case the semantics is the same as well.
+       uint32 flags = B_CHECK_PERMISSION;
+       if (toThread || id < 0)
+               return send_signal_etc(id, signal, flags);

[... truncated: 107 lines follow ...]

Other related posts:

  • » [haiku-commits] r41560 - in haiku/branches/developer/bonefish/signals: headers/private/kernel headers/private/system src/system/kernel src/system/libroot/posix/signal - ingo_weinhold