aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIngo Weinhold <ingo_weinhold@gmx.de>2012-07-29 00:28:11 +0200
committerIngo Weinhold <ingo_weinhold@gmx.de>2012-07-29 00:28:56 +0200
commitd266c87d174fc714e2c0ecbfe9c18713f3c9215d (patch)
tree5486c558ed4d626004b7bc9c9183dda893a46ec4
parent4d8eaa5b11b21e3913b6937e298a7370c3e8c4f8 (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.cpp116
-rw-r--r--src/apps/debugger/user_interface/cli/CliContext.h22
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;
};