[haiku-commits] r41787 - in haiku/branches/developer/bonefish/signals: headers/posix headers/posix/sys headers/private/kernel headers/private/system src/system/kernel ...

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sat, 28 May 2011 01:47:04 +0200 (CEST)

Author: bonefish
Date: 2011-05-28 01:47:02 +0200 (Sat, 28 May 2011)
New Revision: 41787
Changeset: https://dev.haiku-os.org/changeset/41787

Added:
   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/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
Modified:
   haiku/branches/developer/bonefish/signals/headers/posix/limits.h
   haiku/branches/developer/bonefish/signals/headers/posix/sys/types.h
   haiku/branches/developer/bonefish/signals/headers/posix/unistd.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/src/system/kernel/Jamfile
   haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp
   haiku/branches/developer/bonefish/signals/src/system/kernel/syscalls.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/libroot/posix/time/Jamfile
   
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/time/timer_support.cpp
   
haiku/branches/developer/bonefish/signals/src/system/libroot/posix/unistd/conf.c
Log:
Kernel:
* Renamed send_signal_to_team() to send_signal_to_team_id().
* Renamed send_signal_to_team_locked() to send_signal_to_team() and dropped the
  requirement that the team be locked.
* Introduced a send_signal_to_team_locked() that requires the scheduler lock to
  be held. It works analogously to deliver_signal_locked(), just for the team.
  This makes it possible to send team signals when already holding the scheduler
  lock.
* Signal:
  - Added fPending flag plus accessor methods. It is maintained by
    PendingSignals (on addition/removal).
  - Added virtual method Handled() whose base class implementation only invokes
    ReleaseReference(). It allows derived classes to e.g. recycle resources.
    Added SignalHandledCaller helper class to replace BReference's job in
    certain cases.
* Introduced class UserEvent, a base class for classes representing a method to
  deliver an event to userland. Currently the only implementation is
  TeamSignalEvent, which sends a signal to a team.
* Introduced class UserTimer, which represents a timer for a userland team (or,
  later, thread). Added methods to Team to maintain a list of UserTimers.
* Added syscalls to create, delete, set, get user timers.

Headers/libroot:
* Move _POSIX_* macros erroneously added to <unistd.h> to <limits.h>.
* Changed timer_t type to a pointer, so that we can hold a bit of data in
  userland. This also leaves us the option to e.g. use userland-kernel shared
  memory for optimizations.
* Implemented the POSIX timer_*() functions. Not quite complete yet (e.g.
  SIGEV_THREAD support is missing) and mostly untested.


Modified: haiku/branches/developer/bonefish/signals/headers/posix/limits.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/posix/limits.h    
2011-05-27 23:37:10 UTC (rev 41786)
+++ haiku/branches/developer/bonefish/signals/headers/posix/limits.h    
2011-05-27 23:47:02 UTC (rev 41787)
@@ -71,6 +71,12 @@
 #define _POSIX_STREAM_MAX      (8)
 #define _POSIX_TTY_NAME_MAX            (256)
 #define _POSIX_TZNAME_MAX      (3)
+#define _POSIX_SEM_VALUE_MAX   INT_MAX
+#define        _POSIX_SIGQUEUE_MAX             32
+#define _POSIX_RTSIG_MAX               8
+#define _POSIX_CLOCKRES_MIN            20000000
+#define _POSIX_TIMER_MAX               32
+#define _POSIX_DELAYTIMER_MAX  32
 
 #define _POSIX2_LINE_MAX               (2048)
 

Modified: haiku/branches/developer/bonefish/signals/headers/posix/sys/types.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/posix/sys/types.h 
2011-05-27 23:37:10 UTC (rev 41786)
+++ haiku/branches/developer/bonefish/signals/headers/posix/sys/types.h 
2011-05-27 23:47:02 UTC (rev 41787)
@@ -53,7 +53,7 @@
 typedef __haiku_int32          key_t;
 
 typedef __haiku_std_int32      clockid_t;
-typedef __haiku_std_int32      timer_t;
+typedef struct __timer_t*      timer_t;
 
 
 /* pthread types */

