LCOV - code coverage report
Current view: top level - gfx/2d - JobScheduler.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 13 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #ifndef MOZILLA_GFX_TASKSCHEDULER_H_
       7             : #define MOZILLA_GFX_TASKSCHEDULER_H_
       8             : 
       9             : #include "mozilla/RefPtr.h"
      10             : #include "mozilla/gfx/Types.h"
      11             : #include "mozilla/RefCounted.h"
      12             : 
      13             : #ifdef WIN32
      14             : #include "mozilla/gfx/JobScheduler_win32.h"
      15             : #else
      16             : #include "mozilla/gfx/JobScheduler_posix.h"
      17             : #endif
      18             : 
      19             : #include <vector>
      20             : 
      21             : namespace mozilla {
      22             : namespace gfx {
      23             : 
      24             : class MultiThreadedJobQueue;
      25             : class SyncObject;
      26             : class WorkerThread;
      27             : 
      28           0 : class JobScheduler {
      29             : public:
      30             :   /// Return one of the queues that the drawing worker threads pull from, chosen
      31             :   /// pseudo-randomly.
      32           0 :   static MultiThreadedJobQueue* GetDrawingQueue()
      33             :   {
      34           0 :     return sSingleton->mDrawingQueues[
      35           0 :       sSingleton->mNextQueue++ % sSingleton->mDrawingQueues.size()
      36           0 :     ];
      37             :   }
      38             : 
      39             :   /// Return one of the queues that the drawing worker threads pull from with a
      40             :   /// hash to choose the queue.
      41             :   ///
      42             :   /// Calling this function several times with the same hash will yield the same queue.
      43             :   static MultiThreadedJobQueue* GetDrawingQueue(uint32_t aHash)
      44             :   {
      45             :     return sSingleton->mDrawingQueues[
      46             :       aHash % sSingleton->mDrawingQueues.size()
      47             :     ];
      48             :   }
      49             : 
      50             :   /// Return the task queue associated to the worker the task is pinned to if
      51             :   /// the task is pinned to a worker, or a random queue.
      52             :   static MultiThreadedJobQueue* GetQueueForJob(Job* aJob);
      53             : 
      54             :   /// Initialize the task scheduler with aNumThreads worker threads for drawing
      55             :   /// and aNumQueues task queues.
      56             :   ///
      57             :   /// The number of threads must be superior or equal to the number of queues
      58             :   /// (since for now a worker thread only pulls from one queue).
      59             :   static bool Init(uint32_t aNumThreads, uint32_t aNumQueues);
      60             : 
      61             :   /// Shut the scheduler down.
      62             :   ///
      63             :   /// This will block until worker threads are joined and deleted.
      64             :   static void ShutDown();
      65             : 
      66             :   /// Returns true if there is a successfully initialized JobScheduler singleton.
      67           0 :   static bool IsEnabled() { return !!sSingleton; }
      68             : 
      69             :   /// Submit a task buffer to its associated queue.
      70             :   ///
      71             :   /// The caller looses ownership of the task buffer.
      72             :   static void SubmitJob(Job* aJobs);
      73             : 
      74             :   /// Convenience function to block the current thread until a given SyncObject
      75             :   /// is in the signaled state.
      76             :   ///
      77             :   /// The current thread will first try to steal jobs before blocking.
      78             :   static void Join(SyncObject* aCompletionSync);
      79             : 
      80             :   /// Process commands until the command buffer needs to block on a sync object,
      81             :   /// completes, yields, or encounters an error.
      82             :   ///
      83             :   /// Can be used on any thread. Worker threads basically loop over this, but the
      84             :   /// main thread can also dequeue pending task buffers and process them alongside
      85             :   /// the worker threads if it is about to block until completion anyway.
      86             :   ///
      87             :   /// The caller looses ownership of the task buffer.
      88             :   static JobStatus ProcessJob(Job* aJobs);
      89             : 
      90             : protected:
      91             :   static JobScheduler* sSingleton;
      92             : 
      93             :   // queues of Job that are ready to be processed
      94             :   std::vector<MultiThreadedJobQueue*> mDrawingQueues;
      95             :   std::vector<WorkerThread*> mWorkerThreads;
      96             :   Atomic<uint32_t> mNextQueue;
      97             : };
      98             : 
      99             : /// Jobs are not reference-counted because they don't have shared ownership.
     100             : /// The ownership of tasks can change when they are passed to certain methods
     101             : /// of JobScheduler and SyncObject. See the docuumentaion of these classes.
     102             : class Job {
     103             : public:
     104             :   Job(SyncObject* aStart, SyncObject* aCompletion, WorkerThread* aThread = nullptr);
     105             : 
     106             :   virtual ~Job();
     107             : 
     108             :   virtual JobStatus Run() = 0;
     109             : 
     110             :   /// For use in JobScheduler::SubmitJob. Don't use it anywhere else.
     111             :   //already_AddRefed<SyncObject> GetAndResetStartSync();
     112           0 :   SyncObject* GetStartSync() { return mStartSync; }
     113             : 
     114           0 :   bool IsPinnedToAThread() const { return !!mPinToThread; }
     115             : 
     116           0 :   WorkerThread* GetWorkerThread() { return mPinToThread; }
     117             : 
     118             : protected:
     119             :   // An intrusive linked list of tasks waiting for a sync object to enter the
     120             :   // signaled state. When the task is not waiting for a sync object, mNextWaitingJob
     121             :   // should be null. This is only accessed from the thread that owns the task.
     122             :   Job* mNextWaitingJob;
     123             : 
     124             :   RefPtr<SyncObject> mStartSync;
     125             :   RefPtr<SyncObject> mCompletionSync;
     126             :   WorkerThread* mPinToThread;
     127             : 
     128             :   friend class SyncObject;
     129             : };
     130             : 
     131             : class EventObject;
     132             : 
     133             : /// This task will set an EventObject.
     134             : ///
     135             : /// Typically used as the final task, so that the main thread can block on the
     136             : /// corresponfing EventObject until all of the tasks are processed.
     137             : class SetEventJob : public Job
     138             : {
     139             : public:
     140             :   explicit SetEventJob(EventObject* aEvent,
     141             :                         SyncObject* aStart, SyncObject* aCompletion = nullptr,
     142             :                         WorkerThread* aPinToWorker = nullptr);
     143             : 
     144             :   ~SetEventJob();
     145             : 
     146             :   JobStatus Run() override;
     147             : 
     148             :   EventObject* GetEvent() { return mEvent; }
     149             : 
     150             : protected:
     151             :   RefPtr<EventObject> mEvent;
     152             : };
     153             : 
     154             : /// A synchronization object that can be used to express dependencies and ordering between
     155             : /// tasks.
     156             : ///
     157             : /// Jobs can register to SyncObjects in order to asynchronously wait for a signal.
     158             : /// In practice, Job objects usually start with a sync object (startSyc) and end
     159             : /// with another one (completionSync).
     160             : /// a Job never gets processed before its startSync is in the signaled state, and
     161             : /// signals its completionSync as soon as it finishes. This is how dependencies
     162             : /// between tasks is expressed.
     163             : class SyncObject final : public external::AtomicRefCounted<SyncObject> {
     164             : public:
     165           0 :   MOZ_DECLARE_REFCOUNTED_TYPENAME(SyncObject)
     166             : 
     167             :   /// Create a synchronization object.
     168             :   ///
     169             :   /// aNumPrerequisites represents the number of times the object must be signaled
     170             :   /// before actually entering the signaled state (in other words, it means the
     171             :   /// number of dependencies of this sync object).
     172             :   ///
     173             :   /// Explicitly specifying the number of prerequisites when creating sync objects
     174             :   /// makes it easy to start scheduling some of the prerequisite tasks while
     175             :   /// creating the others, which is how we typically use the task scheduler.
     176             :   /// Automatically determining the number of prerequisites using Job's constructor
     177             :   /// brings the risk that the sync object enters the signaled state while we
     178             :   /// are still adding prerequisites which is hard to fix without using muteces.
     179             :   explicit SyncObject(uint32_t aNumPrerequisites = 1);
     180             : 
     181             :   ~SyncObject();
     182             : 
     183             :   /// Attempt to register a task.
     184             :   ///
     185             :   /// If the sync object is already in the signaled state, the buffer is *not*
     186             :   /// registered and the sync object does not take ownership of the task.
     187             :   /// If the object is not yet in the signaled state, it takes ownership of
     188             :   /// the task and places it in a list of pending tasks.
     189             :   /// Pending tasks will not be processed by the worker thread.
     190             :   /// When the SyncObject reaches the signaled state, it places the pending
     191             :   /// tasks back in the available buffer queue, so that they can be
     192             :   /// scheduled again.
     193             :   ///
     194             :   /// Returns true if the SyncOject is not already in the signaled state.
     195             :   /// This means that if this method returns true, the SyncObject has taken
     196             :   /// ownership of the Job.
     197             :   bool Register(Job* aJob);
     198             : 
     199             :   /// Signal the SyncObject.
     200             :   ///
     201             :   /// This decrements an internal counter. The sync object reaches the signaled
     202             :   /// state when the counter gets to zero.
     203             :   void Signal();
     204             : 
     205             :   /// Returns true if mSignals is equal to zero. In other words, returns true
     206             :   /// if all prerequisite tasks have already signaled the sync object.
     207             :   bool IsSignaled();
     208             : 
     209             :   /// Asserts that the number of added prerequisites is equal to the number
     210             :   /// specified in the constructor (does nothin in release builds).
     211             :   void FreezePrerequisites();
     212             : 
     213             : private:
     214             :   // Called by Job's constructor
     215             :   void AddSubsequent(Job* aJob);
     216             :   void AddPrerequisite(Job* aJob);
     217             : 
     218             :   void AddWaitingJob(Job* aJob);
     219             : 
     220             :   void SubmitWaitingJobs();
     221             : 
     222             :   Atomic<int32_t> mSignals;
     223             :   Atomic<Job*> mFirstWaitingJob;
     224             : 
     225             : #ifdef DEBUG
     226             :   uint32_t mNumPrerequisites;
     227             :   Atomic<uint32_t> mAddedPrerequisites;
     228             : #endif
     229             : 
     230             :   friend class Job;
     231             :   friend class JobScheduler;
     232             : };
     233             : 
     234             : /// Base class for worker threads.
     235             : class WorkerThread
     236             : {
     237             : public:
     238             :   static WorkerThread* Create(MultiThreadedJobQueue* aJobQueue);
     239             : 
     240           0 :   virtual ~WorkerThread() {}
     241             : 
     242             :   void Run();
     243             : 
     244           0 :   MultiThreadedJobQueue* GetJobQueue() { return mQueue; }
     245             : 
     246             : protected:
     247             :   explicit WorkerThread(MultiThreadedJobQueue* aJobQueue);
     248             : 
     249           0 :   virtual void SetName(const char* aName) {}
     250             : 
     251             :   MultiThreadedJobQueue* mQueue;
     252             : };
     253             : 
     254             : } // namespace
     255             : } // namespace
     256             : 
     257             : #endif

Generated by: LCOV version 1.13