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:
Ingo Weinhold 2012-07-29 00:28:11 +02:00
parent 4d8eaa5b11
commit d266c87d17
2 changed files with 121 additions and 17 deletions

View File

@ -28,16 +28,22 @@ CliContext::CliContext()
fHistory(NULL),
fPrompt(NULL),
fBlockingSemaphore(-1),
fInputLoopWaitingForEvents(0),
fEventsOccurred(0),
fInputLoopWaiting(false),
fTerminating(false)
{
sCurrentContext = this;
}
CliContext::~CliContext()
{
Cleanup();
sCurrentContext = NULL;
if (fBlockingSemaphore >= 0)
delete_sem(fBlockingSemaphore);
}
@ -47,6 +53,8 @@ CliContext::Init(Team* team, UserInterfaceListener* listener)
fTeam = team;
fListener = listener;
fTeam->AddListener(this);
status_t error = fLock.InitCheck();
if (error != B_OK)
return error;
@ -88,6 +96,11 @@ CliContext::Cleanup()
history_end(fHistory);
fHistory = NULL;
}
if (fTeam != NULL) {
fTeam->RemoveListener(this);
fTeam = NULL;
}
}
@ -97,13 +110,7 @@ CliContext::Terminating()
AutoLocker<BLocker> locker(fLock);
fTerminating = true;
if (fBlockingSemaphore >= 0) {
delete_sem(fBlockingSemaphore);
fBlockingSemaphore = -1;
}
fInputLoopWaiting = false;
_SignalInputLoop(EVENT_QUIT);
// TODO: Signal the input loop, should it be in PromptUser()!
}
@ -134,27 +141,104 @@ CliContext::AddLineToInputHistory(const char* line)
void
CliContext::QuitSession(bool killTeam)
{
AutoLocker<BLocker> locker(fLock);
sem_id blockingSemaphore = fBlockingSemaphore;
fInputLoopWaiting = true;
locker.Unlock();
_PrepareToWaitForEvents(EVENT_QUIT);
fListener->UserInterfaceQuitRequested(
killTeam
? UserInterfaceListener::QUIT_OPTION_ASK_KILL_TEAM
: UserInterfaceListener::QUIT_OPTION_ASK_RESUME_TEAM);
while (acquire_sem(blockingSemaphore) == B_INTERRUPTED) {
}
_WaitForEvents();
}
void
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);
}
}

View File

@ -12,12 +12,21 @@
#include <Locker.h>
#include "Team.h"
class Team;
class UserInterfaceListener;
class CliContext {
class CliContext : private Team::Listener {
public:
enum {
EVENT_QUIT = 0x01,
EVENT_USER_INTERRUPT = 0x02,
EVENT_THREAD_STATE_CHANGED = 0x04,
};
public:
CliContext();
~CliContext();
@ -40,6 +49,15 @@ public:
void WaitForThreadOrUser();
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);
private:
@ -50,6 +68,8 @@ private:
History* fHistory;
const char* fPrompt;
sem_id fBlockingSemaphore;
uint32 fInputLoopWaitingForEvents;
uint32 fEventsOccurred;
bool fInputLoopWaiting;
volatile bool fTerminating;
};