Modified: haiku/branches/developer/bonefish/signals/headers/posix/unistd.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/posix/unistd.h    
2011-05-27 23:37:10 UTC (rev 41786)
+++ haiku/branches/developer/bonefish/signals/headers/posix/unistd.h    
2011-05-27 23:47:02 UTC (rev 41787)
@@ -47,11 +47,8 @@
 #define _POSIX_THREAD_PRIORITY_SCHEDULING      (-1)    /* currently 
unsupported */
 #define _POSIX_REALTIME_SIGNALS                                (200809L)
 #define _POSIX_MEMORY_PROTECTION                       (200809L)
-#define _POSIX_SEM_VALUE_MAX                           INT_MAX
-#define        _POSIX_SIGQUEUE_MAX                                     32
-#define _POSIX_RTSIG_MAX                                       8
 #define _POSIX_MONOTONIC_CLOCK                         (200809L)
-#define _POSIX_CLOCKRES_MIN                                    20000000
+#define _POSIX_TIMERS                                          (200809L)
 
 
 /* pathconf() constants */
@@ -127,6 +124,9 @@
 #define _SC_SIGQUEUE_MAX                               53
 #define _SC_RTSIG_MAX                                  54
 #define _SC_MONOTONIC_CLOCK                            55
+#define _SC_DELAYTIMER_MAX                             56
+#define _SC_TIMER_MAX                                  57
+#define        _SC_TIMERS                                              58
 
 
 /* confstr() constants */

Added: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserEvent.h
===================================================================
--- 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserEvent.h    
                            (rev 0)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserEvent.h    
    2011-05-27 23:47:02 UTC (rev 41787)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_USER_EVENT_H
+#define _KERNEL_USER_EVENT_H
+
+
+#include <signal.h>
+
+#include <SupportDefs.h>
+
+
+namespace BKernel {
+
+
+struct Team;
+
+
+struct UserEvent {
+       virtual                                         ~UserEvent();
+
+       virtual status_t                        Fire() = 0;
+};
+
+
+struct TeamSignalEvent : UserEvent {
+       virtual                                         ~TeamSignalEvent();
+
+       static  TeamSignalEvent*        Create(Team* team, uint32 signalNumber,
+                                                                       int32 
signalCode, int32 errorCode);
+
+       virtual status_t                        Fire();
+
+                       void                            SetUserValue(union 
sigval userValue);
+
+private:
+                       struct EventSignal;
+
+private:
+                                                               
TeamSignalEvent(Team* team,
+                                                                       
EventSignal* signal);
+
+private:
+                       Team*                           fTeam;
+                       EventSignal*            fSignal;
+};
+
+
+}      // namespace BKernel
+
+using BKernel::TeamSignalEvent;
+using BKernel::UserEvent;
+
+
+#endif // _KERNEL_USER_EVENT_H

Added: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h
===================================================================
--- 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h    
                            (rev 0)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/kernel/UserTimer.h    
    2011-05-27 23:47:02 UTC (rev 41787)
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_USER_TIMER_H
+#define _KERNEL_USER_TIMER_H
+
+
+#include <sys/cdefs.h>
+#include <time.h>
+
+#include <util/DoublyLinkedList.h>
+
+#include <ksignal.h>
+#include <timer.h>
+#include <user_timer_defs.h>
+
+
+namespace BKernel {
+
+
+struct UserEvent;
+struct Team;
+
+
+struct UserTimer : DoublyLinkedListLinkImpl<UserTimer> {
+                                                               UserTimer();
+                                                               ~UserTimer();
+
+                       int32                           ID() const
+                                                                       { 
return fID; }
+                       void                            SetID(int32 id)
+                                                                       { fID = 
id; }
+
+                       void                            SetEvent(UserEvent* 
event)
+                                                                       { 
fEvent = event; }
+
+                       void                            Schedule(bigtime_t 
nextTime, bigtime_t interval,
+                                                                       
bigtime_t& _oldNextTime,
+                                                                       
bigtime_t& _oldInterval);
+                       void                            Cancel();
+
+                       void                            GetInfo(bigtime_t& 
_oldNextTime,
+                                                                       
bigtime_t& _oldInterval,
+                                                                       uint32& 
_overrunCount);
+
+private:
+       static  int32                           _HandleTimerHook(struct timer* 
timer);
+                       void                            _HandleTimer();
+
+private:
+                       int32                           fID;
+                       timer                           fTimer;
+                       UserEvent*                      fEvent;
+                       uint32                          fOverrunCount;
+                       bool                            fScheduled;
+};
+
+typedef DoublyLinkedList<UserTimer> UserTimerList;
+
+
+}      // namespace BKernel
+
+using BKernel::UserTimer;
+using BKernel::UserTimerList;
+
+
+__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,
+                               struct user_timer_info* oldInfo);
+
+__END_DECLS
+
+
+#endif // _KERNEL_USER_TIMER_H

