Debugger: CliContext: Introduce the notion of events
* The input loop can now wait on abstract events, which other threads (or even the input loop thread itself) can signal. * Use the new mechanism in QuitSession(). * Also (with the exception of the SIGINT part) implement WaitForThreadOrUser().
This commit is contained in:
@@ -28,16 +28,22 @@ CliContext::CliContext()
|
|||||||
fHistory(NULL),
|
fHistory(NULL),
|
||||||
fPrompt(NULL),
|
fPrompt(NULL),
|
||||||
fBlockingSemaphore(-1),
|
fBlockingSemaphore(-1),
|
||||||
|
fInputLoopWaitingForEvents(0),
|
||||||
|
fEventsOccurred(0),
|
||||||
fInputLoopWaiting(false),
|
fInputLoopWaiting(false),
|
||||||
fTerminating(false)
|
fTerminating(false)
|
||||||
{
|
{
|
||||||
sCurrentContext = this;
|
sCurrentContext = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CliContext::~CliContext()
|
CliContext::~CliContext()
|
||||||
{
|
{
|
||||||
Cleanup();
|
Cleanup();
|
||||||
sCurrentContext = NULL;
|
sCurrentContext = NULL;
|
||||||
|
|
||||||
|
if (fBlockingSemaphore >= 0)
|
||||||
|
delete_sem(fBlockingSemaphore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -47,6 +53,8 @@ CliContext::Init(Team* team, UserInterfaceListener* listener)
|
|||||||
fTeam = team;
|
fTeam = team;
|
||||||
fListener = listener;
|
fListener = listener;
|
||||||
|
|
||||||
|
fTeam->AddListener(this);
|
||||||
|
|
||||||
status_t error = fLock.InitCheck();
|
status_t error = fLock.InitCheck();
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
@@ -88,6 +96,11 @@ CliContext::Cleanup()
|
|||||||
history_end(fHistory);
|
history_end(fHistory);
|
||||||
fHistory = NULL;
|
fHistory = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fTeam != NULL) {
|
||||||
|
fTeam->RemoveListener(this);
|
||||||
|
fTeam = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -97,13 +110,7 @@ CliContext::Terminating()
|
|||||||
AutoLocker<BLocker> locker(fLock);
|
AutoLocker<BLocker> locker(fLock);
|
||||||
|
|
||||||
fTerminating = true;
|
fTerminating = true;
|
||||||
|
_SignalInputLoop(EVENT_QUIT);
|
||||||
if (fBlockingSemaphore >= 0) {
|
|
||||||
delete_sem(fBlockingSemaphore);
|
|
||||||
fBlockingSemaphore = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fInputLoopWaiting = false;
|
|
||||||
|
|
||||||
// TODO: Signal the input loop, should it be in PromptUser()!
|
// TODO: Signal the input loop, should it be in PromptUser()!
|
||||||
}
|
}
|
||||||
@@ -134,27 +141,104 @@ CliContext::AddLineToInputHistory(const char* line)
|
|||||||
void
|
void
|
||||||
CliContext::QuitSession(bool killTeam)
|
CliContext::QuitSession(bool killTeam)
|
||||||
{
|
{
|
||||||
AutoLocker<BLocker> locker(fLock);
|
_PrepareToWaitForEvents(EVENT_QUIT);
|
||||||
|
|
||||||
sem_id blockingSemaphore = fBlockingSemaphore;
|
|
||||||
fInputLoopWaiting = true;
|
|
||||||
|
|
||||||
locker.Unlock();
|
|
||||||
|
|
||||||
fListener->UserInterfaceQuitRequested(
|
fListener->UserInterfaceQuitRequested(
|
||||||
killTeam
|
killTeam
|
||||||
? UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM
|
? UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM
|
||||||
: UserInterfaceListener::QUIT_OPTION_ASK_RESUME_TEAM);
|
: UserInterfaceListener::QUIT_OPTION_ASK_RESUME_TEAM);
|
||||||
|
|
||||||
while (acquire_sem(blockingSemaphore) == B_INTERRUPTED) {
|
_WaitForEvents();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CliContext::WaitForThreadOrUser()
|
CliContext::WaitForThreadOrUser()
|
||||||
{
|
{
|
||||||
// TODO:...
|
// TODO: Deal with SIGINT as well!
|
||||||
|
for (;;) {
|
||||||
|
_PrepareToWaitForEvents(
|
||||||
|
EVENT_USER_INTERRUPT | EVENT_THREAD_STATE_CHANGED);
|
||||||
|
|
||||||
|
// check whether there are any threads stopped already
|
||||||
|
thread_id stoppedThread = -1;
|
||||||
|
AutoLocker<Team> teamLocker(fTeam);
|
||||||
|
|
||||||
|
for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
|
||||||
|
Thread* thread = it.Next();) {
|
||||||
|
if (thread->State() == THREAD_STATE_STOPPED) {
|
||||||
|
stoppedThread = thread->ID();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
teamLocker.Unlock();
|
||||||
|
|
||||||
|
if (stoppedThread >= 0)
|
||||||
|
_SignalInputLoop(EVENT_THREAD_STATE_CHANGED);
|
||||||
|
|
||||||
|
uint32 events = _WaitForEvents();
|
||||||
|
if ((events & EVENT_QUIT) != 0 || stoppedThread >= 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliContext::ThreadStateChanged(const Team::ThreadEvent& event)
|
||||||
|
{
|
||||||
|
_SignalInputLoop(EVENT_THREAD_STATE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliContext::_PrepareToWaitForEvents(uint32 eventMask)
|
||||||
|
{
|
||||||
|
// Set the events we're going to wait for -- always wait for "quit".
|
||||||
|
AutoLocker<BLocker> locker(fLock);
|
||||||
|
fInputLoopWaitingForEvents = eventMask | EVENT_QUIT;
|
||||||
|
fEventsOccurred = fTerminating ? EVENT_QUIT : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32
|
||||||
|
CliContext::_WaitForEvents()
|
||||||
|
{
|
||||||
|
AutoLocker<BLocker> locker(fLock);
|
||||||
|
|
||||||
|
if (fEventsOccurred == 0) {
|
||||||
|
sem_id blockingSemaphore = fBlockingSemaphore;
|
||||||
|
fInputLoopWaiting = true;
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
while (acquire_sem(blockingSemaphore) == B_INTERRUPTED) {
|
||||||
|
}
|
||||||
|
|
||||||
|
locker.Lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 events = fEventsOccurred;
|
||||||
|
fEventsOccurred = 0;
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
CliContext::_SignalInputLoop(uint32 events)
|
||||||
|
{
|
||||||
|
AutoLocker<BLocker> locker(fLock);
|
||||||
|
|
||||||
|
if ((fInputLoopWaitingForEvents & events) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fEventsOccurred = fInputLoopWaitingForEvents & events;
|
||||||
|
fInputLoopWaitingForEvents = 0;
|
||||||
|
|
||||||
|
if (fInputLoopWaiting) {
|
||||||
|
fInputLoopWaiting = false;
|
||||||
|
release_sem(fBlockingSemaphore);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -12,12 +12,21 @@
|
|||||||
|
|
||||||
#include <Locker.h>
|
#include <Locker.h>
|
||||||
|
|
||||||
|
#include "Team.h"
|
||||||
|
|
||||||
|
|
||||||
class Team;
|
class Team;
|
||||||
class UserInterfaceListener;
|
class UserInterfaceListener;
|
||||||
|
|
||||||
|
|
||||||
class CliContext {
|
class CliContext : private Team::Listener {
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
EVENT_QUIT = 0x01,
|
||||||
|
EVENT_USER_INTERRUPT = 0x02,
|
||||||
|
EVENT_THREAD_STATE_CHANGED = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CliContext();
|
CliContext();
|
||||||
~CliContext();
|
~CliContext();
|
||||||
@@ -40,6 +49,15 @@ public:
|
|||||||
void WaitForThreadOrUser();
|
void WaitForThreadOrUser();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Team::Listener
|
||||||
|
virtual void ThreadStateChanged(
|
||||||
|
const Team::ThreadEvent& event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _PrepareToWaitForEvents(uint32 eventMask);
|
||||||
|
uint32 _WaitForEvents();
|
||||||
|
void _SignalInputLoop(uint32 events);
|
||||||
|
|
||||||
static const char* _GetPrompt(EditLine* editLine);
|
static const char* _GetPrompt(EditLine* editLine);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -50,6 +68,8 @@ private:
|
|||||||
History* fHistory;
|
History* fHistory;
|
||||||
const char* fPrompt;
|
const char* fPrompt;
|
||||||
sem_id fBlockingSemaphore;
|
sem_id fBlockingSemaphore;
|
||||||
|
uint32 fInputLoopWaitingForEvents;
|
||||||
|
uint32 fEventsOccurred;
|
||||||
bool fInputLoopWaiting;
|
bool fInputLoopWaiting;
|
||||||
volatile bool fTerminating;
|
volatile bool fTerminating;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user