diff options
| author | Ingo Weinhold <ingo_weinhold@gmx.de> | 2012-07-29 00:28:11 +0200 |
|---|---|---|
| committer | Ingo Weinhold <ingo_weinhold@gmx.de> | 2012-07-29 00:28:56 +0200 |
| commit | d266c87d174fc714e2c0ecbfe9c18713f3c9215d (patch) | |
| tree | 5486c558ed4d626004b7bc9c9183dda893a46ec4 | |
| parent | 4d8eaa5b11b21e3913b6937e298a7370c3e8c4f8 (diff) | |
Debugger: CliContext: Introduce the notion of eventshrev44423
* 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().
| -rw-r--r-- | src/apps/debugger/user_interface/cli/CliContext.cpp | 116 | ||||
| -rw-r--r-- | src/apps/debugger/user_interface/cli/CliContext.h | 22 |
2 files changed, 121 insertions, 17 deletions
diff --git a/src/apps/debugger/user_interface/cli/CliContext.cpp b/src/apps/debugger/user_interface/cli/CliContext.cpp index ad14f82919..68b8e77d33 100644 --- a/src/apps/debugger/user_interface/cli/CliContext.cpp +++ b/src/apps/debugger/user_interface/cli/CliContext.cpp @@ -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); + } } diff --git a/src/apps/debugger/user_interface/cli/CliContext.h b/src/apps/debugger/user_interface/cli/CliContext.h index e3617fe6f7..0d5771edab 100644 --- a/src/apps/debugger/user_interface/cli/CliContext.h +++ b/src/apps/debugger/user_interface/cli/CliContext.h @@ -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; }; |