Modified: 
haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h  
2011-05-27 23:37:10 UTC (rev 41786)
+++ haiku/branches/developer/bonefish/signals/headers/private/kernel/ksignal.h  
2011-05-27 23:47:02 UTC (rev 41787)
@@ -121,6 +121,13 @@
                        void                            SetUserValue(union 
sigval userValue)
                                                                        { 
fUserValue = userValue; }
 
+                       bool                            IsPending() const
+                                                                       { 
return fPending; }
+                       void                            SetPending(bool pending)
+                                                                       { 
fPending = pending; }
+
+       virtual void                            Handled();
+
 protected:
        virtual void                            LastReferenceReleased();
 
@@ -136,6 +143,7 @@
                        int32                           fPollBand;      // for 
SIGPOLL
                        void*                           fAddress;
                        union sigval            fUserValue;
+                       bool                            fPending;
 };
 
 
@@ -197,10 +205,11 @@
 
 status_t send_signal_to_thread(thread_id threadID, const Signal& signal,
        uint32 flags);
-status_t send_signal_to_team_locked(Team* team, const Signal& signal,
+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_team(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-27 23:37:10 UTC (rev 41786)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/kernel/thread_types.h 
    2011-05-27 23:47:02 UTC (rev 41787)
@@ -22,6 +22,7 @@
 #include <smp.h>
 #include <thread_defs.h>
 #include <timer.h>
+#include <UserTimer.h>
 #include <user_debugger.h>
 #include <util/DoublyLinkedList.h>
 #include <util/list.h>
@@ -349,6 +350,11 @@
                                                                        { 
return fSignalActions[signal - 1]; }
                        void                            
InheritSignalActions(Team* parent);
 
+                       UserTimer*                      UserTimerFor(int32 id) 
const;
+                       status_t                        AddUserTimer(UserTimer* 
timer);
+                       void                            
RemoveUserTimer(UserTimer* timer);
+                       void                            DeleteUserTimers(bool 
userDefinedOnly);
+
 private:
                                                                Team(bool 
kernel);
 
@@ -363,6 +369,9 @@
                                                                        // 
protected by scheduler lock
                        struct sigaction        
fSignalActions[MAX_SIGNAL_NUMBER];
                                                                        // 
indexed signal - 1, protected by fLock
+
+                       UserTimerList           fUserTimers;    // protected by 
fLock
+                       int32                           fUserDefinedTimerCount;
 };
 
 

Modified: 
haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h
===================================================================
--- haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h 
2011-05-27 23:37:10 UTC (rev 41786)
+++ haiku/branches/developer/bonefish/signals/headers/private/system/syscalls.h 
2011-05-27 23:47:02 UTC (rev 41787)
@@ -38,6 +38,7 @@
 struct signal_frame_data;
 struct stat;
 struct system_profiler_parameters;
+struct user_timer_info;
 
 struct disk_device_job_progress_info;
 struct partitionable_space_data;
@@ -385,6 +386,15 @@
 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,
+                                               struct user_timer_info* info);
+extern status_t                _kern_set_timer(int32 timerID,
+                                               struct user_timer_info* info,
+                                               struct user_timer_info* 
oldInfo);
+
 // area functions
 extern area_id         _kern_create_area(const char *name, void **address,
                                                uint32 addressSpec, size_t 
size, uint32 lock,

Added: 
haiku/branches/developer/bonefish/signals/headers/private/system/user_timer_defs.h
===================================================================
--- 
haiku/branches/developer/bonefish/signals/headers/private/system/user_timer_defs.h
                          (rev 0)
+++ 
haiku/branches/developer/bonefish/signals/headers/private/system/user_timer_defs.h
  2011-05-27 23:47:02 UTC (rev 41787)
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _SYSTEM_USER_TIMER_DEFS_H
+#define _SYSTEM_USER_TIMER_DEFS_H
+
+
+#include <limits.h>
+#include <time.h>
+
+#include <SupportDefs.h>
+
+
+// limits
+#define MAX_USER_TIMERS_PER_TEAM               _POSIX_TIMER_MAX
+       // maximum numbers of user-defined user timers (timer_create())
+#define MAX_USER_TIMER_OVERRUN_COUNT   _POSIX_DELAYTIMER_MAX
+       // cap value of a timer's overrun counter
+
+#define USER_TIMER_REAL_TIME_ID                                0
+       // predefined ID for the real time timer
+#define USER_TIMER_TEAM_TOTAL_TIME_ID          1
+       // predefined ID for the team's total (kernel + user) time timer
+#define USER_TIMER_TEAM_USER_TIME_ID           2
+       // predefined ID for the team's user time timer
+#define USER_TIMER_FIRST_USER_DEFINED_ID       3
+       // first ID assigned to a user-defined timer (timer_create())
+
+
+#define USER_TIMER_FOR_THREAD  0x01
+
+
+struct user_timer_info {
+       bigtime_t       next_time;
+       bigtime_t       interval;
+       uint32          flags;
+       uint32          overrun_count;
+};
+
+
+#endif /* _SYSTEM_USER_TIMER_DEFS_H */

Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/Jamfile
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/Jamfile 
2011-05-27 23:37:10 UTC (rev 41786)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/Jamfile 
2011-05-27 23:47:02 UTC (rev 41787)
@@ -50,7 +50,9 @@
        team.cpp
        thread.cpp
        timer.cpp
+       UserEvent.cpp
        usergroup.cpp
+       UserTimer.cpp
        wait_for_objects.cpp
 
        # locks

Added: haiku/branches/developer/bonefish/signals/src/system/kernel/UserEvent.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/UserEvent.cpp   
                        (rev 0)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/UserEvent.cpp   
2011-05-27 23:47:02 UTC (rev 41787)
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include <UserEvent.h>
+
+#include <ksignal.h>
+#include <thread_types.h>
+#include <util/AutoLock.h>
+
+
+// #pragma mark - UserEvent
+
+
+UserEvent::~UserEvent()
+{
+}
+
+
+// #pragma mark - TeamSignalEvent
+
+
+struct TeamSignalEvent::EventSignal : Signal {
+       EventSignal(uint32 number, int32 signalCode, int32 errorCode,
+               pid_t sendingProcess)
+               :
+               Signal(number, signalCode, errorCode, sendingProcess),
+               fInUse(false)
+       {
+       }
+
+       bool IsInUse() const
+       {
+               return fInUse;
+       }
+
+       void SetInUse(bool inUse)
+       {
+               fInUse = inUse;
+       }
+
+       virtual void Handled()
+       {
+               // mark not-in-use
+               InterruptsSpinLocker schedulerLocker(gSchedulerLock);
+               fInUse = false;
+               schedulerLocker.Unlock();
+
+               Signal::Handled();
+       }
+
+private:
+       bool                            fInUse;
+};
+
+
+TeamSignalEvent::TeamSignalEvent(Team* team, EventSignal* signal)
+       :
+       fTeam(team),
+       fSignal(signal)
+{
+}
+
+
+TeamSignalEvent::~TeamSignalEvent()
+{
+       fSignal->ReleaseReference();
+}
+
+
+/*static*/ TeamSignalEvent*
+TeamSignalEvent::Create(Team* team, uint32 signalNumber, int32 signalCode,
+       int32 errorCode)
+{
+       // create the signal
+       EventSignal* signal = new(std::nothrow) EventSignal(signalNumber,
+               signalCode, errorCode, team->id);
+       if (signal == NULL)
+               return NULL;
+
+       // create the event
+       TeamSignalEvent* event = new TeamSignalEvent(team, signal);
+       if (event == NULL) {
+               delete signal;
+               return NULL;
+       }
+
+       return event;
+}
+
+
+status_t
+TeamSignalEvent::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_team_locked(fTeam, 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;
+}
+
+
+void
+TeamSignalEvent::SetUserValue(union sigval userValue)
+{
+       fSignal->SetUserValue(userValue);
+}

Added: haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp   
                        (rev 0)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/UserTimer.cpp   
2011-05-27 23:47:02 UTC (rev 41787)
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@xxxxxxx
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include <UserTimer.h>
+
+#include <AutoDeleter.h>
+
+#include <debug.h>
+#include <kernel.h>
+#include <thread_types.h>
+#include <UserEvent.h>
+#include <util/AutoLock.h>
+
+
+// #pragma mark - UserTimer
+
+
+UserTimer::UserTimer()
+       :
+       fID(-1),
+       fEvent(NULL),
+       fScheduled(false)
+{
+       // mark the timer unused
+       fTimer.period = 0;
+       fTimer.user_data = this;
+}
+
+
+UserTimer::~UserTimer()
+{
+       delete fEvent;
+}
+
+
+/*!    Cancels the timer, if it is already scheduled, and optionally schedules 
it
+       with new parameters.
+
+       The caller must not hold the scheduler lock.
+
+       \param nextTime The absolute system time at which the timer should go 
off
+               the next time. If \c B_INFINITE_TIMEOUT, the timer will not be
+               scheduled.
+       \param interval If <tt> >0 </tt>, the timer will be scheduled to fire
+               periodically every \a interval microseconds. Otherwise it will 
fire
+               only once at \a nextTime. If \a nextTime is \c 
B_INFINITE_TIMEOUT, it
+               will fire never in either case.
+       \param _oldNextTime Return variable that will be set to the time for 
which
+               the timer was scheduled next before the call. If it wasn't 
scheduled,
+               the variable is set to \c B_INFINITE_TIMEOUT.
+       \param _oldInterval Return variable that will be set to the interval in
+               microseconds the timer was to be scheduled periodically. If the 
timer
+               wasn't periodic, the variable is set to \c 0.
+*/
+void
+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.
+       if (fScheduled) {
+               cancel_timer(&fTimer);
+
+               _oldNextTime = fTimer.schedule_time;
+               _oldInterval = fTimer.period;
+       } else {
+               _oldNextTime = B_INFINITE_TIMEOUT;
+               _oldInterval = 0;
+       }
+
+       // schedule the new timer
+       fTimer.schedule_time = nextTime;
+       fTimer.period = interval;
+
+       if (nextTime != B_INFINITE_TIMEOUT) {
+               uint32 flags = (interval > 0
+                               ? B_PERIODIC_TIMER : B_ONE_SHOT_ABSOLUTE_TIMER)
+                        | B_TIMER_USE_TIMER_STRUCT_TIMES | 
B_TIMER_ACQUIRE_SCHEDULER_LOCK;
+                       // We use B_TIMER_ACQUIRE_SCHEDULER_LOCK to avoid race 
conditions
+                       // between setting/canceling the timer and the event 
handler.
+
+               add_timer(&fTimer, &_HandleTimerHook, interval, flags);
+
+               fScheduled = true;
+       } else {
+               // mark the timer canceled
+               fScheduled = false;
+       }
+}
+
+
+/*!    Cancels the timer, if it is scheduled.
+
+       The caller must not hold the scheduler lock.
+*/
+void
+UserTimer::Cancel()
+{
+       bigtime_t oldNextTime;
+       bigtime_t oldInterval;
+       return Schedule(B_INFINITE_TIMEOUT, 0, oldNextTime, oldInterval);
+}
+
+
+/*!    Return information on the current timer.
+
+       The caller must not hold the scheduler lock.
+
+       \param _nextTime Return variable that will be set to the time for which
+               the timer is scheduled next. If it isn't scheduled, the 
variable is set
+               to \c B_INFINITE_TIMEOUT.
+       \param _interval Return variable that will be set to the interval in
+               microseconds the timer is to be scheduled periodically. If the 
timer
+               isn't periodic, the variable is set to \c 0.
+       \param _overrunCount Return variable that will be set to the number of 
times
+               the timer went off, but its event couldn't be delivered, since 
it's
+               previous delivery hasn't been handled yet.
+*/
+void
+UserTimer::GetInfo(bigtime_t& _oldNextTime, bigtime_t& _oldInterval,
+       uint32& _overrunCount)
+{
+       InterruptsSpinLocker schedulerLocker(gSchedulerLock);
+
+       if (fScheduled) {
+               _oldNextTime = fTimer.schedule_time;
+               _oldInterval = fTimer.period;
+       } else {
+               _oldNextTime = B_INFINITE_TIMEOUT;
+               _oldInterval = 0;
+       }
+
+       _overrunCount = fOverrunCount;
+}
+
+
+/*static*/ int32
+UserTimer::_HandleTimerHook(struct timer* timer)
+{
+       ((UserTimer*)timer->user_data)->_HandleTimer();
+       return B_HANDLED_INTERRUPT;
+}
+
+
+void
+UserTimer::_HandleTimer()
+{
+       if (fEvent == NULL)
+               return;
+
+       // fire the event and update the overrun count (increase or reset)
+       status_t error = fEvent->Fire();
+       if (error == B_BUSY) {
+               if (++fOverrunCount > MAX_USER_TIMER_OVERRUN_COUNT)
+                       fOverrunCount = MAX_USER_TIMER_OVERRUN_COUNT;
+       } else
+               fOverrunCount = 0;
+
+       // If it's not a periodic timer, it isn't scheduled anymore.
+       if (fTimer.period == 0)
+               fScheduled = false;
+}
+
+
+// #pragma mark - syscalls
+
+
+int32
+_user_create_timer(clockid_t clockID, uint32 flags, struct sigevent* userEvent)
+{
+       // we support only monotonic and real time timers
+       switch (clockID) {
+               case CLOCK_MONOTONIC:
+               case CLOCK_REALTIME:
+                       break;
+               default:
+                       return B_BAD_VALUE;
+       }
+
+       // create the timer object
+       UserTimer* timer = new(std::nothrow) UserTimer;
+       if (timer == NULL)
+               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;
+       }
+
+       Team* team = thread_get_current_thread()->team;
+
+       TeamSignalEvent* signalEvent = NULL;
+
+       switch (event.sigev_notify) {
+               case SIGEV_NONE:
+                       // the timer's event remains NULL
+                       break;
+
+               case SIGEV_SIGNAL:
+               {
+                       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 (signalEvent == NULL)
+                               return B_NO_MEMORY;
+
+                       timer->SetEvent(signalEvent);
+                       break;
+               }
+
+               case SIGEV_THREAD:
+// TODO:...
+return B_NOT_SUPPORTED;
+                       break;
+
+               default:
+                       return B_BAD_VALUE;
+       }
+
+       // add it to the team
+       TeamLocker teamLocker(team);
+
+       status_t error = 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();
+
+               signalEvent->SetUserValue(event.sigev_value);
+       }
+
+       return timerDeleter.Detach()->ID();
+}
+
+
+status_t
+_user_delete_timer(int32 timerID)
+{
+       // 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);
+
+       UserTimer* timer = team->UserTimerFor(timerID);
+       if (timer == NULL)
+               return B_BAD_VALUE;
+
+       timer->Cancel();
+
+       // remove and delete it
+       team->RemoveUserTimer(timer);
+
+       return B_OK;
+}
+
+
+status_t
+_user_get_timer(int32 timerID, struct user_timer_info* userInfo)
+{
+       // get the timer
+       Team* team = thread_get_current_thread()->team;
+       TeamLocker teamLocker(team);
+
+       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);
+
+       // copy it back to userland
+       if (userInfo != NULL
+               && (!IS_USER_ADDRESS(userInfo)
+                       || user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) 
{
+               return B_BAD_ADDRESS;
+       }
+
+       return B_OK;
+}
+
+
+status_t
+_user_set_timer(int32 timerID, struct user_timer_info* userInfo,
+       struct user_timer_info* userOldInfo)
+{
+       // copy info to userland
+       user_timer_info info;
+       if (userInfo == NULL || !IS_USER_ADDRESS(userInfo)
+               || user_memcpy(&info, userInfo, sizeof(info)) != B_OK) {
+               return B_BAD_ADDRESS;
+       }
+
+       // check the values
+       if (info.next_time < 0 || info.interval < 0)
+               return B_BAD_VALUE;
+
+       // get the timer
+       Team* team = thread_get_current_thread()->team;
+       TeamLocker teamLocker(team);
+
+       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);
+
+       // copy back the old info
+       if (userOldInfo != NULL
+               && (!IS_USER_ADDRESS(userOldInfo)
+                       || user_memcpy(userOldInfo, &oldInfo, sizeof(oldInfo)) 
!= B_OK)) {
+               return B_BAD_ADDRESS;
+       }
+
+       return B_OK;
+}

