Debugger: Cleanups and improvements for status notification.
Worker/Job: - Add job listener hooks for when work actually begins for a job, and when a job is suspended to wait for user input. - Add hook for setting a job description string, and implement in several subclasses. LoadImageDebugInfoJob: - Get rid of ImageDebugInfoJobListener since its functionality can be handled via the more general job wait for user input hook. Refactor accordingly. TeamDebugger: - Adjust to use new job hooks. When a worker job is initiated, we now check if the job has a description, and if so pass it on to the UI to display a notification. DwarfLoadingStateHandler: - Notify the UI when a package download is in progress. With these changes, the status bar now notifies the user if any of the following actions are in flight: 1) Loading/parsing debug information 2) Stack trace retrieval 3) Source code retrieval 4) Downloading a debug info package
This commit is contained in:
parent
4c7fff8044
commit
9d9c74ecdb
@ -13,6 +13,7 @@
|
||||
#include <new>
|
||||
|
||||
#include <Entry.h>
|
||||
#include <InterfaceDefs.h>
|
||||
#include <Message.h>
|
||||
#include <StringList.h>
|
||||
|
||||
@ -1369,6 +1370,17 @@ TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::JobStarted(Job* job)
|
||||
{
|
||||
BString description(job->GetDescription());
|
||||
if (!description.IsEmpty()) {
|
||||
description.Append(B_UTF8_ELLIPSIS);
|
||||
fUserInterface->NotifyBackgroundWorkStatus(description.String());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::JobDone(Job* job)
|
||||
{
|
||||
@ -1377,6 +1389,21 @@ TeamDebugger::JobDone(Job* job)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::JobWaitingForInput(Job* job)
|
||||
{
|
||||
LoadImageDebugInfoJob* infoJob = dynamic_cast<LoadImageDebugInfoJob*>(job);
|
||||
|
||||
if (infoJob == NULL)
|
||||
return;
|
||||
|
||||
BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT);
|
||||
message.AddPointer("job", infoJob);
|
||||
message.AddPointer("state", infoJob->GetLoadingState());
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::JobFailed(Job* job)
|
||||
{
|
||||
@ -1396,30 +1423,6 @@ TeamDebugger::JobAborted(Job* job)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::ImageDebugInfoJobNeedsUserInput(Job* job,
|
||||
ImageDebugInfoLoadingState* state)
|
||||
{
|
||||
TRACE_JOBS("TeamDebugger::DebugInfoJobNeedsUserInput(%p, %p)\n",
|
||||
job, state);
|
||||
|
||||
BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT);
|
||||
message.AddPointer("job", job);
|
||||
message.AddPointer("state", state);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::ImageDebugInfoJobInProgress(Image* image)
|
||||
{
|
||||
BString message;
|
||||
message.SetToFormat("Loading debug information for %s...",
|
||||
image->Name().String());
|
||||
fUserInterface->NotifyBackgroundWorkStatus(message.String());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event)
|
||||
{
|
||||
|
@ -32,8 +32,7 @@ class WatchpointManager;
|
||||
|
||||
|
||||
class TeamDebugger : public BLooper, private UserInterfaceListener,
|
||||
private JobListener, private ImageDebugInfoJobListener,
|
||||
private Team::Listener {
|
||||
private JobListener, private Team::Listener {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
@ -134,14 +133,12 @@ private:
|
||||
QuitOption quitOption);
|
||||
|
||||
// JobListener
|
||||
virtual void JobStarted(Job* job);
|
||||
virtual void JobDone(Job* job);
|
||||
virtual void JobWaitingForInput(Job* job);
|
||||
virtual void JobFailed(Job* job);
|
||||
virtual void JobAborted(Job* job);
|
||||
|
||||
virtual void ImageDebugInfoJobNeedsUserInput(Job* job,
|
||||
ImageDebugInfoLoadingState* state);
|
||||
virtual void ImageDebugInfoJobInProgress(Image* image);
|
||||
|
||||
// Team::Listener
|
||||
virtual void ThreadStateChanged(
|
||||
const ::Team::ThreadEvent& event);
|
||||
|
@ -76,14 +76,13 @@ private:
|
||||
|
||||
|
||||
ThreadHandler::ThreadHandler(Thread* thread, Worker* worker,
|
||||
DebuggerInterface* debuggerInterface,
|
||||
ImageDebugInfoJobListener* listener,
|
||||
DebuggerInterface* debuggerInterface, JobListener* jobListener,
|
||||
BreakpointManager* breakpointManager)
|
||||
:
|
||||
fThread(thread),
|
||||
fWorker(worker),
|
||||
fDebuggerInterface(debuggerInterface),
|
||||
fDebugInfoJobListener(listener),
|
||||
fJobListener(jobListener),
|
||||
fBreakpointManager(breakpointManager),
|
||||
fStepMode(STEP_NONE),
|
||||
fStepStatement(NULL),
|
||||
@ -113,7 +112,7 @@ void
|
||||
ThreadHandler::Init()
|
||||
{
|
||||
fWorker->ScheduleJob(new(std::nothrow) GetThreadStateJob(fDebuggerInterface,
|
||||
fThread));
|
||||
fThread), fJobListener);
|
||||
fConditionWaitSem = create_sem(0, "breakpoint condition waiter");
|
||||
}
|
||||
|
||||
@ -458,7 +457,8 @@ ThreadHandler::HandleThreadStateChanged()
|
||||
if (fThread->State() == THREAD_STATE_STOPPED
|
||||
&& fThread->GetCpuState() == NULL) {
|
||||
fWorker->ScheduleJob(
|
||||
new(std::nothrow) GetCpuStateJob(fDebuggerInterface, fThread));
|
||||
new(std::nothrow) GetCpuStateJob(fDebuggerInterface, fThread),
|
||||
fJobListener);
|
||||
}
|
||||
}
|
||||
|
||||
@ -475,8 +475,8 @@ ThreadHandler::HandleCpuStateChanged()
|
||||
if (fThread->GetCpuState() != NULL && fThread->GetStackTrace() == NULL) {
|
||||
fWorker->ScheduleJob(
|
||||
new(std::nothrow) GetStackTraceJob(fDebuggerInterface,
|
||||
fDebugInfoJobListener, fDebuggerInterface->GetArchitecture(),
|
||||
fThread));
|
||||
fJobListener, fDebuggerInterface->GetArchitecture(),
|
||||
fThread), fJobListener);
|
||||
}
|
||||
}
|
||||
|
||||
@ -954,7 +954,8 @@ ThreadHandler::_HandleBreakpointConditionIfNeeded(CpuState* cpuState)
|
||||
|
||||
status_t error = fWorker->ScheduleJob(
|
||||
new(std::nothrow) ExpressionEvaluationJob(fThread->GetTeam(),
|
||||
fDebuggerInterface, language, expressionInfo, frame, fThread));
|
||||
fDebuggerInterface, language, expressionInfo, frame, fThread),
|
||||
fJobListener);
|
||||
|
||||
BPrivate::ObjectDeleter<ExpressionEvaluationListener> deleter(
|
||||
listener);
|
||||
|
@ -20,6 +20,7 @@ class BreakpointManager;
|
||||
class DebuggerInterface;
|
||||
class ExpressionResult;
|
||||
class ImageDebugInfoJobListener;
|
||||
class JobListener;
|
||||
class StackFrame;
|
||||
class Statement;
|
||||
class Worker;
|
||||
@ -30,7 +31,7 @@ class ThreadHandler : public BReferenceable, private ImageDebugInfoProvider,
|
||||
public:
|
||||
ThreadHandler(Thread* thread, Worker* worker,
|
||||
DebuggerInterface* debuggerInterface,
|
||||
ImageDebugInfoJobListener* listener,
|
||||
JobListener* listener,
|
||||
BreakpointManager* breakpointManager);
|
||||
~ThreadHandler();
|
||||
|
||||
@ -117,7 +118,7 @@ private:
|
||||
Thread* fThread;
|
||||
Worker* fWorker;
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
ImageDebugInfoJobListener* fDebugInfoJobListener;
|
||||
JobListener* fJobListener;
|
||||
BreakpointManager* fBreakpointManager;
|
||||
uint32 fStepMode;
|
||||
Statement* fStepStatement;
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <Entry.h>
|
||||
#include <InterfaceDefs.h>
|
||||
#include <Path.h>
|
||||
#include <package/solver/Solver.h>
|
||||
#include <package/solver/SolverPackage.h>
|
||||
@ -108,6 +109,10 @@ DwarfLoadingStateHandler::HandleState(
|
||||
BString command;
|
||||
command.SetToFormat("/bin/pkgman install -y %s",
|
||||
requiredPackage.String());
|
||||
BString notification;
|
||||
notification.SetToFormat("Installing package %s" B_UTF8_ELLIPSIS,
|
||||
requiredPackage.String());
|
||||
interface->NotifyBackgroundWorkStatus(notification);
|
||||
int error = system(command.String());
|
||||
if (interface->IsInteractive()) {
|
||||
if (WIFEXITED(error)) {
|
||||
|
@ -18,12 +18,11 @@
|
||||
|
||||
|
||||
GetStackTraceJob::GetStackTraceJob(DebuggerInterface* debuggerInterface,
|
||||
ImageDebugInfoJobListener* listener, Architecture* architecture,
|
||||
Thread* thread)
|
||||
JobListener* listener, Architecture* architecture, Thread* thread)
|
||||
:
|
||||
fKey(thread, JOB_TYPE_GET_STACK_TRACE),
|
||||
fDebuggerInterface(debuggerInterface),
|
||||
fDebugInfoJobListener(listener),
|
||||
fJobListener(listener),
|
||||
fArchitecture(architecture),
|
||||
fThread(thread)
|
||||
{
|
||||
@ -32,6 +31,9 @@ GetStackTraceJob::GetStackTraceJob(DebuggerInterface* debuggerInterface,
|
||||
fCpuState = fThread->GetCpuState();
|
||||
if (fCpuState != NULL)
|
||||
fCpuState->AcquireReference();
|
||||
|
||||
|
||||
SetDescription("Retrieving stack trace for thread %" B_PRId32, fThread->ID());
|
||||
}
|
||||
|
||||
|
||||
@ -84,7 +86,7 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
|
||||
// schedule a job, if not loaded
|
||||
ImageDebugInfo* info;
|
||||
status_t error = LoadImageDebugInfoJob::ScheduleIfNecessary(GetWorker(),
|
||||
image, fDebugInfoJobListener, &info);
|
||||
image, fJobListener, &info);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
|
@ -92,20 +92,11 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class ImageDebugInfoJobListener {
|
||||
public:
|
||||
virtual ~ImageDebugInfoJobListener();
|
||||
virtual void ImageDebugInfoJobNeedsUserInput(Job* job,
|
||||
ImageDebugInfoLoadingState* state);
|
||||
virtual void ImageDebugInfoJobInProgress(Image* image);
|
||||
};
|
||||
|
||||
|
||||
class GetStackTraceJob : public Job, private ImageDebugInfoProvider {
|
||||
public:
|
||||
GetStackTraceJob(
|
||||
DebuggerInterface* debuggerInterface,
|
||||
ImageDebugInfoJobListener* listener,
|
||||
JobListener* jobListener,
|
||||
Architecture* architecture, Thread* thread);
|
||||
virtual ~GetStackTraceJob();
|
||||
|
||||
@ -120,7 +111,7 @@ private:
|
||||
private:
|
||||
SimpleJobKey fKey;
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
ImageDebugInfoJobListener* fDebugInfoJobListener;
|
||||
JobListener* fJobListener;
|
||||
Architecture* fArchitecture;
|
||||
Thread* fThread;
|
||||
CpuState* fCpuState;
|
||||
@ -129,8 +120,7 @@ private:
|
||||
|
||||
class LoadImageDebugInfoJob : public Job {
|
||||
public:
|
||||
LoadImageDebugInfoJob(Image* image,
|
||||
ImageDebugInfoJobListener* listener);
|
||||
LoadImageDebugInfoJob(Image* image);
|
||||
virtual ~LoadImageDebugInfoJob();
|
||||
|
||||
virtual const JobKey& Key() const;
|
||||
@ -138,7 +128,7 @@ public:
|
||||
|
||||
static status_t ScheduleIfNecessary(Worker* worker,
|
||||
Image* image,
|
||||
ImageDebugInfoJobListener* listener,
|
||||
JobListener* jobListener,
|
||||
ImageDebugInfo** _imageDebugInfo = NULL);
|
||||
// If already loaded returns a
|
||||
// reference, if desired. If not loaded
|
||||
@ -147,19 +137,16 @@ public:
|
||||
// if scheduling the job failed, or the
|
||||
// debug info already failed to load
|
||||
// earlier.
|
||||
private:
|
||||
void NotifyUserInputListener();
|
||||
|
||||
private:
|
||||
typedef BObjectList<ImageDebugInfoJobListener> ListenerList;
|
||||
|
||||
ImageDebugInfoLoadingState*
|
||||
GetLoadingState()
|
||||
{ return &fState; }
|
||||
|
||||
private:
|
||||
SimpleJobKey fKey;
|
||||
Image* fImage;
|
||||
ImageDebugInfoLoadingState
|
||||
fState;
|
||||
ImageDebugInfoJobListener* fListener;
|
||||
};
|
||||
|
||||
|
||||
|
@ -14,39 +14,19 @@
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
// #pragma mark - ImageDebugInfoJobListener
|
||||
|
||||
|
||||
ImageDebugInfoJobListener::~ImageDebugInfoJobListener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageDebugInfoJobListener::ImageDebugInfoJobNeedsUserInput(Job* job,
|
||||
ImageDebugInfoLoadingState* state)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageDebugInfoJobListener::ImageDebugInfoJobInProgress(Image* image)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - LoadImageDebugInfoJob
|
||||
|
||||
|
||||
LoadImageDebugInfoJob::LoadImageDebugInfoJob(Image* image,
|
||||
ImageDebugInfoJobListener* listener)
|
||||
LoadImageDebugInfoJob::LoadImageDebugInfoJob(Image* image)
|
||||
:
|
||||
fKey(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO),
|
||||
fImage(image),
|
||||
fState(),
|
||||
fListener(listener)
|
||||
fState()
|
||||
{
|
||||
fImage->AcquireReference();
|
||||
|
||||
SetDescription("Loading debugging information for %s",
|
||||
fImage->Name().String());
|
||||
}
|
||||
|
||||
|
||||
@ -71,9 +51,6 @@ LoadImageDebugInfoJob::Do()
|
||||
ImageInfo imageInfo(fImage->Info());
|
||||
locker.Unlock();
|
||||
|
||||
if (fListener != NULL)
|
||||
fListener->ImageDebugInfoJobInProgress(fImage);
|
||||
|
||||
// create the debug info
|
||||
ImageDebugInfo* debugInfo;
|
||||
status_t error = fImage->GetTeam()->DebugInfo()->LoadImageDebugInfo(
|
||||
@ -83,7 +60,6 @@ LoadImageDebugInfoJob::Do()
|
||||
locker.Lock();
|
||||
|
||||
if (fState.UserInputRequired()) {
|
||||
NotifyUserInputListener();
|
||||
return WaitForUserInput();
|
||||
} else if (error == B_OK) {
|
||||
error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED);
|
||||
@ -97,7 +73,7 @@ LoadImageDebugInfoJob::Do()
|
||||
|
||||
/*static*/ status_t
|
||||
LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
|
||||
ImageDebugInfoJobListener* listener, ImageDebugInfo** _imageDebugInfo)
|
||||
JobListener* listener, ImageDebugInfo** _imageDebugInfo)
|
||||
{
|
||||
AutoLocker<Team> teamLocker(image->GetTeam());
|
||||
|
||||
@ -122,12 +98,12 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
|
||||
return B_ERROR;
|
||||
|
||||
// schedule a job
|
||||
LoadImageDebugInfoJob* job = new(std::nothrow) LoadImageDebugInfoJob(image,
|
||||
listener);
|
||||
LoadImageDebugInfoJob* job = new(std::nothrow) LoadImageDebugInfoJob(
|
||||
image);
|
||||
if (job == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = worker->ScheduleJob(job);
|
||||
status_t error = worker->ScheduleJob(job, listener);
|
||||
if (error != B_OK) {
|
||||
image->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE);
|
||||
return error;
|
||||
@ -139,12 +115,3 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
|
||||
*_imageDebugInfo = NULL;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LoadImageDebugInfoJob::NotifyUserInputListener()
|
||||
{
|
||||
if (fListener != NULL)
|
||||
fListener->ImageDebugInfoJobNeedsUserInput(this, &fState);
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,9 @@ LoadSourceCodeJob::LoadSourceCodeJob(
|
||||
fLoadForFunction(loadForFunction)
|
||||
{
|
||||
fFunctionInstance->AcquireReference();
|
||||
|
||||
SetDescription("Loading source code for function %s",
|
||||
fFunctionInstance->PrettyName().String());
|
||||
}
|
||||
|
||||
|
||||
|
@ -70,12 +70,24 @@ JobListener::~JobListener()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JobListener::JobStarted(Job* job)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JobListener::JobDone(Job* job)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JobListener::JobWaitingForInput(Job* job)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
JobListener::JobFailed(Job* job)
|
||||
{
|
||||
@ -121,6 +133,15 @@ Job::WaitForUserInput()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Job::SetDescription(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
fDescription.SetToFormatVarArgs(format, args);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Job::SetWorker(Worker* worker)
|
||||
{
|
||||
@ -179,6 +200,13 @@ Job::NotifyListeners()
|
||||
for (int32 i = count - 1; i >= 0; i--) {
|
||||
JobListener* listener = fListeners.ItemAt(i);
|
||||
switch (fState) {
|
||||
case JOB_STATE_ACTIVE:
|
||||
listener->JobStarted(this);
|
||||
break;
|
||||
case JOB_STATE_WAITING:
|
||||
if (fWaitStatus == JOB_USER_INPUT_WAITING)
|
||||
listener->JobWaitingForInput(this);
|
||||
break;
|
||||
case JOB_STATE_SUCCEEDED:
|
||||
listener->JobDone(this);
|
||||
break;
|
||||
@ -403,6 +431,7 @@ Worker::WaitForUserInput(Job* waitingJob)
|
||||
return B_INTERRUPTED;
|
||||
|
||||
waitingJob->SetWaitStatus(JOB_USER_INPUT_WAITING);
|
||||
waitingJob->NotifyListeners();
|
||||
fSuspendedJobs.Add(waitingJob);
|
||||
|
||||
return B_OK;
|
||||
@ -459,6 +488,7 @@ Worker::_ProcessJobs()
|
||||
// process the next job
|
||||
if (Job* job = fUnscheduledJobs.RemoveHead()) {
|
||||
job->SetState(JOB_STATE_ACTIVE);
|
||||
job->NotifyListeners();
|
||||
|
||||
locker.Unlock();
|
||||
status_t error = job->Do();
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <ObjectList.h>
|
||||
#include <Referenceable.h>
|
||||
#include <String.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
@ -69,7 +70,9 @@ class JobListener {
|
||||
public:
|
||||
virtual ~JobListener();
|
||||
|
||||
virtual void JobStarted(Job* job);
|
||||
virtual void JobDone(Job* job);
|
||||
virtual void JobWaitingForInput(Job* job);
|
||||
virtual void JobFailed(Job* job);
|
||||
virtual void JobAborted(Job* job);
|
||||
};
|
||||
@ -89,9 +92,13 @@ public:
|
||||
Worker* GetWorker() const { return fWorker; }
|
||||
job_state State() const { return fState; }
|
||||
|
||||
const BString& GetDescription() const
|
||||
{ return fDescription; }
|
||||
|
||||
protected:
|
||||
job_wait_status WaitFor(const JobKey& key);
|
||||
status_t WaitForUserInput();
|
||||
void SetDescription(const char* format, ...);
|
||||
|
||||
private:
|
||||
friend class Worker;
|
||||
@ -122,6 +129,7 @@ private:
|
||||
JobList fDependentJobs;
|
||||
job_wait_status fWaitStatus;
|
||||
ListenerList fListeners;
|
||||
BString fDescription;
|
||||
|
||||
public:
|
||||
Job* fNext;
|
||||
|
Loading…
Reference in New Issue
Block a user