/* -*- 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 "mozilla/gfx/Logging.h" using namespace std; namespace mozilla { namespace gfx { void* ThreadCallback(void* threadData); class WorkerThreadPosix : public WorkerThread { public: explicit WorkerThreadPosix(MultiThreadedJobQueue* aJobQueue) : WorkerThread(aJobQueue) { pthread_create(&mThread, nullptr, ThreadCallback, static_cast(this)); } ~WorkerThreadPosix() { pthread_join(mThread, nullptr); } virtual void SetName(const char*) override { // XXX - temporarily disabled, see bug 1209039 // // // Call this from the thread itself because of Mac. //#ifdef XP_MACOSX // pthread_setname_np(aName); //#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) // pthread_set_name_np(mThread, aName); //#elif defined(__NetBSD__) // pthread_setname_np(mThread, "%s", (void*)aName); //#else // pthread_setname_np(mThread, aName); //#endif } protected: pthread_t mThread; }; void* ThreadCallback(void* threadData) { WorkerThread* thread = static_cast(threadData); thread->Run(); return nullptr; } WorkerThread* WorkerThread::Create(MultiThreadedJobQueue* aJobQueue) { return new WorkerThreadPosix(aJobQueue); } MultiThreadedJobQueue::MultiThreadedJobQueue() : mThreadsCount(0) , mShuttingDown(false) {} MultiThreadedJobQueue::~MultiThreadedJobQueue() { MOZ_ASSERT(mJobs.empty()); } bool MultiThreadedJobQueue::WaitForJob(Job*& aOutJob) { return PopJob(aOutJob, BLOCKING); } bool MultiThreadedJobQueue::PopJob(Job*& aOutJobs, AccessType aAccess) { for (;;) { CriticalSectionAutoEnter lock(&mMutex); while (aAccess == BLOCKING && !mShuttingDown && mJobs.empty()) { mAvailableCondvar.Wait(&mMutex); } if (mShuttingDown) { return false; } if (mJobs.empty()) { if (aAccess == NON_BLOCKING) { return false; } continue; } Job* task = mJobs.front(); MOZ_ASSERT(task); mJobs.pop_front(); aOutJobs = task; return true; } } void MultiThreadedJobQueue::SubmitJob(Job* aJobs) { MOZ_ASSERT(aJobs); CriticalSectionAutoEnter lock(&mMutex); mJobs.push_back(aJobs); mAvailableCondvar.Broadcast(); } size_t MultiThreadedJobQueue::NumJobs() { CriticalSectionAutoEnter lock(&mMutex); return mJobs.size(); } bool MultiThreadedJobQueue::IsEmpty() { CriticalSectionAutoEnter lock(&mMutex); return mJobs.empty(); } void MultiThreadedJobQueue::ShutDown() { CriticalSectionAutoEnter lock(&mMutex); mShuttingDown = true; while (mThreadsCount) { mAvailableCondvar.Broadcast(); mShutdownCondvar.Wait(&mMutex); } } void MultiThreadedJobQueue::RegisterThread() { mThreadsCount += 1; } void MultiThreadedJobQueue::UnregisterThread() { CriticalSectionAutoEnter lock(&mMutex); mThreadsCount -= 1; if (mThreadsCount == 0) { mShutdownCondvar.Broadcast(); } } EventObject::EventObject() : mIsSet(false) {} EventObject::~EventObject() {} bool EventObject::Peak() { CriticalSectionAutoEnter lock(&mMutex); return mIsSet; } void EventObject::Set() { CriticalSectionAutoEnter lock(&mMutex); if (!mIsSet) { mIsSet = true; mCond.Broadcast(); } } void EventObject::Wait() { CriticalSectionAutoEnter lock(&mMutex); if (mIsSet) { return; } mCond.Wait(&mMutex); } } // namespce } // namespce