Modified: haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp
===================================================================
--- haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp      
2011-05-27 23:37:10 UTC (rev 41786)
+++ haiku/branches/developer/bonefish/signals/src/system/kernel/signal.cpp      
2011-05-27 23:47:02 UTC (rev 41787)
@@ -139,6 +139,34 @@
 }
 
 
+// #pragma mark - SignalHandledCaller
+
+
+struct SignalHandledCaller {
+       SignalHandledCaller(Signal* signal)
+               :
+               fSignal(signal)
+       {
+       }
+
+       ~SignalHandledCaller()
+       {
+               Done();
+       }
+
+       void Done()
+       {
+               if (fSignal != NULL) {
+                       fSignal->Handled();
+                       fSignal = NULL;
+               }
+       }
+
+private:
+       Signal* fSignal;
+};
+
+
 // #pragma mark - QueuedSignalsCounter
 
 
@@ -186,7 +214,8 @@
 
 Signal::Signal()
        :
-       fCounter(NULL)
+       fCounter(NULL),
+       fPending(false)
 {
 }
 
@@ -202,7 +231,8 @@
        fStatus(other.fStatus),
        fPollBand(other.fPollBand),
        fAddress(other.fAddress),
-       fUserValue(other.fUserValue)
+       fUserValue(other.fUserValue),
+       fPending(false)
 {
 }
 
