[haiku-commits] r41793 - in haiku/branches/developer/bonefish/signals: headers/private/kernel headers/private/system src/system/kernel src/system/kernel/arch/x86 src/system/kernel/vm ...

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 28 May 2011 21:32:39 +0200 (CEST)

Author: bonefish
Date: 2011-05-28 21:32:38 +0200 (Sat, 28 May 2011)
New Revision: 41793
Changeset: https://dev.haiku-os.org/changeset/41793

Modified:
   haiku/branches/developer/bonefish/signals/headers/private/kernel/UserEvent.h
   haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h
   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/headers/private/system/user_timer_defs.h
   haiku/branches/developer/bonefish/signals/src/system/kernel/UserEvent.cpp
   haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp
   
haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_int.cpp
   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/kernel/thread.cpp
   haiku/branches/developer/bonefish/signals/src/system/kernel/vm/vm.cpp
   
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/time/timer_support.cpp
Log:
* Renamed send_signal_to_thread() to send_signal_to_thread_id(), introduced a
  new send_signal_to_thread(), which takes a Thread* argument, and made
  deliver_signal_locked() public (kernel private) and renamed it to
  send_signal_to_thread_locked().
* Pulled base class SignalEvent out of TeamSignalEvent and implemented another
  derived class ThreadSignalEvent, which sends a signal to a thread.
* Team: Added CheckAddUserDefinedTimer() and UserDefinedTimersRemoved() methods
  that atomically (check and) modify fUserDefinedTimerCount.
* Thread: Similar to Team, added fUserTimers attribute and methods to add/remove
  user timers.
* UserTimerList::AddTimer(): If the timer to be added already has an ID, keep
  that one. Allows to add pre-defined timers.
* UserTimerList::DeleteTimers(): Return the number of deleted user-defined
  timers.
* User timer syscalls:
  - Added missing const parameter modifiers.
  - Added a "thread_id thread" parameter to the timer related syscalls. If >= 0,
    it refers to the thread the timer belongs to. If < 0, it's a team timer.
  - Renamed USER_TIMER_FOR_THREAD to USER_TIMER_SIGNAL_THREAD and made use of
    it: It indicates to the user timer creation code whether a thread timer
    shall send a signal to the thread or the team.
  - Added helper class TimerLocker to simplify the team or thread timer locking.
  - _user_create_timer(): Moved creation code to helper function create_timer().
* Added user_timer_create_thread_timers() function, which creates the
  pre-defined timers for a thread. Currently only a system time based one. The
  function isn't used yet.


Modified: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserEvent.h
===================================================================
--- 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserEvent.h    
    2011-05-28 16:29:16 UTC (rev 41792)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserEvent.h    
    2011-05-28 19:32:38 UTC (rev 41793)
@@ -15,6 +15,7 @@
 
 
 struct Team;
+struct Thread;
 
 
 struct UserEvent {
@@ -24,32 +25,57 @@
 };
 
 
