aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRene Gollent <anevilyak@gmail.com>2012-07-19 20:21:06 -0400
committerRene Gollent <anevilyak@gmail.com>2012-07-19 20:24:52 -0400
commit1f80f2eec3fcca13f5d0f4e146bde2058672a0ab (patch)
tree406b4ca9d3ea819c114efbd93b25ee65a4f11d42
parent02378956042046a9fc635820f73d2cbeb7a4b5df (diff)
- When a job needs to go dependent on another job, we no longer use recursion to manage the execution stack. Instead the job is simply marked as waiting and we execute other jobs with no dependencies in the meantime. When a job completes, all dependents are moved back onto the unscheduled list and executed as needed. - Adjustments to ResolveValueNodeJob to handle the now asynchronous nature of waiting.
-rw-r--r--src/apps/debugger/Jobs.cpp6
-rw-r--r--src/apps/debugger/Worker.cpp45
-rw-r--r--src/apps/debugger/Worker.h2
3 files changed, 28 insertions, 25 deletions
diff --git a/src/apps/debugger/Jobs.cpp b/src/apps/debugger/Jobs.cpp
index 0e812cc114..bfd2fe11dc 100644
--- a/src/apps/debugger/Jobs.cpp
+++ b/src/apps/debugger/Jobs.cpp
@@ -1,4 +1,5 @@
/*
+ * Copyright 2012, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@@ -523,6 +524,9 @@ ResolveValueNodeValueJob::_ResolveNodeValue()
fValueNode, fValueNode->Name().String(), parentNode);
return error;
}
+
+ if (State() == JOB_STATE_WAITING)
+ return B_OK;
}
// resolve the node child location, if necessary
@@ -629,6 +633,8 @@ ResolveValueNodeValueJob::_ResolveParentNodeValue(ValueNode* parentNode)
// "Not found" can happen due to a race condition between
// unlocking the worker and starting to wait.
break;
+ case JOB_DEPENDENCY_ACTIVE:
+ return B_OK;
case JOB_DEPENDENCY_FAILED:
case JOB_DEPENDENCY_ABORTED:
default:
diff --git a/src/apps/debugger/Worker.cpp b/src/apps/debugger/Worker.cpp
index dc1f06af09..409ff2b5b9 100644
--- a/src/apps/debugger/Worker.cpp
+++ b/src/apps/debugger/Worker.cpp
@@ -1,4 +1,5 @@
/*
+ * Copyright 2012, Rene Gollent, rene@gollent.com.
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
@@ -138,6 +139,15 @@ void
Job::SetWaitStatus(job_wait_status status)
{
fWaitStatus = status;
+ switch (fWaitStatus) {
+ case JOB_DEPENDENCY_ACTIVE:
+ fState = JOB_STATE_WAITING;
+ break;
+ default:
+ fState = JOB_STATE_ACTIVE;
+ break;
+
+ }
}
@@ -346,18 +356,6 @@ Worker::WaitForJob(Job* waitingJob, const JobKey& key)
waitingJob->SetDependency(job);
job->DependentJobs().Add(waitingJob);
- // TODO: Continuations would be nice. For the time being we have to use
- // recursion. Disadvantages are that we'll use more stack and that aborting
- // a job waiting for a dependency won't abort the job before the dependency
- // is done.
- locker.Unlock();
- _ProcessJobs(waitingJob);
- locker.Lock();
-
- // ignore the actual wait status when the game is over anyway
- if (fTerminating || waitingJob->State() == JOB_STATE_ABORTED)
- return JOB_DEPENDENCY_ABORTED;
-
return waitingJob->WaitStatus();
}
@@ -372,7 +370,7 @@ Worker::_WorkerLoopEntry(void* data)
status_t
Worker::_WorkerLoop()
{
- _ProcessJobs(NULL);
+ _ProcessJobs();
// clean up aborted jobs
AutoLocker<Worker> locker(this);
@@ -384,7 +382,7 @@ Worker::_WorkerLoop()
void
-Worker::_ProcessJobs(Job* waitingJob)
+Worker::_ProcessJobs()
{
while (true) {
AutoLocker<Worker> locker(this);
@@ -395,8 +393,10 @@ Worker::_ProcessJobs(Job* waitingJob)
status_t error = acquire_sem(fWorkToDoSem);
if (error != B_OK) {
- if (error == B_INTERRUPTED)
+ if (error == B_INTERRUPTED) {
+ locker.Lock();
continue;
+ }
break;
}
@@ -404,13 +404,9 @@ Worker::_ProcessJobs(Job* waitingJob)
}
// clean up aborted jobs
- while (Job* job = fAbortedJobs.RemoveHead()) {
+ while (Job* job = fAbortedJobs.RemoveHead())
_FinishJob(job);
- if (waitingJob != NULL && waitingJob->State() != JOB_STATE_WAITING)
- break;
- }
-
// process the next job
if (Job* job = fUnscheduledJobs.RemoveHead()) {
job->SetState(JOB_STATE_ACTIVE);
@@ -422,12 +418,10 @@ Worker::_ProcessJobs(Job* waitingJob)
if (job->State() == JOB_STATE_ACTIVE) {
job->SetState(
error == B_OK ? JOB_STATE_SUCCEEDED : JOB_STATE_FAILED);
- }
+ } else if (job->State() == JOB_STATE_WAITING)
+ continue;
_FinishJob(job);
-
- if (waitingJob != NULL && waitingJob->State() != JOB_STATE_WAITING)
- break;
}
}
}
@@ -492,7 +486,10 @@ Worker::_FinishJob(Job* job)
while (Job* dependentJob = job->DependentJobs().RemoveHead()) {
dependentJob->SetDependency(NULL);
dependentJob->SetWaitStatus(waitStatus);
+ fUnscheduledJobs.Add(dependentJob);
}
+
+ release_sem(fWorkToDoSem);
}
if (job->State() != JOB_STATE_ABORTED)
diff --git a/src/apps/debugger/Worker.h b/src/apps/debugger/Worker.h
index 241a3f4afa..7e356992a7 100644
--- a/src/apps/debugger/Worker.h
+++ b/src/apps/debugger/Worker.h
@@ -182,7 +182,7 @@ private:
static status_t _WorkerLoopEntry(void* data);
status_t _WorkerLoop();
- void _ProcessJobs(Job* waitingJob);
+ void _ProcessJobs();
void _AbortJob(Job* job, bool removeFromTable);
void _FinishJob(Job* job);