void ForegroundJobProcessor::RemoveManager(JobManager *const manager) { Assert(manager); // Managers must remove themselves. Hence, Close does not remove managers. So, not asserting on !IsClosed(). managers.Unlink(manager); if (manager->numJobsAddedToProcessor == 0) return; // Remove this manager's jobs from the queue Job *firstJob = 0; for (Job *job = jobs.Head(); job; job = job->Next()) { if (job->Manager() == manager) { if (!firstJob) firstJob = job; } else if (firstJob) { jobs.UnlinkSubsequence(firstJob, job->Previous()); for (Job *removedJob = firstJob; removedJob;) { Job *const next = removedJob->Next(); Assert(!removedJob->IsCritical()); JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards Assert(manager->numJobsAddedToProcessor != 0); --manager->numJobsAddedToProcessor; removedJob = next; } firstJob = 0; } } if (firstJob) { jobs.UnlinkSubsequenceFromEnd(firstJob); for (Job *removedJob = firstJob; removedJob;) { Job *const next = removedJob->Next(); Assert(!removedJob->IsCritical()); JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards Assert(manager->numJobsAddedToProcessor != 0); --manager->numJobsAddedToProcessor; removedJob = next; } } Assert(manager->numJobsAddedToProcessor == 0); LastJobProcessed(manager); }
void JobProcessor::PrioritizeManager(JobManager *const manager) { Assert(manager); Assert(!isClosed); managers.MoveToBeginning(manager); if (manager->numJobsAddedToProcessor == 0) { return; } // Move this manager's jobs to the beginning too. Find sequences of this manager's jobs backwards so that their relative // order remains intact after the sequences are moved. Job *const originalHead = jobs.Head(); Job *lastJob = 0; for (Job *job = jobs.Tail(); job; job = job->Previous()) { if (job->Manager() == manager) { if (!lastJob) lastJob = job; } else if (lastJob) { jobs.MoveSubsequenceToBeginning(job->Next(), lastJob); lastJob = 0; } if (job == originalHead) { break; } } if (lastJob) { jobs.MoveSubsequenceToBeginning(originalHead, lastJob); } }
void ForegroundJobProcessor::Close() { if (IsClosed()) return; for (Job *job = jobs.Head(); job;) { Job *const next = job->Next(); JobManager *const manager = job->Manager(); JobProcessed( manager, job, job->IsCritical() ? Process(job) : false); // the job may be deleted during this and should not be used afterwards Assert(manager->numJobsAddedToProcessor != 0); --manager->numJobsAddedToProcessor; if (manager->numJobsAddedToProcessor == 0) LastJobProcessed(manager); // the manager may be deleted during this and should not be used afterwards job = next; } jobs.Clear(); JobProcessor::Close(); }
void BackgroundJobProcessor::RemoveManager(JobManager *const manager) { Assert(manager); ParallelThreadData *threadDataProcessingCurrentJob = nullptr; { AutoCriticalSection lock(&criticalSection); // Managers must remove themselves. Hence, Close does not remove managers. So, not asserting on !IsClosed(). managers.Unlink(manager); if(manager->numJobsAddedToProcessor == 0) { Assert(!GetCurrentJobOfManager(manager)); return; } // Remove this manager's jobs from the queue Job *firstJob = 0; for(Job *job = jobs.Head(); job; job = job->Next()) { if(job->Manager() == manager) { if(!firstJob) firstJob = job; } else if(firstJob) { jobs.UnlinkSubsequence(firstJob, job->Previous()); for(Job *removedJob = firstJob; removedJob;) { Job *const next = removedJob->Next(); Assert(!removedJob->IsCritical()); Assert(numJobs != 0); --numJobs; JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards Assert(manager->numJobsAddedToProcessor != 0); --manager->numJobsAddedToProcessor; if(manager->isWaitable) { WaitableJobManager *const waitableManager = static_cast<WaitableJobManager *>(manager); if(waitableManager->jobBeingWaitedUpon == removedJob) { waitableManager->jobBeingWaitedUponProcessed.Set(); waitableManager->jobBeingWaitedUpon = 0; } } removedJob = next; } firstJob = 0; } } if(firstJob) { jobs.UnlinkSubsequenceFromEnd(firstJob); for(Job *removedJob = firstJob; removedJob;) { Job *const next = removedJob->Next(); Assert(!removedJob->IsCritical()); Assert(numJobs != 0); --numJobs; JobProcessed(manager, removedJob, false); // the job may be deleted during this and should not be used afterwards Assert(manager->numJobsAddedToProcessor != 0); --manager->numJobsAddedToProcessor; if(manager->isWaitable) { WaitableJobManager *const waitableManager = static_cast<WaitableJobManager *>(manager); if(waitableManager->jobBeingWaitedUpon == removedJob) { waitableManager->jobBeingWaitedUponProcessed.Set(); waitableManager->jobBeingWaitedUpon = 0; } } removedJob = next; } } if(manager->numJobsAddedToProcessor == 0) { LastJobProcessed(manager); return; } Assert(manager->numJobsAddedToProcessor >= 1); Assert(manager->isWaitable); Assert(GetCurrentJobOfManager(manager)); } //Wait for all the on going jobs to complete. criticalSection.Enter(); while (true) { Job *job = GetCurrentJobOfManager(manager); if (!job) { break; } WaitableJobManager * const waitableManager = static_cast<WaitableJobManager *>(manager); Assert(!waitableManager->jobBeingWaitedUpon); waitableManager->jobBeingWaitedUpon = job; waitableManager->jobBeingWaitedUponProcessed.Reset(); threadDataProcessingCurrentJob = GetThreadDataFromCurrentJob(waitableManager->jobBeingWaitedUpon); criticalSection.Leave(); WaitWithThread(threadDataProcessingCurrentJob, waitableManager->jobBeingWaitedUponProcessed); criticalSection.Enter(); waitableManager->jobBeingWaitedUpon = 0; } criticalSection.Leave(); }