-struct TeamSignalEvent : UserEvent {
-       virtual                                         ~TeamSignalEvent();
+struct SignalEvent : UserEvent {
+       virtual                                         ~SignalEvent();
 
+                       void                            SetUserValue(union 
sigval userValue);
+
+protected:
+                       struct EventSignal;
+
+protected:
+                                                               
SignalEvent(EventSignal* signal);
+
+protected:
+                       EventSignal*            fSignal;
+};
+
+
+struct TeamSignalEvent : SignalEvent {
        static  TeamSignalEvent*        Create(Team* team, uint32 signalNumber,
                                                                        int32 
signalCode, int32 errorCode);
 
        virtual status_t                        Fire();
 
-                       void                            SetUserValue(union 
sigval userValue);
+private:
+                                                               
TeamSignalEvent(Team* team,
+                                                                       
EventSignal* signal);
 
 private:
-                       struct EventSignal;
+                       Team*                           fTeam;
+};
 
+
+struct ThreadSignalEvent : SignalEvent {
+       static  ThreadSignalEvent*      Create(Thread* thread, uint32 
signalNumber,
+                                                                       int32 
signalCode, int32 errorCode);
+
+       virtual status_t                        Fire();
+
 private:
-                                                               
TeamSignalEvent(Team* team,
+                                                               
ThreadSignalEvent(Thread* thread,
                                                                        
EventSignal* signal);
 
 private:
-                       Team*                           fTeam;
-                       EventSignal*            fSignal;
+                       Thread*                         fThread;
 };
 
 
 }      // namespace BKernel
 
+using BKernel::SignalEvent;
 using BKernel::TeamSignalEvent;
+using BKernel::ThreadSignalEvent;
 using BKernel::UserEvent;
 
 

Modified: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h
===================================================================
--- 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h    
    2011-05-28 16:29:16 UTC (rev 41792)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h    
    2011-05-28 19:32:38 UTC (rev 41793)
@@ -65,7 +65,7 @@
                        void                            AddTimer(UserTimer* 
timer);
                        void                            RemoveTimer(UserTimer* 
timer)
                                                                        { 
fTimers.Remove(timer); }
-                       void                            DeleteTimers(bool 
userDefinedOnly);
+                       int32                           DeleteTimers(bool 
userDefinedOnly);
 
 private:
                        typedef DoublyLinkedList<UserTimer> TimerList;
@@ -83,11 +83,15 @@
 
 __BEGIN_DECLS
 
-int32          _user_create_timer(clockid_t clockID, uint32 flags,
-                               struct sigevent* event);
-status_t       _user_delete_timer(int32 timerID);
-status_t       _user_get_timer(int32 timerID, struct user_timer_info* info);
-status_t       _user_set_timer(int32 timerID, struct user_timer_info* info,
+status_t       user_timer_create_thread_timers(Thread* thread);
+
+int32          _user_create_timer(clockid_t clockID, thread_id threadID,
+                               uint32 flags, const struct sigevent* event);
+status_t       _user_delete_timer(int32 timerID, thread_id threadID);
+status_t       _user_get_timer(int32 timerID, thread_id threadID,
+                               struct user_timer_info* info);
+status_t       _user_set_timer(int32 timerID, thread_id threadID,
+                               const struct user_timer_info* info,
                                struct user_timer_info* oldInfo);
 
 __END_DECLS

Modified: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h  
2011-05-28 16:29:16 UTC (rev 41792)
+++ haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h  
2011-05-28 19:32:38 UTC (rev 41793)
@@ -203,13 +203,19 @@
 bool is_team_signal_blocked(Team* team, int signal);
 void signal_get_user_stack(addr_t address, stack_t* stack);
 
-status_t send_signal_to_thread(thread_id threadID, const Signal& signal,
+status_t send_signal_to_thread_locked(Thread* thread, uint32 signalNumber,
+       Signal* signal, uint32 flags);
+status_t send_signal_to_thread(Thread* thread, const Signal& signal,
        uint32 flags);
+status_t send_signal_to_thread_id(thread_id threadID, const Signal& signal,
+       uint32 flags);
+
 status_t send_signal_to_team_locked(Team* team, uint32 signalNumber,
        Signal* signal, uint32 flags);
 status_t send_signal_to_team(Team* team, const Signal& signal, uint32 flags);
 status_t send_signal_to_team_id(team_id teamID, const Signal& signal,
        uint32 flags);
+
 status_t send_signal_to_process_group_locked(ProcessGroup* group,
        const Signal& signal, uint32 flags);
 status_t send_signal_to_process_group(pid_t groupID, const Signal& signal,

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-28 16:29:16 UTC (rev 41792)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 
    2011-05-28 19:32:38 UTC (rev 41793)
@@ -357,6 +357,9 @@
                        void                            
RemoveUserTimer(UserTimer* timer);
                        void                            DeleteUserTimers(bool 
userDefinedOnly);
 
+                       bool                            
CheckAddUserDefinedTimer();
+                       void                            
UserDefinedTimersRemoved(int32 count);
+
 private:
                                                                Team(bool 
kernel);
 
@@ -373,7 +376,7 @@
                                                                        // 
indexed signal - 1, protected by fLock
 
                        UserTimerList           fUserTimers;                    
// protected by fLock
-                       int32                           fUserDefinedTimerCount; 
// protected by fLock
+                       vint32                          fUserDefinedTimerCount; 
// accessed atomically
 };
 
 
@@ -513,6 +516,18 @@
 
                        status_t                        Init(bool idleThread);
 
+                       bool                            Lock()
+                                                                       { 
mutex_lock(&fLock); return true; }
+                       bool                            TryLock()
+                                                                       { 
return mutex_trylock(&fLock) == B_OK; }
+                       void                            Unlock()
+                                                                       { 
mutex_unlock(&fLock); }
+
+                       void                            
UnlockAndReleaseReference()
+                                                                       { 
Unlock(); ReleaseReference(); }
+
+                       bool                            IsAlive() const;
+
                        sigset_t                        ThreadPendingSignals() 
const
                                                                        { 
return fPendingSignals.AllSignals(); }
        inline  sigset_t                        AllPendingSignals() const;
@@ -533,23 +548,20 @@
        inline  Signal*                         DequeuePendingSignal(sigset_t 
nonBlocked,
                                                                        Signal& 
buffer);
 
-                       bool                            Lock()
-                                                                       { 
mutex_lock(&fLock); return true; }
-                       bool                            TryLock()
-                                                                       { 
return mutex_trylock(&fLock) == B_OK; }
-                       void                            Unlock()
-                                                                       { 
mutex_unlock(&fLock); }
+                       // user timers -- protected by fLock
+                       UserTimer*                      UserTimerFor(int32 id) 
const
+                                                                       { 
return fUserTimers.TimerFor(id); }
+                       status_t                        AddUserTimer(UserTimer* 
timer);
+                       void                            
RemoveUserTimer(UserTimer* timer);
+                       void                            DeleteUserTimers(bool 
userDefinedOnly);
 
-                       void                            
UnlockAndReleaseReference()
-                                                                       { 
Unlock(); ReleaseReference(); }
-
-                       bool                            IsAlive() const;
-
 private:
                        mutex                           fLock;
 
                        BKernel::PendingSignals fPendingSignals;
                                                                        // 
protected by scheduler lock
+
+                       UserTimerList           fUserTimers;                    
// protected by fLock
 };
 
 

Modified: 
haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h 
2011-05-28 16:29:16 UTC (rev 41792)
+++ haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h 
2011-05-28 19:32:38 UTC (rev 41793)
@@ -386,13 +386,13 @@
 extern bigtime_t       _kern_system_time();
 extern status_t                _kern_snooze_etc(bigtime_t time, int timebase, 
int32 flags);
 
-extern int32           _kern_create_timer(clockid_t clockID, uint32 flags,
-                                               struct sigevent* event);
-extern status_t                _kern_delete_timer(int32 timerID);
-extern status_t                _kern_get_timer(int32 timerID,
+extern int32           _kern_create_timer(clockid_t clockID, thread_id 
threadID,
+                                               uint32 flags, const struct 
sigevent* event);
+extern status_t                _kern_delete_timer(int32 timerID, thread_id 
threadID);
+extern status_t                _kern_get_timer(int32 timerID, thread_id 
threadID,
                                                struct user_timer_info* info);
-extern status_t                _kern_set_timer(int32 timerID,
-                                               struct user_timer_info* info,
+extern status_t                _kern_set_timer(int32 timerID, thread_id 
threadID,
+                                               const struct user_timer_info* 
info,
                                                struct user_timer_info* 
oldInfo);
 
 // area functions

Modified: 
haiku/branches/developer/bonefish/signals/headers/private/system/user_timer_defs.h
===================================================================
--- 
haiku/branches/developer/bonefish/signals/headers/private/system/user_timer_defs.h
  2011-05-28 16:29:16 UTC (rev 41792)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/system/user_timer_defs.h
  2011-05-28 19:32:38 UTC (rev 41793)
@@ -27,10 +27,12 @@
 #define USER_TIMER_FIRST_USER_DEFINED_ID       3
        // first ID assigned to a user-defined timer (timer_create())
 
+// _kern_create_user_timer() flag:
+#define USER_TIMER_SIGNAL_THREAD                       0x01
+       // send the signal to the thread instead of the team (valid only for 
thread
+       // timers)
 
-#define USER_TIMER_FOR_THREAD  0x01
 
-
 struct user_timer_info {
        bigtime_t       next_time;
        bigtime_t       interval;

Modified: 
haiku/branches/developer/bonefish/signals/src/system/kernel/UserEvent.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/UserEvent.cpp   
2011-05-28 16:29:16 UTC (rev 41792)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/UserEvent.cpp   
2011-05-28 19:32:38 UTC (rev 41793)
@@ -19,10 +19,10 @@
 }
 
 
-// #pragma mark - TeamSignalEvent
+// #pragma mark - SignalEvent
 
 
-struct TeamSignalEvent::EventSignal : Signal {
+struct SignalEvent::EventSignal : Signal {
        EventSignal(uint32 number, int32 signalCode, int32 errorCode,
                pid_t sendingProcess)
                :
@@ -56,20 +56,37 @@
 };
 
 
-TeamSignalEvent::TeamSignalEvent(Team* team, EventSignal* signal)
+SignalEvent::SignalEvent(EventSignal* signal)
        :
-       fTeam(team),
        fSignal(signal)
 {
 }
 
 
-TeamSignalEvent::~TeamSignalEvent()
+SignalEvent::~SignalEvent()
 {
        fSignal->ReleaseReference();
 }
 
 
+void
+SignalEvent::SetUserValue(union sigval userValue)
+{
+       fSignal->SetUserValue(userValue);
+}
+
+
+// #pragma mark - TeamSignalEvent
+
+
+TeamSignalEvent::TeamSignalEvent(Team* team, EventSignal* signal)
+       :
+       SignalEvent(signal),
+       fTeam(team)
+{
+}
+
+
 /*static*/ TeamSignalEvent*
 TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode,
        int32 errorCode)
@@ -113,8 +130,55 @@
 }
 
 
-void
-TeamSignalEvent::SetUserValue(union sigval userValue)
+// #pragma mark - ThreadSignalEvent
+
+
+ThreadSignalEvent::ThreadSignalEvent(Thread* thread, EventSignal* signal)
+       :
+       SignalEvent(signal),
+       fThread(thread)
 {
-       fSignal->SetUserValue(userValue);
 }
+
+
+/*static*/ ThreadSignalEvent*
+ThreadSignalEvent::Create(Thread* thread, uint32 signalNumber, int32 
signalCode,
+       int32 errorCode)
+{
+       // create the signal
+       EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
+               signalCode, errorCode, thread->team->id);
+       if (signal == NULL)
+               return NULL;
+
+       // create the event
+       ThreadSignalEvent* event = new ThreadSignalEvent(thread, signal);
+       if (event == NULL) {
+               delete signal;
+               return NULL;
+       }
+
+       return event;
+}
+
+
+status_t
+ThreadSignalEvent::Fire()
+{
+       // called with the scheduler lock held
+       if (fSignal->IsInUse())
+               return B_BUSY;
+
+       fSignal->AcquireReference();
+               // one reference is transferred to send_signal_to_team_locked
+       status_t error = send_signal_to_thread_locked(fThread, 
fSignal->Number(),
+               fSignal, B_DO_NOT_RESCHEDULE);
+       if (error == B_OK) {
+               // Mark the signal in-use. There are situations (for certain 
signals),
+               // in which send_signal_to_team_locked() succeeds without 
queuing the
+               // signal.
+               fSignal->SetInUse(fSignal->IsPending());
+       }
+
+       return error;
+}

Modified: 
haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp   
2011-05-28 16:29:16 UTC (rev 41792)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp   
2011-05-28 19:32:38 UTC (rev 41793)
@@ -15,6 +15,73 @@
 #include <util/AutoLock.h>
 
 
+// #pragma mark - TimerLocker
+
+
+namespace {
+
+struct TimerLocker {
+       Team*   team;
+       Thread* thread;
+
+       TimerLocker()
+               :
+               team(NULL),
+               thread(NULL)
+       {
+       }
+
+       ~TimerLocker()
+       {
+               Unlock();
+       }
+
+       status_t Lock(thread_id threadID)
+       {
+               team = thread_get_current_thread()->team;
+               team->Lock();
+
+               if (threadID >= 0) {
+                       thread = Thread::GetAndLock(threadID);
+                       if (thread == NULL)
+                               return B_BAD_THREAD_ID;
+               }
+
+               return B_OK;
+       }
+
+       status_t LockAndGetTimer(thread_id threadID, int32 timerID,
+               UserTimer*& _timer)
+       {
+               status_t error = Lock(threadID);
+               if (error != B_OK)
+                       return error;
+
+               UserTimer* timer = thread != NULL
+                       ? thread->UserTimerFor(timerID) : 
team->UserTimerFor(timerID);
+               if (timer == NULL)
+                       return B_BAD_VALUE;
+
+               _timer = timer;
+               return B_OK;
+       }
+
+       void Unlock()
+       {
+               if (thread != NULL) {
+                       thread->UnlockAndReleaseReference();
+                       thread = NULL;
+               }
+               if (team != NULL) {
+                       team->Unlock();
+                       team = NULL;
+               }
+       }
+};
+
+}      // unnamed namespace
+
+
 // #pragma mark - UserTimer
 
 
@@ -59,9 +126,6 @@
 UserTimer::Schedule(bigtime_t nextTime, bigtime_t interval,
        bigtime_t& _oldNextTime, bigtime_t& _oldInterval)
 {
-       STATIC_ASSERT(B_ONE_SHOT_RELATIVE_ALARM == B_ONE_SHOT_RELATIVE_TIMER);
-               // just to be sure no one changes the headers some day
-
        InterruptsSpinLocker schedulerLocker(gSchedulerLock);
 
        // Cancel the old timer, if still scheduled, and get the previous 
values.
@@ -210,21 +274,40 @@
 void
 UserTimerList::AddTimer(UserTimer* timer)
 {
-       // find an usused ID
-       int32 id = USER_TIMER_FIRST_USER_DEFINED_ID;
-       UserTimer* insertAfter = NULL;
-       for (TimerList::Iterator it = fTimers.GetIterator();
-                       UserTimer* other = it.Next();) {
-               if (other->ID() > id)
-                       break;
-               if (other->ID() == id)
-                       id++;
-               insertAfter = timer;
+       int32 id = timer->ID();
+       if (id < 0) {
+               // user-defined timer -- find an usused ID
+               id = USER_TIMER_FIRST_USER_DEFINED_ID;
+               UserTimer* insertAfter = NULL;
+               for (TimerList::Iterator it = fTimers.GetIterator();
+                               UserTimer* other = it.Next();) {
+                       if (other->ID() > id)
+                               break;
+                       if (other->ID() == id)
+                               id++;
+                       insertAfter = timer;
+               }
+
+               // insert the timer
+               timer->SetID(id);
+               fTimers.InsertAfter(insertAfter, timer);
+       } else {
+               // default timer -- find the insertion point
+               UserTimer* insertAfter = NULL;
+               for (TimerList::Iterator it = fTimers.GetIterator();
+                               UserTimer* other = it.Next();) {
+                       if (other->ID() > id)
+                               break;
+                       if (other->ID() == id) {
+                               panic("UserTimerList::AddTimer(): timer with ID 
%" B_PRId32
+                                       " already exists!", id);
+                       }
+                       insertAfter = timer;
+               }
+
+               // insert the timer
+               fTimers.InsertAfter(insertAfter, timer);
        }
-
-       // insert the timer
-       timer->SetID(id);
-       fTimers.InsertAfter(insertAfter, timer);
 }
 
 
@@ -232,28 +315,37 @@
 
        \param userDefinedOnly If \c true, only the user-defined timers are 
deleted,
                otherwise all timers are deleted.
+       \return The number of user-defined timers that were removed and deleted.
 */
-void
+int32
 UserTimerList::DeleteTimers(bool userDefinedOnly)
 {
+       int32 userDefinedCount = 0;
+
        for (TimerList::Iterator it = fTimers.GetIterator();
                        UserTimer* timer = it.Next();) {
-               if (userDefinedOnly && timer->ID() < 
USER_TIMER_FIRST_USER_DEFINED_ID)
-                       continue;
+               if (timer->ID() < USER_TIMER_FIRST_USER_DEFINED_ID) {
+                       if (userDefinedOnly)
+                               continue;
+               } else
+                       userDefinedCount++;
 
                // remove, cancel, and delete the timer
                it.Remove();
                timer->Cancel();
                delete timer;
        }
+
+       return userDefinedCount;
 }
 
 
-// #pragma mark - syscalls
+// #pragma mark - private
 
 
-int32
-_user_create_timer(clockid_t clockID, uint32 flags, struct sigevent* userEvent)
+static int32
+create_timer(clockid_t clockID, int32 timerID, thread_id threadID, uint32 
flags,
+       const struct sigevent& event, bool isDefaultEvent)
 {
        // we support only monotonic and real time timers
        switch (clockID) {
@@ -270,22 +362,12 @@
                return B_NO_MEMORY;
        ObjectDeleter<UserTimer> timerDeleter(timer);
 
-       // copy the sigevent structure from userland
-       struct sigevent event;
-       if (userEvent != NULL) {
-               if (!IS_USER_ADDRESS(userEvent)
-                       || user_memcpy(&event, userEvent, sizeof(event)) != 
B_OK) {
-                       return B_BAD_ADDRESS;
-               }
-       } else {
-               // none given -- use defaults
-               event.sigev_notify = SIGEV_SIGNAL;
-               event.sigev_signo = SIGALRM;
-       }
+       if (timerID >= 0)
+               timer->SetID(timerID);
 
        Team* team = thread_get_current_thread()->team;
 
-       TeamSignalEvent* signalEvent = NULL;
+       SignalEvent* signalEvent = NULL;
 
        switch (event.sigev_notify) {
                case SIGEV_NONE:
@@ -297,8 +379,21 @@
                        if (event.sigev_signo <= 0 || event.sigev_signo > 
MAX_SIGNAL_NUMBER)
                                return B_BAD_VALUE;
 
-                       signalEvent = TeamSignalEvent::Create(team, 
event.sigev_signo,
-                               SI_TIMER, 0);
+                       if (threadID >= 0 && (flags & USER_TIMER_SIGNAL_THREAD) 
!= 0) {
+                               // The signal shall be sent to the thread. Get 
it.
+                               Thread* thread = Thread::Get(threadID);
+                               if (thread == NULL)
+                                       return B_BAD_THREAD_ID;
+                               BReference<Thread> threadReference(thread, 
true);
+
+                               signalEvent = ThreadSignalEvent::Create(thread,
+                                       event.sigev_signo, SI_TIMER, 0);
+                       } else {
+                               // The signal shall be sent to the team.
+                               signalEvent = TeamSignalEvent::Create(team, 
event.sigev_signo,
+                                       SI_TIMER, 0);
+                       }
+
                        if (signalEvent == NULL)
                                return B_NO_MEMORY;
 
@@ -315,65 +410,121 @@
                        return B_BAD_VALUE;
        }
 
-       // add it to the team
-       TeamLocker teamLocker(team);
+       // add it to the team/thread
+       TimerLocker timerLocker;
+       status_t error = timerLocker.Lock(threadID);
+       if (error != B_OK)
+               return error;
 
-       status_t error = team->AddUserTimer(timer);
+       error = threadID >= 0
+               ? timerLocker.thread->AddUserTimer(timer) : 
team->AddUserTimer(timer);
        if (error != B_OK)
                return error;
 
        // set a signal event's user value
        if (signalEvent != NULL) {
                // If no sigevent structure was given, use the timer ID.
-               if (userEvent == NULL)
-                       event.sigev_value.sival_int = timer->ID();
+               union sigval signalValue = event.sigev_value;
+               if (isDefaultEvent)
+                       signalValue.sival_int = timer->ID();
 
-               signalEvent->SetUserValue(event.sigev_value);
+               signalEvent->SetUserValue(signalValue);
        }
 
        return timerDeleter.Detach()->ID();
 }
 
 
+// #pragma mark - kernel private
+
+
 status_t
-_user_delete_timer(int32 timerID)
+user_timer_create_thread_timers(Thread* thread)
 {
+       // create a real time user timer
+       struct sigevent event;
+       event.sigev_notify = SIGEV_SIGNAL;
+       event.sigev_signo = SIGALRM;
+
+       int32 timerID = create_timer(CLOCK_MONOTONIC, USER_TIMER_REAL_TIME_ID,
+               thread->id, USER_TIMER_SIGNAL_THREAD, event, true);
+       if (timerID < 0)
+               return timerID;
+
+       return B_OK;
+}
+
+
+// #pragma mark - syscalls
+
+
+int32
+_user_create_timer(clockid_t clockID, thread_id threadID, uint32 flags,
+       const struct sigevent* userEvent)
+{
+       // copy the sigevent structure from userland
+       struct sigevent event;
+       if (userEvent != NULL) {
+               if (!IS_USER_ADDRESS(userEvent)
+                       || user_memcpy(&event, userEvent, sizeof(event)) != 
B_OK) {
+                       return B_BAD_ADDRESS;
+               }
+       } else {
+               // none given -- use defaults
+               event.sigev_notify = SIGEV_SIGNAL;
+               event.sigev_signo = SIGALRM;
+       }
+
+       // create the timer
+       return create_timer(clockID, -1, threadID, flags, event, userEvent == 
NULL);
+}
+
+
+status_t
+_user_delete_timer(int32 timerID, thread_id threadID)
+{
        // can only delete user-defined timers
        if (timerID < USER_TIMER_FIRST_USER_DEFINED_ID)
                return B_BAD_VALUE;
 
        // get the timer
-       Team* team = thread_get_current_thread()->team;
-       TeamLocker teamLocker(team);
+       TimerLocker timerLocker;
+       UserTimer* timer;
+       status_t error = timerLocker.LockAndGetTimer(threadID, timerID, timer);
+       if (error != B_OK)
+               return error;
 
-       UserTimer* timer = team->UserTimerFor(timerID);
-       if (timer == NULL)
-               return B_BAD_VALUE;
-
+       // cancel, remove, and delete it
        timer->Cancel();
 
-       // remove and delete it
-       team->RemoveUserTimer(timer);
+       if (threadID >= 0)
+               timerLocker.thread->RemoveUserTimer(timer);
+       else
+               timerLocker.team->RemoveUserTimer(timer);
 
+       delete timer;
+
        return B_OK;
 }
 
 
 status_t
-_user_get_timer(int32 timerID, struct user_timer_info* userInfo)
+_user_get_timer(int32 timerID, thread_id threadID,
+       struct user_timer_info* userInfo)
 {
        // get the timer
-       Team* team = thread_get_current_thread()->team;
-       TeamLocker teamLocker(team);
+       TimerLocker timerLocker;
+       UserTimer* timer;
+       status_t error = timerLocker.LockAndGetTimer(threadID, timerID, timer);
+       if (error != B_OK)
+               return error;
 
-       UserTimer* timer = team->UserTimerFor(timerID);
-       if (timer == NULL)
-               return B_BAD_VALUE;
-
        // get the info
        user_timer_info info;
        timer->GetInfo(info.next_time, info.interval, info.overrun_count);
 
+       timerLocker.Unlock();
+
        // copy it back to userland
        if (userInfo != NULL
                && (!IS_USER_ADDRESS(userInfo)
@@ -386,8 +537,8 @@
 
 
 status_t
-_user_set_timer(int32 timerID, struct user_timer_info* userInfo,
-       struct user_timer_info* userOldInfo)
+_user_set_timer(int32 timerID, thread_id threadID,
+       const struct user_timer_info* userInfo, struct user_timer_info* 
userOldInfo)
 {
        // copy info to userland
        user_timer_info info;
@@ -401,18 +552,19 @@
                return B_BAD_VALUE;
 
        // get the timer
-       Team* team = thread_get_current_thread()->team;
-       TeamLocker teamLocker(team);
+       TimerLocker timerLocker;
+       UserTimer* timer;
+       status_t error = timerLocker.LockAndGetTimer(threadID, timerID, timer);
+       if (error != B_OK)
+               return error;
 
-       UserTimer* timer = team->UserTimerFor(timerID);
-       if (timer == NULL)
-               return B_BAD_VALUE;
-
        // schedule the timer
        user_timer_info oldInfo;
        timer->Schedule(info.next_time, info.interval, oldInfo.next_time,
                oldInfo.interval);
 
+       timerLocker.Unlock();
+
        // copy back the old info
        if (userOldInfo != NULL
                && (!IS_USER_ADDRESS(userOldInfo)

Modified: 
haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_int.cpp
===================================================================
--- 
haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_int.cpp
   2011-05-28 16:29:16 UTC (rev 41792)
+++ 
haiku/branches/developer/bonefish/signals/src/system/kernel/arch/x86/arch_int.cpp
   2011-05-28 19:32:38 UTC (rev 41793)
@@ -873,7 +873,7 @@
                        Signal signal(signalNumber, signalCode, signalError,
                                thread->team->id);
                        signal.SetAddress((void*)signalAddress);
-                       send_signal_to_thread(thread->id, signal, 0);
+                       send_signal_to_thread(thread, signal, 0);
                }
        } else {
                char name[32];

Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp      
2011-05-28 16:29:16 UTC (rev 41792)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp      
2011-05-28 19:32:38 UTC (rev 41793)
@@ -1170,7 +1170,7 @@
                                                if (thread != 
team->main_thread) {
                                                        Signal 
childSignal(SIGKILLTHR, SI_USER, B_OK,
                                                                team->id);
-                                                       
send_signal_to_thread(team->id, childSignal, 0);
+                                                       
send_signal_to_thread_id(team->id, childSignal, 0);
                                                }
                                        }
 
@@ -1343,9 +1343,9 @@
        \return \c B_OK, when the signal was delivered successfully, another 
error
                code otherwise.
 */
-static status_t
-deliver_signal_locked(Thread* thread, uint32 signalNumber, Signal* signal,
-       uint32 flags)
+status_t
+send_signal_to_thread_locked(Thread* thread, uint32 signalNumber,
+       Signal* signal, uint32 flags)
 {
        ASSERT(signal == NULL || signalNumber == signal->Number());
 
@@ -1443,11 +1443,11 @@
 }
 
 
-/*!    Sends the given signal to the thread with the given ID.
+/*!    Sends the given signal to the given thread.
 
-       The caller must not hold the thread's lock.
+       The caller must not hold the scheduler lock.
 
-       \param threadID The ID of the thread the signal shall be sent to.
+       \param thread The thread the signal shall be sent to.
        \param signal The signal to be delivered. If the signal's number is \c 
0, no
                actual signal will be delivered. Only delivery checks will be 
performed.
                The given object will be copied. The caller retains ownership.
@@ -1462,13 +1462,8 @@
                code otherwise.
 */
 status_t
-send_signal_to_thread(thread_id threadID, const Signal& signal, uint32 flags)
+send_signal_to_thread(Thread* thread, const Signal& signal, uint32 flags)
 {
-       Thread* thread = Thread::Get(threadID);
-       if (thread == NULL)
-               return B_BAD_THREAD_ID;
-       BReference<Thread> threadReference(thread, true);
-
        // Clone the signal -- the clone will be queued. If something fails and 
the
        // caller doesn't require queuing, we will add an unqueued signal.
        Signal* signalToQueue = NULL;
@@ -1479,7 +1474,7 @@
 
        InterruptsSpinLocker schedulerLocker(gSchedulerLock);
 
-       error = deliver_signal_locked(thread, signal.Number(), signalToQueue,
+       error = send_signal_to_thread_locked(thread, signal.Number(), 
signalToQueue,
                flags);
        if (error != B_OK)
                return error;
@@ -1491,6 +1486,36 @@
 }
 
 
+/*!    Sends the given signal to the thread with the given ID.
+
+       The caller must not hold the scheduler lock.
+
+       \param threadID The ID of the thread the signal shall be sent to.
+       \param signal The signal to be delivered. If the signal's number is \c 
0, no
+               actual signal will be delivered. Only delivery checks will be 
performed.
+               The given object will be copied. The caller retains ownership.
+       \param flags A bitwise combination of any number of the following:
+               - \c B_CHECK_PERMISSION: Check the caller's permission to send 
the
+                       target thread the signal.
+               - \c B_DO_NOT_RESCHEDULE: If clear and a higher level thread 
has been
+                       woken up, the scheduler will be invoked. If set that 
will not be
+                       done explicitly, but rescheduling can still happen, 
e.g. when the
+                       current thread's time slice runs out.
+       \return \c B_OK, when the signal was delivered successfully, another 
error
+               code otherwise.
+*/
+status_t
+send_signal_to_thread_id(thread_id threadID, const Signal& signal, uint32 
flags)
+{
+       Thread* thread = Thread::Get(threadID);
+       if (thread == NULL)
+               return B_BAD_THREAD_ID;
+       BReference<Thread> threadReference(thread, true);
+
+       return send_signal_to_thread(thread, signal, flags);
+}
+
+
 /*!    Sends the given signal to the given team.
 
        The caller must hold the scheduler lock.
@@ -1796,11 +1821,11 @@
 
        // If id is > 0, send the signal to the respective thread.
        if (id > 0)
-               return send_signal_to_thread(id, signal, flags);
+               return send_signal_to_thread_id(id, signal, flags);
 
        // If id == 0, send the signal to the current thread.
        if (id == 0)
-               return send_signal_to_thread(thread->id, signal, flags);
+               return send_signal_to_thread(thread, signal, flags);
 
        // If id == -1, send the signal to all teams the calling team has 
permission
        // to send signals to.
@@ -1945,7 +1970,7 @@
        Thread* thread = (Thread*)t->user_data;
 
        TRACE(("alarm_event: thread = %p\n", thread));
-       deliver_signal_locked(thread, SIGALRM, NULL, B_DO_NOT_RESCHEDULE);
+       send_signal_to_thread_locked(thread, SIGALRM, NULL, 
B_DO_NOT_RESCHEDULE);
                // TODO: Support queuing! Could be done by pre-allocating a 
Signal
                // subclass in set_alarm().
 

Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp        
2011-05-28 16:29:16 UTC (rev 41792)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/team.cpp        
2011-05-28 19:32:38 UTC (rev 41793)
@@ -804,27 +804,29 @@
 }
 
 
-/*!    Adds the given user timer to the team and assigns it an ID.
+/*!    Adds the given user timer to the team and, if user-defined, assigns it 
an
+       ID.
 
        The caller must hold the team's lock.
 
-       \param timer The timer to be added.
+       \param timer The timer to be added. If it doesn't have an ID yet, it is
+               considered user-defined and will be assigned an ID.
        \return \c B_OK, if the timer was added successfully, another error code
                otherwise.
 */
 status_t
 Team::AddUserTimer(UserTimer* timer)
 {
-       // check timer limit
-       if (fUserDefinedTimerCount >= MAX_USER_TIMERS_PER_TEAM)
-               return EAGAIN;
-
        // don't allow addition of timers when already shutting the team down
        if (state >= TEAM_STATE_SHUTDOWN)
                return B_BAD_TEAM_ID;
 
+       // If the timer is user-defined, check timer limit and increment
+       // user-defined count.
+       if (timer->ID() < 0 && !CheckAddUserDefinedTimer())
+               return EAGAIN;
+
        fUserTimers.AddTimer(timer);
-       fUserDefinedTimerCount++;
 
        return B_OK;
 }
@@ -841,12 +843,15 @@
 Team::RemoveUserTimer(UserTimer* timer)
 {
        fUserTimers.RemoveTimer(timer);
-       fUserDefinedTimerCount--;
+
+       if (timer->ID() >= USER_TIMER_FIRST_USER_DEFINED_ID)
+               UserDefinedTimersRemoved(1);
 }
 
 
-/*!    Deletes all (or all user-defined) user timers.
+/*!    Deletes all (or all user-defined) user timers of the team.
 
+       Timer's belonging to the team's threads are not affected.
        The caller must hold the team's lock.
 
        \param userDefinedOnly If \c true, only the user-defined timers are 
deleted,
@@ -855,11 +860,37 @@
 void
 Team::DeleteUserTimers(bool userDefinedOnly)
 {
-       fUserTimers.DeleteTimers(userDefinedOnly);

[... truncated: 321 lines follow ...]

Other related posts:

  • » [haiku-commits] r41793 - in haiku/branches/developer/bonefish/signals: headers/private/kernel headers/private/system src/system/kernel src/system/kernel/arch/x86 src/system/kernel/vm ... - ingo_weinhold