[haiku-commits] r41508 - in haiku/branches/developer/bonefish/signals: headers/private/kernel src/system/kernel

Author: bonefish
Date: 2011-05-15 03:00:48 +0200 (Sun, 15 May 2011)
New Revision: 41508
Changeset: https://dev.haiku-os.org/changeset/41508

Modified:
   haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h
   haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp
Log:
Work towards support for queued signals:
* Added new class Signal, instances of which represent queued signals. Currently
  the only data member is the signal number. Later it will contain all data
  associate with the signal.
* Rewrote most of PendingSignals:
  - It does now store queued and unqueued signals. The queued ones are,
    obviously, stored in a queue. The unqueued ones in a mask.
  - Added methods to get the signals' highest priority and to dequeue the signal
    with the highest priority. Not used yet.


Modified: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h  
2011-05-15 00:37:59 UTC (rev 41507)
+++ haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h  
2011-05-15 01:00:48 UTC (rev 41508)
@@ -5,11 +5,16 @@
 #ifndef _KERNEL_SIGNAL_H
 #define _KERNEL_SIGNAL_H
 
+#include <signal.h>
 
 #include <KernelExport.h>
-#include <signal.h>
 
+#include <Referenceable.h>
 
+#include <heap.h>
+#include <util/DoublyLinkedList.h>
+
+
 namespace BKernel {
        struct ProcessGroup;
        struct Team;
@@ -32,29 +37,69 @@
 namespace BKernel {
 
 
+struct Signal : BReferenceable, DeferredDeletable,
+       DoublyLinkedListLinkImpl<Signal> {
+public:
+                                                               Signal(int32 
number) : fNumber(number) {}
+
+                       void                            SetTo(int32 number)
+                                                                       { 
fNumber = number; }
+
+                       int32                           Number() const { return 
fNumber; }
+                       int32                           Priority() const;
+
+protected:
+       virtual void                            LastReferenceReleased();
+
+private:
+                       int                                     fNumber;
+};
+
+
 struct PendingSignals {
-                                                               
PendingSignals() : fAllMask(0) {}
-                                                               
~PendingSignals() {}
+                                                               
PendingSignals();
+                                                               
~PendingSignals();
 
-                       sigset_t                        AllSignals() const      
{ return fAllMask; }
+                       sigset_t                        AllSignals() const
+                                                                       { 
return fQueuedSignalsMask
+                                                                               
| fUnqueuedSignalsMask; }
 
-                       void                            Clear()
-                                                                       { 
fAllMask = 0; }
-                       void                            AddSignal(int signal)
-                                                                       { 
fAllMask |= SIGNAL_TO_MASK(signal); }
-                       void                            RemoveSignal(int signal)
+                       int32                           
HighestSignalPriority(sigset_t blocked) const;
+
+                       void                            Clear();
+                       void                            AddSignal(int32 signal)
+                                                                       { 
fUnqueuedSignalsMask
+                                                                               
|= SIGNAL_TO_MASK(signal); }
+                       void                            AddSignal(Signal* 
signal);
+                       void                            RemoveSignal(int32 
signal)
                                                                        { 
RemoveSignals(SIGNAL_TO_MASK(signal)); }
-                       void                            RemoveSignals(sigset_t 
mask)
-                                                                       { 
fAllMask &= ~mask; }
+                       void                            RemoveSignals(sigset_t 
mask);
 
+                       Signal*                         DequeueSignal(sigset_t 
blocked, Signal& buffer);
+
 private:
-                       sigset_t                        fAllMask;
+                       typedef DoublyLinkedList<Signal> SignalList;
+
+private:
+                       int32                           
_GetHighestPrioritySignal(sigset_t blocked,
+                                                                       
Signal*& _queuedSignal,
+                                                                       int32& 
_unqueuedSignal) const;
+                       void                            
_UpdateQueuedSignalMask();
+
+private:
+                       sigset_t                        fQueuedSignalsMask;
+                       sigset_t                        fUnqueuedSignalsMask;
+                       SignalList                      fQueuedSignals;
 };
 
 
 }      // namespace BKernel
 
 
+using BKernel::PendingSignals;
+using BKernel::Signal;
+
+
 #ifdef __cplusplus
 extern "C" {
 #endif

Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp      
2011-05-15 00:37:59 UTC (rev 41507)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp      
2011-05-15 01:00:48 UTC (rev 41508)
@@ -56,17 +56,268 @@
        | SIGNAL_TO_MASK(SIGSEGV))
 
 
-const char * const sigstr[NSIG] = {
-       "NONE", "HUP", "INT", "QUIT", "ILL", "CHLD", "ABRT", "PIPE",
-       "FPE", "KILL", "STOP", "SEGV", "CONT", "TSTP", "ALRM", "TERM",
-       "TTIN", "TTOU", "USR1", "USR2", "WINCH", "KILLTHR", "TRAP",
-       "POLL", "PROF", "SYS", "URG", "VTALRM", "XCPU", "XFSZ"
+static const struct {
+       const char*     name;
+       int32           priority;
+} kSignalInfos[] = {
+       {"NONE",        -1},
+       {"HUP",         0},
+       {"INT",         0},
+       {"QUIT",        0},
+       {"ILL",         0},
+       {"CHLD",        0},
+       {"ABRT",        0},
+       {"PIPE",        0},
+       {"FPE",         0},
+       {"KILL",        100},
+       {"STOP",        0},
+       {"SEGV",        0},
+       {"CONT",        0},
+       {"TSTP",        0},
+       {"ALRM",        0},
+       {"TERM",        0},
+       {"TTIN",        0},
+       {"TTOU",        0},
+       {"USR1",        0},
+       {"USR2",        0},
+       {"WINCH",       0},
+       {"KILLTHR",     100},
+       {"TRAP",        0},
+       {"POLL",        0},
+       {"PROF",        0},
+       {"SYS",         0},
+       {"URG",         0},
+       {"VTALRM",      0},
+       {"XCPU",        0},
+       {"XFSZ",        0}
 };
 
 
 static status_t deliver_signal(Thread *thread, uint signal, uint32 flags);
 
 
+// #pragma mark - Signal
+
+
+int32
+Signal::Priority() const
+{
+       return kSignalInfos[fNumber].priority;
+}
+
+
+void
+Signal::LastReferenceReleased()
+{
+       if (are_interrupts_enabled())
+               delete this;
+       else
+               deferred_delete(this);
+}
+
+
+// #pragma mark - PendingSignals
+
+
+PendingSignals::PendingSignals()
+       :
+       fQueuedSignalsMask(0),
+       fUnqueuedSignalsMask(0)
+{
+}
+
+
+PendingSignals::~PendingSignals()
+{
+       Clear();
+}
+
+
+/*!    Of the signals not it \a blocked returns the priority of that with the
+       highest priority.
+       \param blocked The mask with the 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
+{
+       Signal* queuedSignal;
+       int32 unqueuedSignal;
+       return _GetHighestPrioritySignal(blocked, queuedSignal, unqueuedSignal);
+}
+
+
+void
+PendingSignals::Clear()
+{
+       // release references of all queued signals
+       while (Signal* signal = fQueuedSignals.RemoveHead())
+               signal->ReleaseReference();
+
+       fQueuedSignalsMask = 0;
+       fUnqueuedSignalsMask = 0;
+}
+
+
+/*!    Adds a signal.
+       Takes over the reference to the signal from the caller.
+*/
+void
+PendingSignals::AddSignal(Signal* signal)
+{
+       // queue according to priority
+       int32 priority = signal->Priority();
+       Signal* otherSignal = NULL;
+       for (SignalList::Iterator it = fQueuedSignals.GetIterator();
+                       (otherSignal = it.Next()) != NULL;) {
+               if (priority > otherSignal->Priority())
+                       break;
+       }
+
+       fQueuedSignals.InsertBefore(otherSignal, signal);
+
+       fQueuedSignalsMask |= SIGNAL_TO_MASK(signal->Number());
+}
+
+
+void
+PendingSignals::RemoveSignals(sigset_t mask)
+{
+       // remove from queued signals
+       if ((fQueuedSignalsMask & mask) != 0) {
+               for (SignalList::Iterator it = fQueuedSignals.GetIterator();
+                               Signal* signal = it.Next();) {
+                       // remove signal, if in mask
+                       if ((SIGNAL_TO_MASK(signal->Number()) & mask) != 0) {
+                               it.Remove();
+                               signal->ReleaseReference();
+                       }
+               }
+
+               fQueuedSignalsMask &= ~mask;
+       }
+
+       // remove from unqueued signals
+       fUnqueuedSignalsMask &= ~mask;
+}
+
+
+/*!    Removes and returns a signal not in \a blocked that has the highest
+       priority.
+       The caller gets a reference to the returned signal, if any.
+       \param blocked The mask of 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)
+{
+       // find the signal with the highest priority
+       Signal* queuedSignal;
+       int32 unqueuedSignal;
+       if (_GetHighestPrioritySignal(blocked, queuedSignal, unqueuedSignal) < 
0)
+               return NULL;
+
+       // if it is a queued signal, dequeue it
+       if (queuedSignal != NULL) {
+               fQueuedSignals.Remove(queuedSignal);
+               _UpdateQueuedSignalMask();
+               return queuedSignal;
+       }
+
+       // it is unqueued -- remove from mask
+       fUnqueuedSignalsMask &= ~SIGNAL_TO_MASK(unqueuedSignal);
+
+       // init buffer
+       buffer.SetTo(unqueuedSignal);
+       buffer.AcquireReference();
+       return &buffer;
+}
+
+
+/*!    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 _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
+               variable is set to that signal's number, otherwise to \c -1.
+       \return The priority of the highest priority non-blocked signal, or, if 
all
+               signals are blocked, \c -1.
+*/
+int32
+PendingSignals::_GetHighestPrioritySignal(sigset_t blocked,
+       Signal*& _queuedSignal, int32& _unqueuedSignal) const
+{
+       sigset_t nonBlocked = ~blocked;
+
+       // check queued signals
+       Signal* queuedSignal = NULL;
+       int32 queuedPriority = -1;
+
+       if ((fQueuedSignalsMask & nonBlocked) != 0) {
+               for (SignalList::ConstIterator it = 
fQueuedSignals.GetIterator();
+                               Signal* signal = it.Next();) {
+                       if ((SIGNAL_TO_MASK(signal->Number()) & nonBlocked) != 
0) {
+                               queuedPriority = signal->Priority();
+                               queuedSignal = signal;
+                               break;
+                       }
+               }
+       }
+
+       // check unqueued signals
+       int32 unqueuedSignal = -1;
+       int32 unqueuedPriority = -1;
+
+       sigset_t unqueuedSignals = fUnqueuedSignalsMask & nonBlocked;
+       if (unqueuedSignals != 0) {
+               int32 signal = 1;
+               while (unqueuedSignals != 0) {
+                       sigset_t mask = SIGNAL_TO_MASK(signal);
+                       if ((unqueuedSignals & mask) != 0) {
+                               int32 priority = kSignalInfos[signal].priority;
+                               if (priority > unqueuedPriority) {
+                                       unqueuedSignal = signal;
+                                       unqueuedPriority = priority;
+                               }
+                               unqueuedSignals &= ~mask;
+                       }
+
+                       signal++;
+               }
+       }
+
+       // Return found queued or unqueued signal, whichever has the higher
+       // priority.
+       if (queuedPriority >= unqueuedPriority) {
+               _queuedSignal = queuedSignal;
+               _unqueuedSignal = -1;
+               return queuedPriority;
+       }
+
+       _queuedSignal = NULL;
+       _unqueuedSignal = unqueuedSignal;
+       return queuedPriority;
+}
+
+
+void
+PendingSignals::_UpdateQueuedSignalMask()
+{
+       sigset_t mask = 0;
+       for (SignalList::Iterator it = fQueuedSignals.GetIterator();
+                       Signal* signal = it.Next();) {
+               mask |= SIGNAL_TO_MASK(signal->Number());
+       }
+
+       fQueuedSignalsMask = mask;
+}
+
+
 // #pragma mark - signal tracing
 
 
@@ -131,7 +382,8 @@
                {
                        out.Print("signal send: target: %ld, signal: %lu (%s), "
                                "flags: 0x%lx", fTarget, fSignal,
-                               (fSignal < NSIG ? sigstr[fSignal] : "invalid"), 
fFlags);
+                               fSignal < NSIG ? kSignalInfos[fSignal].name : 
"invalid",
+                               fFlags);
                }
 
        private:
@@ -157,7 +409,7 @@
                        out.Print("signal action: thread: %ld, signal: %lu 
(%s), "
                                "action: {handler: %p, flags: 0x%x, mask: 
0x%lx}",
                                fThread, fSignal,
-                               (fSignal < NSIG ? sigstr[fSignal] : "invalid"),
+                               fSignal < NSIG ? kSignalInfos[fSignal].name : 
"invalid",
                                fAction.sa_handler, fAction.sa_flags, 
fAction.sa_mask);
                }
 
@@ -398,7 +650,8 @@
                debugSignal = !(~atomic_get(&thread->team->debug_info.flags)
                                & (B_TEAM_DEBUG_SIGNALS | 
B_TEAM_DEBUG_DEBUGGER_INSTALLED));
 
-               TRACE(("Thread 0x%lx received signal %s\n", thread->id, 
sigstr[signal]));
+               TRACE(("Thread 0x%lx received signal %s\n", thread->id,
+                       kSignalInfos[signal].name));
 
                if (handler.sa_handler == SIG_IGN) {
                        // signal is to be ignored


Other related posts:

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