forked from mirrors/gecko-dev
		
	 126bd9e1a4
			
		
	
	
		126bd9e1a4
		
	
	
	
	
		
			
			This patch was generated automatically by the "modeline.py" script, available here: https://github.com/amccreight/moz-source-tools/blob/master/modeline.py For every file that is modified in this patch, the changes are as follows: (1) The patch changes the file to use the exact C++ mode lines from the Mozilla coding style guide, available here: https://developer.mozilla.org/en-US/docs/Mozilla/Developer_guide/Coding_Style#Mode_Line (2) The patch deletes any blank lines between the mode line & the MPL boilerplate comment. (3) If the file previously had the mode lines and MPL boilerplate in a single contiguous C++ comment, then the patch splits them into separate C++ comments, to match the boilerplate in the coding style. MozReview-Commit-ID: 77D61xpSmIl --HG-- extra : rebase_source : c6162fa3cf539a07177a19838324bf368faa162b
		
			
				
	
	
		
			258 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			258 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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/. */
 | |
| 
 | |
| #ifndef MOZILLA_GFX_TASKSCHEDULER_H_
 | |
| #define MOZILLA_GFX_TASKSCHEDULER_H_
 | |
| 
 | |
| #include "mozilla/RefPtr.h"
 | |
| #include "mozilla/gfx/Types.h"
 | |
| #include "mozilla/RefCounted.h"
 | |
| 
 | |
| #ifdef WIN32
 | |
| #include "mozilla/gfx/JobScheduler_win32.h"
 | |
| #else
 | |
| #include "mozilla/gfx/JobScheduler_posix.h"
 | |
| #endif
 | |
| 
 | |
