Fixed the application quit mechanism. Due to the two levels of asynchronous
message sending the main thread exit()ed before the team debugger could process its quit message. We're no longer taking the detour via Debugger when quitting a window. The team debugger just quits and synchronously notifies the application, which in turn waits until all team debugger threads have gone. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31219 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
#include <Application.h>
|
#include <Application.h>
|
||||||
#include <Message.h>
|
#include <Message.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
#include <ObjectList.h>
|
#include <ObjectList.h>
|
||||||
|
|
||||||
#include "debug_utils.h"
|
#include "debug_utils.h"
|
||||||
@@ -163,11 +164,12 @@ parse_arguments(int argc, const char* const* argv, bool noOutput,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Debugger : public BApplication {
|
class Debugger : public BApplication, private TeamDebugger::Listener {
|
||||||
public:
|
public:
|
||||||
Debugger()
|
Debugger()
|
||||||
:
|
:
|
||||||
BApplication(kDebuggerSignature)
|
BApplication(kDebuggerSignature),
|
||||||
|
fRunningTeamDebuggers(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,17 +180,14 @@ public:
|
|||||||
virtual void MessageReceived(BMessage* message)
|
virtual void MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
switch (message->what) {
|
switch (message->what) {
|
||||||
case MSG_DEBUGGER_QUIT_REQUESTED:
|
case MSG_TEAM_DEBUGGER_QUIT:
|
||||||
{
|
{
|
||||||
TeamDebugger* debugger = NULL;
|
int32 threadID;
|
||||||
if (message->FindPointer("debugger",
|
if (message->FindInt32("thread", &threadID) == B_OK)
|
||||||
(void**)&debugger) == B_OK
|
wait_for_thread(threadID, NULL);
|
||||||
&& fTeamDebuggers.HasItem(debugger)) {
|
|
||||||
fTeamDebuggers.RemoveItem(debugger);
|
if (--fRunningTeamDebuggers == 0)
|
||||||
debugger->DeleteSelf();
|
Quit();
|
||||||
if (fTeamDebuggers.CountItems() == 0)
|
|
||||||
PostMessage(B_QUIT_REQUESTED);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -255,23 +254,45 @@ printf("There's already a debugger for team: %ld\n", team);
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
debugger = new(std::nothrow) TeamDebugger;
|
debugger = new(std::nothrow) TeamDebugger(this);
|
||||||
if (debugger == NULL) {
|
if (debugger == NULL) {
|
||||||
// TODO: Notify the user!
|
// TODO: Notify the user!
|
||||||
fprintf(stderr, "Error: Out of memory!\n");
|
fprintf(stderr, "Error: Out of memory!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debugger->Init(team, thread, stopInMain) == B_OK
|
status_t error = debugger->Init(team, thread, stopInMain);
|
||||||
&& fTeamDebuggers.AddItem(debugger)) {
|
if (debugger->Thread())
|
||||||
|
fRunningTeamDebuggers++;
|
||||||
|
|
||||||
|
if (error == B_OK && fTeamDebuggers.AddItem(debugger)) {
|
||||||
printf("debugger for team %ld created and initialized successfully!\n", team);
|
printf("debugger for team %ld created and initialized successfully!\n", team);
|
||||||
} else
|
} else
|
||||||
delete debugger;
|
delete debugger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef BObjectList<TeamDebugger> TeamDebuggerList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// TeamDebugger::Listener
|
||||||
|
virtual void TeamDebuggerQuit(TeamDebugger* debugger)
|
||||||
|
{
|
||||||
|
// Note: Locking here only works, since we're never locking the other
|
||||||
|
// way around. If we even need to do that, we'll have to introduce a
|
||||||
|
// separate lock to protect the list.
|
||||||
|
AutoLocker<Debugger> locker(this);
|
||||||
|
fTeamDebuggers.RemoveItem(debugger);
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
if (debugger->Thread() >= 0) {
|
||||||
|
BMessage message(MSG_TEAM_DEBUGGER_QUIT);
|
||||||
|
message.AddInt32("thread", debugger->Thread());
|
||||||
|
PostMessage(&message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool QuitRequested()
|
virtual bool QuitRequested()
|
||||||
{
|
{
|
||||||
// TODO:...
|
|
||||||
// return true;
|
|
||||||
// NOTE: The default implementation will just ask all windows'
|
// NOTE: The default implementation will just ask all windows'
|
||||||
// QuitRequested() hooks. This in turn will ask the TeamWindows.
|
// QuitRequested() hooks. This in turn will ask the TeamWindows.
|
||||||
// For now, this is what we want. If we have more windows later,
|
// For now, this is what we want. If we have more windows later,
|
||||||
@@ -282,12 +303,17 @@ printf("debugger for team %ld created and initialized successfully!\n", team);
|
|||||||
// QuitReqested() hook or the TeamsWindow and other global windows
|
// QuitReqested() hook or the TeamsWindow and other global windows
|
||||||
// could always return false in their QuitRequested().
|
// could always return false in their QuitRequested().
|
||||||
return BApplication::QuitRequested();
|
return BApplication::QuitRequested();
|
||||||
|
// TODO: This is ugly. The team debuggers own the windows, not the
|
||||||
|
// other way around.
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
virtual void Quit()
|
||||||
typedef BObjectList<TeamDebugger> TeamDebuggerList;
|
{
|
||||||
|
// don't quit before all team debuggers have been quit
|
||||||
|
if (fRunningTeamDebuggers <= 0)
|
||||||
|
BApplication::Quit();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
TeamDebugger* _TeamDebuggerForTeam(team_id teamID) const
|
TeamDebugger* _TeamDebuggerForTeam(team_id teamID) const
|
||||||
{
|
{
|
||||||
for (int32 i = 0; TeamDebugger* debugger = fTeamDebuggers.ItemAt(i);
|
for (int32 i = 0; TeamDebugger* debugger = fTeamDebuggers.ItemAt(i);
|
||||||
@@ -301,6 +327,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
TeamDebuggerList fTeamDebuggers;
|
TeamDebuggerList fTeamDebuggers;
|
||||||
|
int32 fRunningTeamDebuggers;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ enum {
|
|||||||
MSG_STACK_FRAME_SOURCE_CODE_CHANGED = 'sfsc',
|
MSG_STACK_FRAME_SOURCE_CODE_CHANGED = 'sfsc',
|
||||||
MSG_USER_BREAKPOINT_CHANGED = 'ubrc',
|
MSG_USER_BREAKPOINT_CHANGED = 'ubrc',
|
||||||
|
|
||||||
MSG_DEBUGGER_QUIT_REQUESTED = 'dbqt'
|
MSG_TEAM_DEBUGGER_QUIT = 'dbqt'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include <Alert.h>
|
#include <Alert.h>
|
||||||
#include <Application.h>
|
|
||||||
#include <Message.h>
|
#include <Message.h>
|
||||||
|
|
||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
@@ -26,9 +25,10 @@
|
|||||||
#include "TeamDebugModel.h"
|
#include "TeamDebugModel.h"
|
||||||
|
|
||||||
|
|
||||||
TeamDebugger::TeamDebugger()
|
TeamDebugger::TeamDebugger(Listener* listener)
|
||||||
:
|
:
|
||||||
BLooper("team debugger"),
|
BLooper("team debugger"),
|
||||||
|
fListener(listener),
|
||||||
fTeam(NULL),
|
fTeam(NULL),
|
||||||
fDebugModel(NULL),
|
fDebugModel(NULL),
|
||||||
fTeamID(-1),
|
fTeamID(-1),
|
||||||
@@ -63,6 +63,8 @@ TeamDebugger::~TeamDebugger()
|
|||||||
delete fWorker;
|
delete fWorker;
|
||||||
delete fDebugModel;
|
delete fDebugModel;
|
||||||
delete fTeam;
|
delete fTeam;
|
||||||
|
|
||||||
|
fListener->TeamDebuggerQuit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -188,14 +190,6 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TeamDebugger::DeleteSelf()
|
|
||||||
{
|
|
||||||
Lock();
|
|
||||||
Quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamDebugger::MessageReceived(BMessage* message)
|
TeamDebugger::MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
@@ -323,13 +317,9 @@ TeamDebugger::ClearBreakpointRequested(target_addr_t address)
|
|||||||
bool
|
bool
|
||||||
TeamDebugger::TeamWindowQuitRequested(TeamWindow* window)
|
TeamDebugger::TeamWindowQuitRequested(TeamWindow* window)
|
||||||
{
|
{
|
||||||
// TODO: Is this what shall happen?
|
AutoLocker< ::Team> locker(fTeam);
|
||||||
if (!fTeam->Lock())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
BString name(fTeam->Name());
|
BString name(fTeam->Name());
|
||||||
|
locker.Unlock();
|
||||||
fTeam->Unlock();
|
|
||||||
|
|
||||||
BString message;
|
BString message;
|
||||||
message << "What shall be done about the debugged team '";
|
message << "What shall be done about the debugged team '";
|
||||||
@@ -354,14 +344,11 @@ TeamDebugger::TeamWindowQuitRequested(TeamWindow* window)
|
|||||||
case 1:
|
case 1:
|
||||||
return false;
|
return false;
|
||||||
case 2:
|
case 2:
|
||||||
// Detach from the team and resume and stopped threads. Seems to be
|
// Detach from the team and resume and stopped threads.
|
||||||
// the default action anyways.
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
BMessage quitMessage(MSG_DEBUGGER_QUIT_REQUESTED);
|
PostMessage(B_QUIT_REQUESTED);
|
||||||
quitMessage.AddPointer("debugger", this);
|
|
||||||
be_app->PostMessage(&quitMessage);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -891,3 +878,11 @@ TeamDebugger::_NotifyUser(const char* title, const char* text,...)
|
|||||||
// create it and don't care anymore. Maybe an error window, which can
|
// create it and don't care anymore. Maybe an error window, which can
|
||||||
// display a list of errors would be the better choice.
|
// display a list of errors would be the better choice.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Listener
|
||||||
|
|
||||||
|
|
||||||
|
TeamDebugger::Listener::~Listener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,10 +20,13 @@ class DebuggerInterface;
|
|||||||
class TeamDebugModel;
|
class TeamDebugModel;
|
||||||
|
|
||||||
|
|
||||||
class TeamDebugger : private BLooper, private TeamWindow::Listener,
|
class TeamDebugger : public BLooper, private TeamWindow::Listener,
|
||||||
private JobListener, private Team::Listener {
|
private JobListener, private Team::Listener {
|
||||||
public:
|
public:
|
||||||
TeamDebugger();
|
class Listener;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TeamDebugger(Listener* listener);
|
||||||
~TeamDebugger();
|
~TeamDebugger();
|
||||||
|
|
||||||
status_t Init(team_id teamID, thread_id threadID,
|
status_t Init(team_id teamID, thread_id threadID,
|
||||||
@@ -31,11 +34,9 @@ public:
|
|||||||
|
|
||||||
team_id TeamID() const { return fTeamID; }
|
team_id TeamID() const { return fTeamID; }
|
||||||
|
|
||||||
void DeleteSelf();
|
|
||||||
|
|
||||||
private:
|
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
private:
|
||||||
// TeamWindow::Listener
|
// TeamWindow::Listener
|
||||||
virtual void StackFrameSourceCodeRequested(
|
virtual void StackFrameSourceCodeRequested(
|
||||||
TeamWindow* window, StackFrame* frame);
|
TeamWindow* window, StackFrame* frame);
|
||||||
@@ -111,6 +112,7 @@ private:
|
|||||||
const char* text,...);
|
const char* text,...);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Listener* fListener;
|
||||||
::Team* fTeam;
|
::Team* fTeam;
|
||||||
TeamDebugModel* fDebugModel;
|
TeamDebugModel* fDebugModel;
|
||||||
team_id fTeamID;
|
team_id fTeamID;
|
||||||
@@ -123,4 +125,13 @@ private:
|
|||||||
bool fKillTeamOnQuit;
|
bool fKillTeamOnQuit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TeamDebugger::Listener {
|
||||||
|
public:
|
||||||
|
virtual ~Listener();
|
||||||
|
|
||||||
|
virtual void TeamDebuggerQuit(TeamDebugger* debugger) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // TEAM_DEBUGGER_H
|
#endif // TEAM_DEBUGGER_H
|
||||||
|
|||||||
Reference in New Issue
Block a user