@@ -218,7 +248,8 @@
        fSendingUser(getuid()),
        fStatus(0),
        fPollBand(0),
-       fAddress(NULL)
+       fAddress(NULL),
+       fPending(false)
 {
        fUserValue.sival_ptr = NULL;
 }
@@ -298,6 +329,13 @@
 
 
 void
+Signal::Handled()
+{
+       ReleaseReference();
+}
+
+
+void
 Signal::LastReferenceReleased()
 {
        if (are_interrupts_enabled())
@@ -344,7 +382,7 @@
 {
        // release references of all queued signals
        while (Signal* signal = fQueuedSignals.RemoveHead())
-               signal->ReleaseReference();
+               signal->Handled();
 
        fQueuedSignalsMask = 0;
        fUnqueuedSignalsMask = 0;
@@ -367,6 +405,7 @@
        }
 
        fQueuedSignals.InsertBefore(otherSignal, signal);
+       signal->SetPending(true);
 
        fQueuedSignalsMask |= SIGNAL_TO_MASK(signal->Number());
 }
@@ -375,6 +414,7 @@
 void
 PendingSignals::RemoveSignal(Signal* signal)
 {
+       signal->SetPending(false);
        fQueuedSignals.Remove(signal);
        _UpdateQueuedSignalMask();
 }
