* Scheduler/wait object listener:

- Moved scheduler listening interface to <listeners.h> and added more
    convenient to use templatized notification functions.
  - Added a listener mechanism for the wait objects (semaphores, condition
    variables, mutex, rw_lock).
* system profiler:
  - Hopefully fixed locking issues related to notifying the profiler thread
    for good. We still had an inconsistent locking order, since the scheduler
    notification callbacks are invoked with the thread lock held and have to
    acquire the object lock then, while the other callbacks acquired the object
    lock first and as a side effect of ConditionVariable::NotifyOne() acquired
    the thread lock. Now we make sure the object lock is the innermost lock.
  - Track the number of dropped events due to a full buffer.
    _user_system_profiler_next_buffer() returns this count now.
  - When scheduling profiling events are requested also listen to wait objects
    and generate the respective profiling events. We send those events lazily
    and cache the infos to avoid resending an event for the same wait object.
  - When starting profiling we do now generate "thread scheduled" events for
    the already running threads.
  - _user_system_profiler_start(): Check whether the parameters pointer is a
    userland address at all.
  - The system_profiler_team_added event does now also contain the team's name.
* Added a sem_get_name_unsafe() returning a semaphore's name. It is "unsafe",
  since the caller has to ensure that the semaphore exists and continues to
  exist as long as the returned name is used.
* Adjusted the "profile" and "scheduling_recorder" according to the system
  profiling changes. The latter prints the number of dropped events, now.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30345 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-04-23 13:47:52 +00:00
