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