@@ -390,7 +430,8 @@
                        // remove signal, if in mask
                        if ((SIGNAL_TO_MASK(signal->Number()) & mask) != 0) {
                                it.Remove();
-                               signal->ReleaseReference();
+                               signal->SetPending(false);
+                               signal->Handled();
                        }
                }
 
@@ -422,6 +463,7 @@
        // if it is a queued signal, dequeue it
        if (queuedSignal != NULL) {
                fQueuedSignals.Remove(queuedSignal);
+               queuedSignal->SetPending(false);
                _UpdateQueuedSignalMask();
                return queuedSignal;
        }
@@ -927,7 +969,7 @@
                Signal* signal = dequeue_thread_or_team_signal(thread, 
nonBlockedMask,
                        stackSignal);
                ASSERT(signal != NULL);
-               BReference<Signal> signalReference(signal, true);
+               SignalHandledCaller signalHandledCaller(signal);
 
                schedulerLocker.Unlock();
 
@@ -1054,8 +1096,7 @@
                                                                team->id);
                                                        
childSignal.SetStatus(signal->Number());
                                                        
childSignal.SetSendingUser(signal->SendingUser());
-                                                       
send_signal_to_team_locked(parentTeam, childSignal,
-                                                               0);
+                                                       
send_signal_to_team(parentTeam, childSignal, 0);
                                                }
 
                                                team->UnlockTeamAndParent();
@@ -1071,6 +1112,7 @@
                                                thread->next_state = 
B_THREAD_SUSPENDED;

[... truncated: 708 lines follow ...]

Other related posts:

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