diff options
Diffstat (limited to 'gfx/2d/JobScheduler.cpp')
-rw-r--r-- | gfx/2d/JobScheduler.cpp | 288 |
1 files changed, 0 insertions, 288 deletions
diff --git a/gfx/2d/JobScheduler.cpp b/gfx/2d/JobScheduler.cpp deleted file mode 100644 index 2c687cde0..000000000 --- a/gfx/2d/JobScheduler.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "JobScheduler.h" -#include "Logging.h" - -namespace mozilla { -namespace gfx { - -JobScheduler* JobScheduler::sSingleton = nullptr; - -bool JobScheduler::Init(uint32_t aNumThreads, uint32_t aNumQueues) -{ - MOZ_ASSERT(!sSingleton); - MOZ_ASSERT(aNumThreads >= aNumQueues); - - sSingleton = new JobScheduler(); - sSingleton->mNextQueue = 0; - - for (uint32_t i = 0; i < aNumQueues; ++i) { - sSingleton->mDrawingQueues.push_back(new MultiThreadedJobQueue()); - } - - for (uint32_t i = 0; i < aNumThreads; ++i) { - sSingleton->mWorkerThreads.push_back(WorkerThread::Create(sSingleton->mDrawingQueues[i%aNumQueues])); - } - return true; -} - -void JobScheduler::ShutDown() -{ - MOZ_ASSERT(IsEnabled()); - if (!IsEnabled()) { - return; - } - - for (auto queue : sSingleton->mDrawingQueues) { - queue->ShutDown(); - delete queue; - } - - for (WorkerThread* thread : sSingleton->mWorkerThreads) { - // this will block until the thread is joined. - delete thread; - } - - sSingleton->mWorkerThreads.clear(); - delete sSingleton; - sSingleton = nullptr; -} - -JobStatus -JobScheduler::ProcessJob(Job* aJob) -{ - MOZ_ASSERT(aJob); - auto status = aJob->Run(); - if (status == JobStatus::Error || status == JobStatus::Complete) { - delete aJob; - } - return status; -} - -void -JobScheduler::SubmitJob(Job* aJob) -{ - MOZ_ASSERT(aJob); - RefPtr<SyncObject> start = aJob->GetStartSync(); - if (start && start->Register(aJob)) { - // The Job buffer starts with a non-signaled sync object, it - // is now registered in the list of task buffers waiting on the - // sync object, so we should not place it in the queue. - return; - } - - GetQueueForJob(aJob)->SubmitJob(aJob); -} - -void -JobScheduler::Join(SyncObject* aCompletion) -{ - RefPtr<EventObject> waitForCompletion = new EventObject(); - JobScheduler::SubmitJob(new SetEventJob(waitForCompletion, aCompletion)); - waitForCompletion->Wait(); -} - -MultiThreadedJobQueue* -JobScheduler::GetQueueForJob(Job* aJob) -{ - return aJob->IsPinnedToAThread() ? aJob->GetWorkerThread()->GetJobQueue() - : GetDrawingQueue(); -} - -Job::Job(SyncObject* aStart, SyncObject* aCompletion, WorkerThread* aThread) -: mNextWaitingJob(nullptr) -, mStartSync(aStart) -, mCompletionSync(aCompletion) -, mPinToThread(aThread) -{ - if (mStartSync) { - mStartSync->AddSubsequent(this); - } - if (mCompletionSync) { - mCompletionSync->AddPrerequisite(this); - } -} - -Job::~Job() -{ - if (mCompletionSync) { - //printf(" -- Job %p dtor completion %p\n", this, mCompletionSync); - mCompletionSync->Signal(); - mCompletionSync = nullptr; - } -} - -JobStatus -SetEventJob::Run() -{ - mEvent->Set(); - return JobStatus::Complete; -} - -SetEventJob::SetEventJob(EventObject* aEvent, - SyncObject* aStart, SyncObject* aCompletion, - WorkerThread* aWorker) -: Job(aStart, aCompletion, aWorker) -, mEvent(aEvent) -{} - -SetEventJob::~SetEventJob() -{} - -SyncObject::SyncObject(uint32_t aNumPrerequisites) -: mSignals(aNumPrerequisites) -, mFirstWaitingJob(nullptr) -#ifdef DEBUG -, mNumPrerequisites(aNumPrerequisites) -, mAddedPrerequisites(0) -#endif -{} - -SyncObject::~SyncObject() -{ - MOZ_ASSERT(mFirstWaitingJob == nullptr); -} - -bool -SyncObject::Register(Job* aJob) -{ - MOZ_ASSERT(aJob); - - // For now, ensure that when we schedule the first subsequent, we have already - // created all of the prerequisites. This is an arbitrary restriction because - // we specify the number of prerequisites in the constructor, but in the typical - // scenario, if the assertion FreezePrerequisite blows up here it probably means - // we got the initial nmber of prerequisites wrong. We can decide to remove - // this restriction if needed. - FreezePrerequisites(); - - int32_t signals = mSignals; - - if (signals > 0) { - AddWaitingJob(aJob); - // Since Register and Signal can be called concurrently, it can happen that - // reading mSignals in Register happens before decrementing mSignals in Signal, - // but SubmitWaitingJobs happens before AddWaitingJob. This ordering means - // the SyncObject ends up in the signaled state with a task sitting in the - // waiting list. To prevent that we check mSignals a second time and submit - // again if signals reached zero in the mean time. - // We do this instead of holding a mutex around mSignals+mJobs to reduce - // lock contention. - int32_t signals2 = mSignals; - if (signals2 == 0) { - SubmitWaitingJobs(); - } - return true; - } - - return false; -} - -void -SyncObject::Signal() -{ - int32_t signals = --mSignals; - MOZ_ASSERT(signals >= 0); - - if (signals == 0) { - SubmitWaitingJobs(); - } -} - -void -SyncObject::AddWaitingJob(Job* aJob) -{ - // Push (using atomics) the task into the list of waiting tasks. - for (;;) { - Job* first = mFirstWaitingJob; - aJob->mNextWaitingJob = first; - if (mFirstWaitingJob.compareExchange(first, aJob)) { - break; - } - } -} - -void SyncObject::SubmitWaitingJobs() -{ - // Scheduling the tasks can cause code that modifies <this>'s reference - // count to run concurrently, and cause the caller of this function to - // be owned by another thread. We need to make sure the reference count - // does not reach 0 on another thread before the end of this method, so - // hold a strong ref to prevent that! - RefPtr<SyncObject> kungFuDeathGrip(this); - - // First atomically swap mFirstWaitingJob and waitingJobs... - Job* waitingJobs = nullptr; - for (;;) { - waitingJobs = mFirstWaitingJob; - if (mFirstWaitingJob.compareExchange(waitingJobs, nullptr)) { - break; - } - } - - // ... and submit all of the waiting tasks in waitingJob now that they belong - // to this thread. - while (waitingJobs) { - Job* next = waitingJobs->mNextWaitingJob; - waitingJobs->mNextWaitingJob = nullptr; - JobScheduler::GetQueueForJob(waitingJobs)->SubmitJob(waitingJobs); - waitingJobs = next; - } -} - -bool -SyncObject::IsSignaled() -{ - return mSignals == 0; -} - -void -SyncObject::FreezePrerequisites() -{ - MOZ_ASSERT(mAddedPrerequisites == mNumPrerequisites); -} - -void -SyncObject::AddPrerequisite(Job* aJob) -{ - MOZ_ASSERT(++mAddedPrerequisites <= mNumPrerequisites); -} - -void -SyncObject::AddSubsequent(Job* aJob) -{ -} - -WorkerThread::WorkerThread(MultiThreadedJobQueue* aJobQueue) -: mQueue(aJobQueue) -{ - aJobQueue->RegisterThread(); -} - -void -WorkerThread::Run() -{ - SetName("gfx worker"); - - for (;;) { - Job* commands = nullptr; - if (!mQueue->WaitForJob(commands)) { - mQueue->UnregisterThread(); - return; - } - - JobStatus status = JobScheduler::ProcessJob(commands); - - if (status == JobStatus::Error) { - // Don't try to handle errors for now, but that's open to discussions. - // I expect errors to be mostly OOM issues. - gfxDevCrash(LogReason::JobStatusError) << "Invalid job status " << (int)status; - } - } -} - -} //namespace -} //namespace |