Merged branch haiku/branches/developer/bonefish/optimization revision

23139 into trunk, with roughly the following changes (for details svn
log the branch):
* The int 99 syscall handler is now fully in assembly.
* Added a sysenter/sysexit handler and use it on Pentiums that support
  it (via commpage).
* Got rid of i386_handle_trap(). A bit of functionality was moved into
  the assembly handler which now uses a jump table to call C functions
  handling the respective interrupt.
* Some optimizations to get user debugger support code out of the
  interrupt handling path.
* Introduced a thread::flags fields which allows to skip handling of
  rare events (signals, user debug enabling/disabling) on the
  common interrupt handling path.
* Got rid of the explicit iframe stack. The iframes can still be
  retrieved by iterating through the stack frames.
* Made the commpage an architecture independent feature. It's used for
  the real time data stuff (instead of creating a separate area).
* The x86 CPU modules can now provide processor optimized versions for
  common functions (currently memcpy() only). They are used in the
  kernel and are provided to the userland via commpage entries.
* Introduced build system feature allowing easy use of C structure
  member offsets in assembly code.

Changes after merging:
* Fixed merge conflict in src/system/kernel/arch/x86/arch_debug.cpp
  (caused by refactoring and introduction of "call" debugger command).



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23370 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-01-11 00:36:44 +00:00
parent 5a69bb2730
commit 34b3b26b3b
50 changed files with 1641 additions and 722 deletions
+159 -5
View File
@@ -23,6 +23,8 @@
#include <vm_types.h>
#include <arch/user_debugger.h>
#include <util/AutoLock.h>
//#define TRACE_USER_DEBUGGER
#ifdef TRACE_USER_DEBUGGER
# define TRACE(x) dprintf x
@@ -109,6 +111,96 @@ debugger_write(port_id port, int32 code, const void *buffer, size_t bufferSize,
}
/*! Updates the thread::flags field according to what user debugger flags are
set for the thread.
Interrupts must be disabled and the thread lock must be held.
*/
static void
update_thread_user_debug_flag(struct thread* thread)
{
if (atomic_get(&thread->debug_info.flags)
& (B_THREAD_DEBUG_STOP | B_THREAD_DEBUG_SINGLE_STEP)) {
atomic_or(&thread->flags, THREAD_FLAGS_DEBUG_THREAD);
} else
atomic_and(&thread->flags, ~THREAD_FLAGS_DEBUG_THREAD);
}
/*! Updates the thread::flags THREAD_FLAGS_BREAKPOINTS_DEFINED bit of the
current thread.
Interrupts must be disabled and the team lock must be held.
*/
static void
update_thread_breakpoints_flag()
{
struct thread* thread = thread_get_current_thread();
struct team* team = thread->team;
if (arch_has_breakpoints(&team->debug_info.arch_info))
atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_DEFINED);
else
atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_DEFINED);
}
/*! Updates the thread::flags THREAD_FLAGS_BREAKPOINTS_DEFINED bit of all
threads of the current team.
Interrupts must be disabled and the team lock must be held.
*/
static void
update_threads_breakpoints_flag()
{
InterruptsSpinLocker _(team_spinlock);
struct team* team = thread_get_current_thread()->team;
struct thread* thread = team->thread_list;
if (arch_has_breakpoints(&team->debug_info.arch_info)) {
for (; thread != NULL; thread = thread->team_next)
atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_DEFINED);
} else {
for (; thread != NULL; thread = thread->team_next)
atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_DEFINED);
}
}
/*! Updates the thread::flags B_TEAM_DEBUG_DEBUGGER_INSTALLED bit of the
current thread.
Interrupts must be disabled and the team lock must be held.
*/
static void
update_thread_debugger_installed_flag()
{
struct thread* thread = thread_get_current_thread();
struct team* team = thread->team;
if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED)
atomic_or(&thread->flags, THREAD_FLAGS_DEBUGGER_INSTALLED);
else
atomic_and(&thread->flags, ~THREAD_FLAGS_DEBUGGER_INSTALLED);
}
/*! Updates the thread::flags THREAD_FLAGS_DEBUGGER_INSTALLED bit of all
threads of the given team.
Interrupts must be disabled and the team lock must be held.
*/
static void
update_threads_debugger_installed_flag(struct team* team)
{
struct thread* thread = team->thread_list;
if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
for (; thread != NULL; thread = thread->team_next)
atomic_or(&thread->flags, THREAD_FLAGS_DEBUGGER_INSTALLED);
} else {
for (; thread != NULL; thread = thread->team_next)
atomic_and(&thread->flags, ~THREAD_FLAGS_DEBUGGER_INSTALLED);
}
}
/**
* For the first initialization the function must be called with \a initLock
* set to \c true. If it would be possible that another thread accesses the
@@ -379,6 +471,8 @@ thread_hit_debug_event_internal(debug_debugger_message event,
threadFlags |= B_THREAD_DEBUG_STOPPED;
atomic_set(&thread->debug_info.flags, threadFlags);
update_thread_user_debug_flag(thread);
RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
RELEASE_THREAD_LOCK();
restore_interrupts(state);
@@ -519,6 +613,8 @@ thread_hit_debug_event_internal(debug_debugger_message event,
// unset the "stopped" state
atomic_and(&thread->debug_info.flags, ~B_THREAD_DEBUG_STOPPED);
update_thread_user_debug_flag(thread);
} else {
// the debugger is gone: cleanup our info completely
threadDebugInfo = thread->debug_info;
@@ -529,6 +625,9 @@ thread_hit_debug_event_internal(debug_debugger_message event,
RELEASE_THREAD_LOCK();
restore_interrupts(state);
// enable/disable single stepping
arch_update_thread_single_step();
if (destroyThreadInfo)
destroy_thread_debug_info(&threadDebugInfo);
@@ -744,6 +843,29 @@ user_debug_team_deleted(team_id teamID, port_id debuggerPort)
}
void
user_debug_update_new_thread_flags(thread_id threadID)
{
// Update thread::flags of the thread.
InterruptsLocker interruptsLocker;
SpinLocker threadLocker(thread_spinlock);
struct thread *thread = thread_get_thread_struct_locked(threadID);
if (!thread)
return;
update_thread_user_debug_flag(thread);
threadLocker.Unlock();
SpinLocker teamLocker(team_spinlock);
update_thread_breakpoints_flag();
update_thread_debugger_installed_flag();
}
void
user_debug_thread_created(thread_id threadID)
{
@@ -976,6 +1098,9 @@ nub_thread_cleanup(struct thread *nubThread)
destroyDebugInfo = true;
}
// update the thread::flags fields
update_threads_debugger_installed_flag(nubThread->team);
RELEASE_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);
RELEASE_TEAM_LOCK();
restore_interrupts(state);
@@ -1476,6 +1601,9 @@ debug_nub_thread(void *)
if (result == B_OK)
result = arch_set_breakpoint(address);
if (result == B_OK)
update_threads_breakpoints_flag();
// prepare the reply
reply.set_breakpoint.error = result;
replySize = sizeof(reply.set_breakpoint);
@@ -1501,6 +1629,9 @@ debug_nub_thread(void *)
if (result == B_OK)
result = arch_clear_breakpoint(address);
if (result == B_OK)
update_threads_breakpoints_flag();
break;
}
@@ -1527,6 +1658,9 @@ debug_nub_thread(void *)
if (result == B_OK)
result = arch_set_watchpoint(address, type, length);
if (result == B_OK)
update_threads_breakpoints_flag();
// prepare the reply
reply.set_watchpoint.error = result;
replySize = sizeof(reply.set_watchpoint);
@@ -1552,6 +1686,9 @@ debug_nub_thread(void *)
if (result == B_OK)
result = arch_clear_watchpoint(address);
if (result == B_OK)
update_threads_breakpoints_flag();
break;
}
@@ -1790,7 +1927,7 @@ debug_nub_thread(void *)
Interrupts must be disabled and the team debug info lock of the team to be
debugged must be held. The function will release the lock, but leave
interrupts disabled.
interrupts disabled. The team lock must be held, too.
The function also clears the arch specific team and thread debug infos
(including among other things formerly set break/watchpoints).
@@ -1833,6 +1970,9 @@ install_team_debugger_init_debug_infos(struct team *team, team_id debuggerTeam,
}
RELEASE_THREAD_LOCK();
// update the thread::flags fields
update_threads_debugger_installed_flag(team);
}
@@ -2218,6 +2358,8 @@ _user_debug_thread(thread_id threadID)
// set the flag that tells the thread to stop as soon as possible
atomic_or(&thread->debug_info.flags, B_THREAD_DEBUG_STOP);
update_thread_user_debug_flag(thread);
switch (thread->state) {
case B_THREAD_SUSPENDED:
// thread suspended: wake it up
@@ -2272,10 +2414,16 @@ _user_set_debugger_breakpoint(void *address, uint32 type, int32 length,
// that we install a break/watchpoint the debugger doesn't know about.
// set the break/watchpoint
status_t result;
if (watchpoint)
return arch_set_watchpoint(address, type, length);
result = arch_set_watchpoint(address, type, length);
else
return arch_set_breakpoint(address);
result = arch_set_breakpoint(address);
if (result == B_OK)
update_threads_breakpoints_flag();
return result;
}
@@ -2297,8 +2445,14 @@ _user_clear_debugger_breakpoint(void *address, bool watchpoint)
// that we clear a break/watchpoint the debugger has just installed.
// clear the break/watchpoint
status_t result;
if (watchpoint)
return arch_clear_watchpoint(address);
result = arch_clear_watchpoint(address);
else
return arch_clear_breakpoint(address);
result = arch_clear_breakpoint(address);
if (result == B_OK)
update_threads_breakpoints_flag();
return result;
}