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 ...]