| #include <vector>
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace gfx {
 | |
| 
 | |
| class MultiThreadedJobQueue;
 | |
| class SyncObject;
 | |
| class WorkerThread;
 | |
| 
 | |
| class JobScheduler {
 | |
| public:
 | |
|   /// Return one of the queues that the drawing worker threads pull from, chosen
 | |
|   /// pseudo-randomly.
 | |
|   static MultiThreadedJobQueue* GetDrawingQueue()
 | |
|   {
 | |
|     return sSingleton->mDrawingQueues[
 | |
|       sSingleton->mNextQueue++ % sSingleton->mDrawingQueues.size()
 | |
|     ];
 | |
|   }
 | |
| 
 | |
|   /// Return one of the queues that the drawing worker threads pull from with a
 | |
|   /// hash to choose the queue.
 | |
|   ///
 | |
|   /// Calling this function several times with the same hash will yield the same queue.
 | |
|   static MultiThreadedJobQueue* GetDrawingQueue(uint32_t aHash)
 | |
|   {
 | |
|     return sSingleton->mDrawingQueues[
 | |
|       aHash % sSingleton->mDrawingQueues.size()
 | |
|     ];
 | |
|   }
 | |
| 
 | |
|   /// Return the task queue associated to the worker the task is pinned to if
 | |
|   /// the task is pinned to a worker, or a random queue.
 | |
|   static MultiThreadedJobQueue* GetQueueForJob(Job* aJob);
 | |
| 
 | |
|   /// Initialize the task scheduler with aNumThreads worker threads for drawing
 | |
|   /// and aNumQueues task queues.
 | |
|   ///
 | |
|   /// The number of threads must be superior or equal to the number of queues
 | |
|   /// (since for now a worker thread only pulls from one queue).
 | |
|   static bool Init(uint32_t aNumThreads, uint32_t aNumQueues);
 | |
| 
 | |
|   /// Shut the scheduler down.
 | |
|   ///
 | |
|   /// This will block until worker threads are joined and deleted.
 | |
|   static void ShutDown();
 | |
| 
 | |
|   /// Returns true if there is a successfully initialized JobScheduler singleton.
 | |
|   static bool IsEnabled() { return !!sSingleton; }
 | |
| 
 | |
|   /// Submit a task buffer to its associated queue.
 | |
|   ///
 | |
|   /// The caller looses ownership of the task buffer.
 | |
|   static void SubmitJob(Job* aJobs);
 | |
| 
 | |
|   /// Convenience function to block the current thread until a given SyncObject
 | |
|   /// is in the signaled state.
 | |
|   ///
 | |
|   /// The current thread will first try to steal jobs before blocking.
 | |
|   static void Join(SyncObject* aCompletionSync);
 | |
| 
 | |
|   /// Process commands until the command buffer needs to block on a sync object,
 | |
|   /// completes, yields, or encounters an error.
 | |
|   ///
 | |
|   /// Can be used on any thread. Worker threads basically loop over this, but the
 | |
|   /// main thread can also dequeue pending task buffers and process them alongside
 | |
|   /// the worker threads if it is about to block until completion anyway.
 | |
|   ///
 | |
|   /// The caller looses ownership of the task buffer.
 | |
|   static JobStatus ProcessJob(Job* aJobs);
 | |
| 
 | |
| protected:
 | |
|   static JobScheduler* sSingleton;
 | |
| 
 | |
|   // queues of Job that are ready to be processed
 | |
|   std::vector<MultiThreadedJobQueue*> mDrawingQueues;
 | |
|   std::vector<WorkerThread*> mWorkerThreads;
 | |
|   Atomic<uint32_t> mNextQueue;
 | |
| };
 | |
| 
 | |
| /// Jobs are not reference-counted because they don't have shared ownership.
 | |
| /// The ownership of tasks can change when they are passed to certain methods
 | |
| /// of JobScheduler and SyncObject. See the docuumentaion of these classes.
 | |
| class Job {
 | |
| public:
 | |
|   Job(SyncObject* aStart, SyncObject* aCompletion, WorkerThread* aThread = nullptr);
 | |
| 
 | |
|   virtual ~Job();
 | |
| 
 | |
|   virtual JobStatus Run() = 0;
 | |
| 
 | |
|   /// For use in JobScheduler::SubmitJob. Don't use it anywhere else.
 | |
|   //already_AddRefed<SyncObject> GetAndResetStartSync();
 | |
|   SyncObject* GetStartSync() { return mStartSync; }
 | |
| 
 | |
|   bool IsPinnedToAThread() const { return !!mPinToThread; }
 | |
| 
 | |
|   WorkerThread* GetWorkerThread() { return mPinToThread; }
 | |
| 
 | |
| protected:
 | |
|   // An intrusive linked list of tasks waiting for a sync object to enter the
 | |
|   // signaled state. When the task is not waiting for a sync object, mNextWaitingJob
 | |
|   // should be null. This is only accessed from the thread that owns the task.
 | |
|   Job* mNextWaitingJob;
 | |
| 
 | |
|   RefPtr<SyncObject> mStartSync;
 | |
|   RefPtr<SyncObject> mCompletionSync;
 | |
|   WorkerThread* mPinToThread;
 | |
| 
 | |
|   friend class SyncObject;
 | |
| };
 | |
| 
 | |
| class EventObject;
 | |
| 
 | |
| /// This task will set an EventObject.
 | |
| ///
 | |
| /// Typically used as the final task, so that the main thread can block on the
 | |
| /// corresponfing EventObject until all of the tasks are processed.
 | |
| class SetEventJob : public Job
 | |
| {
 | |
| public:
 | |
|   explicit SetEventJob(EventObject* aEvent,
 | |
|                         SyncObject* aStart, SyncObject* aCompletion = nullptr,
 | |
|                         WorkerThread* aPinToWorker = nullptr);
 | |
| 
 | |
|   ~SetEventJob();
 | |
| 
 | |
|   JobStatus Run() override;
 | |
| 
 | |
|   EventObject* GetEvent() { return mEvent; }
 | |
| 
 | |
| protected:
 | |
|   RefPtr<EventObject> mEvent;
 | |
| };
 | |
| 
 | |
| /// A synchronization object that can be used to express dependencies and ordering between
 | |
| /// tasks.
 | |
| ///
 | |
| /// Jobs can register to SyncObjects in order to asynchronously wait for a signal.
 | |
| /// In practice, Job objects usually start with a sync object (startSyc) and end
 | |
| /// with another one (completionSync).
 | |
| /// a Job never gets processed before its startSync is in the signaled state, and
 | |
| /// signals its completionSync as soon as it finishes. This is how dependencies
 | |
| /// between tasks is expressed.
 | |
| class SyncObject final : public external::AtomicRefCounted<SyncObject> {
 | |
| public:
 | |
|   MOZ_DECLARE_REFCOUNTED_TYPENAME(SyncObject)
 | |
| 
 | |
|   /// Create a synchronization object.
 | |
|   ///
 | |
|   /// aNumPrerequisites represents the number of times the object must be signaled
 | |
|   /// before actually entering the signaled state (in other words, it means the
 | |
|   /// number of dependencies of this sync object).
 | |
|   ///
 | |
|   /// Explicitly specifying the number of prerequisites when creating sync objects
 | |
|   /// makes it easy to start scheduling some of the prerequisite tasks while
 | |
|   /// creating the others, which is how we typically use the task scheduler.
 | |
|   /// Automatically determining the number of prerequisites using Job's constructor
 | |
|   /// brings the risk that the sync object enters the signaled state while we
 | |
|   /// are still adding prerequisites which is hard to fix without using muteces.
 | |
|   explicit SyncObject(uint32_t aNumPrerequisites = 1);
 | |
| 
 | |
|   ~SyncObject();
 | |
| 
 | |
|   /// Attempt to register a task.
 | |
|   ///
 | |
|   /// If the sync object is already in the signaled state, the buffer is *not*
 | |
|   /// registered and the sync object does not take ownership of the task.
 | |
|   /// If the object is not yet in the signaled state, it takes ownership of
 | |
|   /// the task and places it in a list of pending tasks.
 | |
|   /// Pending tasks will not be processed by the worker thread.
 | |
|   /// When the SyncObject reaches the signaled state, it places the pending
 | |
|   /// tasks back in the available buffer queue, so that they can be
 | |
|   /// scheduled again.
 | |
|   ///
 | |
|   /// Returns true if the SyncOject is not already in the signaled state.
 | |
|   /// This means that if this method returns true, the SyncObject has taken
 | |
|   /// ownership of the Job.
 | |
|   bool Register(Job* aJob);
 | |
| 
 | |
|   /// Signal the SyncObject.
 | |
|   ///
 | |
|   /// This decrements an internal counter. The sync object reaches the signaled
 | |
|   /// state when the counter gets to zero.
 | |
|   void Signal();
 | |
| 
 | |
|   /// Returns true if mSignals is equal to zero. In other words, returns true
 | |
|   /// if all prerequisite tasks have already signaled the sync object.
 | |
|   bool IsSignaled();
 | |
| 
 | |
|   /// Asserts that the number of added prerequisites is equal to the number
 | |
|   /// specified in the constructor (does nothin in release builds).
 | |
|   void FreezePrerequisites();
 | |
| 
 | |
| private:
 | |
|   // Called by Job's constructor
 | |
|   void AddSubsequent(Job* aJob);
 | |
|   void AddPrerequisite(Job* aJob);
 | |
| 
 | |
|   void AddWaitingJob(Job* aJob);
 | |
| 
 | |
|   void SubmitWaitingJobs();
 | |
| 
 | |
|   Atomic<int32_t> mSignals;
 | |
|   Atomic<Job*> mFirstWaitingJob;
 | |
| 
 | |
| #ifdef DEBUG
 | |
|   uint32_t mNumPrerequisites;
 | |
|   Atomic<uint32_t> mAddedPrerequisites;
 | |
| #endif
 | |
| 
 | |
|   friend class Job;
 | |
|   friend class JobScheduler;
 | |
| };
 | |
| 
 | |
| /// Base class for worker threads.
 | |
| class WorkerThread
 | |
| {
 | |
| public:
 | |
|   static WorkerThread* Create(MultiThreadedJobQueue* aJobQueue);
 | |
| 
 | |
|   virtual ~WorkerThread() {}
 | |
| 
 | |
|   void Run();
 | |
| 
 | |
|   MultiThreadedJobQueue* GetJobQueue() { return mQueue; }
 | |
| 
 | |
| protected:
 | |
|   explicit WorkerThread(MultiThreadedJobQueue* aJobQueue);
 | |
| 
 | |
|   virtual void SetName(const char* aName) {}
 | |
| 
 | |
|   MultiThreadedJobQueue* mQueue;
 | |
| };
 | |
| 
 | |
| } // namespace
 | |
| } // namespace
 | |
| 
 | |
| #endif
 |