DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Header

Mercurial (b6d82b1a6b02)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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"

namespace mozilla {
namespace gfx {

DWORD __stdcall ThreadCallback(void* threadData);

class WorkerThreadWin32 : public WorkerThread {
 public:
  explicit WorkerThreadWin32(MultiThreadedJobQueue* aJobQueue)
      : WorkerThread(aJobQueue) {
    mThread = ::CreateThread(nullptr, 0, ThreadCallback,
                             static_cast<WorkerThread*>(this), 0, nullptr);
  }

  virtual ~WorkerThreadWin32() {
    ::WaitForSingleObject(mThread, INFINITE);
    ::CloseHandle(mThread);
  }

 protected:
  HANDLE mThread;
};

DWORD __stdcall ThreadCallback(void* threadData) {
  WorkerThread* thread = static_cast<WorkerThread*>(threadData);
  thread->Run();
  return 0;
}

WorkerThread* WorkerThread::Create(MultiThreadedJobQueue* aJobQueue) {
  return new WorkerThreadWin32(aJobQueue);
}

bool MultiThreadedJobQueue::PopJob(Job*& aOutJob, AccessType aAccess) {
  for (;;) {
    while (aAccess == BLOCKING && mJobs.empty()) {
      {
        CriticalSectionAutoEnter lock(&mSection);
        if (mShuttingDown) {
          return false;
        }
      }

      HANDLE handles[] = {mAvailableEvent, mShutdownEvent};
      ::WaitForMultipleObjects(2, handles, FALSE, INFINITE);
    }

    CriticalSectionAutoEnter lock(&mSection);

    if (mShuttingDown) {
      return false;
    }

    if (mJobs.empty()) {
      if (aAccess == NON_BLOCKING) {
        return false;
      }
      continue;
    }

    Job* task = mJobs.front();
    MOZ_ASSERT(task);

    mJobs.pop_front();

    if (mJobs.empty()) {
      ::ResetEvent(mAvailableEvent);
    }

    aOutJob = task;
    return true;
  }
}

void MultiThreadedJobQueue::SubmitJob(Job* aJob) {
  MOZ_ASSERT(aJob);
  CriticalSectionAutoEnter lock(&mSection);
  mJobs.push_back(aJob);
  ::SetEvent(mAvailableEvent);
}

void MultiThreadedJobQueue::ShutDown() {
  {
    CriticalSectionAutoEnter lock(&mSection);
    mShuttingDown = true;
  }
  while (mThreadsCount) {
    ::SetEvent(mAvailableEvent);
    ::WaitForSingleObject(mShutdownEvent, INFINITE);
  }
}

size_t MultiThreadedJobQueue::NumJobs() {
  CriticalSectionAutoEnter lock(&mSection);
  return mJobs.size();
}

bool MultiThreadedJobQueue::IsEmpty() {
  CriticalSectionAutoEnter lock(&mSection);
  return mJobs.empty();
}

void MultiThreadedJobQueue::RegisterThread() { mThreadsCount += 1; }

void MultiThreadedJobQueue::UnregisterThread() {
  mSection.Enter();
  mThreadsCount -= 1;
  bool finishShutdown = mThreadsCount == 0;
  mSection.Leave();

  if (finishShutdown) {
    // Can't touch mSection or any other member from now on because this object
    // may get deleted on the main thread after mShutdownEvent is set.
    ::SetEvent(mShutdownEvent);
  }
}

}  // namespace gfx
}  // namespace mozilla