tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ParallelMarking.h (4445B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef gc_ParallelMarking_h
      8 #define gc_ParallelMarking_h
      9 
     10 #include "mozilla/Atomics.h"
     11 #include "mozilla/BitSet.h"
     12 #include "mozilla/Maybe.h"
     13 #include "mozilla/TimeStamp.h"
     14 
     15 #include "gc/GCMarker.h"
     16 #include "gc/GCParallelTask.h"
     17 #include "js/HeapAPI.h"
     18 #include "js/SliceBudget.h"
     19 #include "threading/ConditionVariable.h"
     20 #include "threading/ProtectedData.h"
     21 
     22 namespace js {
     23 
     24 class AutoLockHelperThreadState;
     25 
     26 namespace gc {
     27 
     28 class ParallelMarker;
     29 
     30 using ParallelTaskBitset = mozilla::BitSet<MaxParallelWorkers, uint32_t>;
     31 
     32 // A helper thread task that performs parallel marking.
     33 class alignas(TypicalCacheLineSize) ParallelMarkTask : public GCParallelTask {
     34 public:
     35  friend class ParallelMarker;
     36 
     37  ParallelMarkTask(ParallelMarker* pm, GCMarker* marker, MarkColor color,
     38                   uint32_t id, const JS::SliceBudget& budget);
     39  ~ParallelMarkTask();
     40 
     41  void run(AutoLockHelperThreadState& lock) override;
     42 
     43  using AtomicCount = mozilla::Atomic<uint32_t, mozilla::Relaxed>;
     44  AtomicCount& waitingTaskCountRef();
     45 
     46  void donateWork();
     47 
     48  void recordDuration() override;
     49 
     50 private:
     51  bool tryMarking(AutoLockHelperThreadState& lock);
     52  bool requestWork(AutoLockHelperThreadState& lock);
     53 
     54  void waitUntilResumed(AutoLockHelperThreadState& lock);
     55  void resume();
     56  void resumeOnFinish(const AutoLockHelperThreadState& lock);
     57 
     58  bool hasWork() const;
     59 
     60  // The following fields are only accessed by the marker thread:
     61  ParallelMarker* const pm;
     62  GCMarker* const marker;
     63  AutoSetMarkColor color;
     64  JS::SliceBudget budget;
     65  ConditionVariable resumed;
     66 
     67  const uint32_t id;
     68 
     69  HelperThreadLockData<bool> isWaiting;
     70 
     71  // Length of time this task spent blocked waiting for work.
     72  MainThreadOrGCTaskData<mozilla::TimeDuration> markTime;
     73  MainThreadOrGCTaskData<mozilla::TimeDuration> waitTime;
     74 };
     75 
     76 // Per-runtime parallel marking state.
     77 //
     78 // This class is used on the main thread and coordinates parallel marking using
     79 // several helper threads running ParallelMarkTasks.
     80 //
     81 // This uses a work-requesting approach. Threads mark until they run out of
     82 // work and then add themselves to a list of waiting tasks and block. Running
     83 // tasks with enough work may donate work to a waiting task and resume it.
     84 class MOZ_STACK_CLASS ParallelMarker {
     85 public:
     86  static bool mark(GCRuntime* gc, const JS::SliceBudget& sliceBudget);
     87 
     88  bool hasWaitingTasks() const { return !waitingTasks.IsEmpty(); }
     89 
     90  void donateWorkFrom(GCMarker* src);
     91 
     92 private:
     93  static bool markOneColor(GCRuntime* gc, MarkColor color,
     94                           const JS::SliceBudget& sliceBudget);
     95 
     96  explicit ParallelMarker(GCRuntime* gc, MarkColor color);
     97 
     98  bool mark(const JS::SliceBudget& sliceBudget);
     99 
    100  bool hasWork(MarkColor color) const;
    101 
    102  void addTask(ParallelMarkTask* task, const AutoLockHelperThreadState& lock);
    103 
    104  void addTaskToWaitingList(ParallelMarkTask* task,
    105                            const AutoLockHelperThreadState& lock);
    106 #ifdef DEBUG
    107  bool isTaskInWaitingList(const ParallelMarkTask* task,
    108                           const AutoLockHelperThreadState& lock) const;
    109 #endif
    110  ParallelMarkTask* takeWaitingTask();
    111 
    112  bool hasActiveTasks(const AutoLockHelperThreadState& lock) const {
    113    return !activeTasks.ref().IsEmpty();
    114  }
    115  void setTaskActive(ParallelMarkTask* task,
    116                     const AutoLockHelperThreadState& lock);
    117  void setTaskInactive(ParallelMarkTask* task,
    118                       const AutoLockHelperThreadState& lock);
    119 
    120  size_t workerCount() const;
    121 
    122  friend class ParallelMarkTask;
    123 
    124  GCRuntime* const gc;
    125 
    126  mozilla::Maybe<ParallelMarkTask> tasks[MaxParallelWorkers];
    127 
    128  // waitingTasks is written to with the lock held but can be read without.
    129  using WaitingTaskSet =
    130      mozilla::BitSet<MaxParallelWorkers,
    131                      mozilla::Atomic<uint32_t, mozilla::Relaxed>>;
    132  WaitingTaskSet waitingTasks;
    133 
    134  HelperThreadLockData<ParallelTaskBitset> activeTasks;
    135 
    136  const MarkColor color;
    137 };
    138 
    139 inline ParallelMarkTask::AtomicCount& ParallelMarkTask::waitingTaskCountRef() {
    140  return pm->waitingTasks.Storage()[0];
    141 }
    142 
    143 }  // namespace gc
    144 }  // namespace js
    145 
    146 #endif /* gc_ParallelMarking_h */