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:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user