parent 1c800aa1f9
commit 227fe7d34a
17 changed files with 584 additions and 151 deletions
-21
View File
@@ -15,27 +15,6 @@ struct thread;
struct SchedulerListener;
#ifdef __cplusplus
#include <util/DoublyLinkedList.h>
struct SchedulerListener : DoublyLinkedListLinkImpl<SchedulerListener> {
virtual ~SchedulerListener();
virtual void ThreadEnqueuedInRunQueue(
struct thread* thread) = 0;
virtual void ThreadRemovedFromRunQueue(
struct thread* thread) = 0;
virtual void ThreadScheduled(struct thread* oldThread,
struct thread* newThread) = 0;
};
typedef DoublyLinkedList<SchedulerListener> SchedulerListenerList;
extern SchedulerListenerList gSchedulerListeners;
#endif // __cplusplus
struct scheduler_ops {
void (*enqueue_in_run_queue)(struct thread* thread);
void (*reschedule)(void);
+119
View File
@@ -0,0 +1,119 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef KERNEL_LISTENERS_H
#define KERNEL_LISTENERS_H
#include <KernelExport.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
class ConditionVariable;
struct mutex;
struct rw_lock;
struct thread;
// scheduler listeners
struct SchedulerListener : DoublyLinkedListLinkImpl<SchedulerListener> {
virtual ~SchedulerListener();
virtual void ThreadEnqueuedInRunQueue(
struct thread* thread) = 0;
virtual void ThreadRemovedFromRunQueue(
struct thread* thread) = 0;
virtual void ThreadScheduled(struct thread* oldThread,
struct thread* newThread) = 0;
};
typedef DoublyLinkedList<SchedulerListener> SchedulerListenerList;
extern SchedulerListenerList gSchedulerListeners;
// guarded by the thread spinlock
template<typename Parameter1>
inline void
NotifySchedulerListeners(void (SchedulerListener::*hook)(Parameter1),
Parameter1 parameter1)
{
if (!gSchedulerListeners.IsEmpty()) {
SchedulerListenerList::Iterator it = gSchedulerListeners.GetIterator();
while (SchedulerListener* listener = it.Next())
(listener->*hook)(parameter1);
}
}
template<typename Parameter1, typename Parameter2>
inline void
NotifySchedulerListeners(
void (SchedulerListener::*hook)(Parameter1, Parameter2),
Parameter1 parameter1, Parameter2 parameter2)
{
if (!gSchedulerListeners.IsEmpty()) {
SchedulerListenerList::Iterator it = gSchedulerListeners.GetIterator();
while (SchedulerListener* listener = it.Next())
(listener->*hook)(parameter1, parameter2);
}
}
// wait object listeners
struct WaitObjectListener : DoublyLinkedListLinkImpl<WaitObjectListener> {
virtual void SemaphoreCreated(sem_id id,
const char* name) = 0;
virtual void ConditionVariableInitialized(
ConditionVariable* variable) = 0;
virtual void MutexInitialized(mutex* lock) = 0;
virtual void RWLockInitialized(rw_lock* lock) = 0;
};
typedef DoublyLinkedList<WaitObjectListener> WaitObjectListenerList;
extern WaitObjectListenerList gWaitObjectListeners;
extern spinlock gWaitObjectListenerLock;
template<typename Parameter1>
inline void
NotifyWaitObjectListeners(void (WaitObjectListener::*hook)(Parameter1),
Parameter1 parameter1)
{
if (!gWaitObjectListeners.IsEmpty()) {
InterruptsSpinLocker locker(gWaitObjectListenerLock);
WaitObjectListenerList::Iterator it
= gWaitObjectListeners.GetIterator();
while (WaitObjectListener* listener = it.Next())
(listener->*hook)(parameter1);
}
}
template<typename Parameter1, typename Parameter2>
inline void
NotifyWaitObjectListeners(
void (WaitObjectListener::*hook)(Parameter1, Parameter2),
Parameter1 parameter1, Parameter2 parameter2)
{
if (!gWaitObjectListeners.IsEmpty()) {
InterruptsSpinLocker locker(gWaitObjectListenerLock);
WaitObjectListenerList::Iterator it
= gWaitObjectListeners.GetIterator();
while (WaitObjectListener* listener = it.Next())
(listener->*hook)(parameter1, parameter2);
}
}
void add_wait_object_listener(struct WaitObjectListener* listener);
void remove_wait_object_listener(struct WaitObjectListener* listener);
#endif // KERNEL_LISTENERS_H
+2
View File
@@ -31,6 +31,8 @@ extern status_t deselect_sem(int32 object, struct select_info *info,
extern sem_id create_sem_etc(int32 count, const char *name, team_id owner);
extern const char* sem_get_name_unsafe(sem_id id);
/* user calls */
sem_id _user_create_sem(int32 count, const char *name);
status_t _user_delete_sem(sem_id id);
+2 -1
View File
@@ -17,7 +17,8 @@ __BEGIN_DECLS
status_t _user_system_profiler_start(
struct system_profiler_parameters* parameters);
status_t _user_system_profiler_next_buffer(size_t bytesRead);
status_t _user_system_profiler_next_buffer(size_t bytesRead,
uint64* _droppedEvents);
status_t _user_system_profiler_stop();
__END_DECLS
+2 -1
View File
@@ -393,7 +393,8 @@ extern status_t _kern_clear_debugger_breakpoint(void *address,
extern status_t _kern_system_profiler_start(
struct system_profiler_parameters* parameters);
extern status_t _kern_system_profiler_next_buffer(size_t bytesRead);
extern status_t _kern_system_profiler_next_buffer(size_t bytesRead,
uint64* _droppedEvents);
extern status_t _kern_system_profiler_stop();
/* atomic_* ops (needed for CPUs that don't support them directly) */
@@ -81,7 +81,8 @@ struct system_profiler_event_header {
// B_SYSTEM_PROFILER_TEAM_ADDED
struct system_profiler_team_added {
team_id team;
char args[1];
uint16 args_offset;
char name[1];
};
// B_SYSTEM_PROFILER_TEAM_REMOVED
@@ -127,7 +128,7 @@ struct system_profiler_samples {
addr_t samples[0];
};
// B_SYSTEM_PROFILER_THREAD_SCHEDULED,
// B_SYSTEM_PROFILER_THREAD_SCHEDULED
struct system_profiler_thread_scheduled {
bigtime_t time;
thread_id thread;
@@ -137,14 +138,14 @@ struct system_profiler_thread_scheduled {
addr_t previous_thread_wait_object;
};
// B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE,
// B_SYSTEM_PROFILER_THREAD_ENQUEUED_IN_RUN_QUEUE
struct system_profiler_thread_enqueued_in_run_queue {
bigtime_t time;
thread_id thread;
uint8 priority;
};
// B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE,
// B_SYSTEM_PROFILER_THREAD_REMOVED_FROM_RUN_QUEUE
struct system_profiler_thread_removed_from_run_queue {
bigtime_t time;
thread_id thread;