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:
parent
4d8eaa5b11
commit
d266c87d17
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue