1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef PARTITION_ALLOC_STARSCAN_PCSCAN_INTERNAL_H_
6 #define PARTITION_ALLOC_STARSCAN_PCSCAN_INTERNAL_H_
7 
8 #include <array>
9 #include <functional>
10 #include <memory>
11 #include <mutex>
12 #include <unordered_map>
13 #include <utility>
14 #include <vector>
15 
16 #include "partition_alloc/internal_allocator_forward.h"
17 #include "partition_alloc/partition_alloc_base/memory/scoped_refptr.h"
18 #include "partition_alloc/partition_alloc_base/no_destructor.h"
19 #include "partition_alloc/starscan/pcscan.h"
20 #include "partition_alloc/starscan/starscan_fwd.h"
21 #include "partition_alloc/starscan/write_protector.h"
22 
23 namespace partition_alloc::internal {
24 
25 class PCScanTask;
26 
27 // Internal PCScan singleton. The separation between frontend and backend is
28 // needed to keep access to the hot data (quarantine) in the frontend fast,
29 // whereas the backend can hold cold data.
30 class PCScanInternal final {
31  public:
32   using Root = PCScan::Root;
33   using TaskHandle = scoped_refptr<PCScanTask>;
34 
35   using SuperPages =
36       std::vector<uintptr_t, internal::InternalAllocator<uintptr_t>>;
37   using RootsMap = std::unordered_map<
38       Root*,
39       SuperPages,
40       std::hash<Root*>,
41       std::equal_to<>,
42       internal::InternalAllocator<std::pair<Root* const, SuperPages>>>;
43 
Instance()44   static PCScanInternal& Instance() {
45     // Since the data that PCScanInternal holds is cold, it's fine to have the
46     // runtime check for thread-safe local static initialization.
47     static internal::base::NoDestructor<PCScanInternal> instance;
48     return *instance;
49   }
50 
51   PCScanInternal(const PCScanInternal&) = delete;
52   PCScanInternal& operator=(const PCScanInternal&) = delete;
53 
54   ~PCScanInternal();
55 
56   void Initialize(PCScan::InitConfig);
is_initialized()57   bool is_initialized() const { return is_initialized_; }
58 
59   void PerformScan(PCScan::InvocationMode);
60   void PerformScanIfNeeded(PCScan::InvocationMode);
61   void PerformDelayedScan(base::TimeDelta delay);
62   void JoinScan();
63 
64   TaskHandle CurrentPCScanTask() const;
65   void SetCurrentPCScanTask(TaskHandle task);
66   void ResetCurrentPCScanTask();
67 
68   void RegisterScannableRoot(Root*);
69   void RegisterNonScannableRoot(Root*);
70 
scannable_roots()71   RootsMap& scannable_roots() { return scannable_roots_; }
scannable_roots()72   const RootsMap& scannable_roots() const { return scannable_roots_; }
73 
nonscannable_roots()74   RootsMap& nonscannable_roots() { return nonscannable_roots_; }
nonscannable_roots()75   const RootsMap& nonscannable_roots() const { return nonscannable_roots_; }
76 
77   void RegisterNewSuperPage(Root* root, uintptr_t super_page_base);
78 
79   void SetProcessName(const char* name);
process_name()80   const char* process_name() const { return process_name_; }
81 
82   // Get size of all committed pages from scannable and nonscannable roots.
83   size_t CalculateTotalHeapSize() const;
84 
simd_support()85   SimdSupport simd_support() const { return simd_support_; }
86 
87   void EnableStackScanning();
88   void DisableStackScanning();
89   bool IsStackScanningEnabled() const;
90 
EnableImmediateFreeing()91   void EnableImmediateFreeing() { immediate_freeing_enabled_ = true; }
IsImmediateFreeingEnabled()92   bool IsImmediateFreeingEnabled() const { return immediate_freeing_enabled_; }
93 
94   bool WriteProtectionEnabled() const;
95   void ProtectPages(uintptr_t begin, size_t size);
96   void UnprotectPages(uintptr_t begin, size_t size);
97 
98   void ClearRootsForTesting();                // IN-TEST
99   void ReinitForTesting(PCScan::InitConfig);  // IN-TEST
100   void FinishScanForTesting();                // IN-TEST
101 
102   void RegisterStatsReporter(partition_alloc::StatsReporter* reporter);
103   partition_alloc::StatsReporter& GetReporter();
104 
105  private:
106   friend internal::base::NoDestructor<PCScanInternal>;
107   friend class StarScanSnapshot;
108 
109   PCScanInternal();
110 
111   TaskHandle current_task_;
112   mutable std::mutex current_task_mutex_;
113 
114   RootsMap scannable_roots_;
115   RootsMap nonscannable_roots_;
116   mutable std::mutex roots_mutex_;
117 
118   bool stack_scanning_enabled_{false};
119 
120   bool immediate_freeing_enabled_{false};
121 
122   const char* process_name_ = nullptr;
123   const SimdSupport simd_support_;
124 
125   std::unique_ptr<WriteProtector> write_protector_;
126   partition_alloc::StatsReporter* stats_reporter_ = nullptr;
127 
128   bool is_initialized_ = false;
129 };
130 
131 }  // namespace partition_alloc::internal
132 
133 #endif  // PARTITION_ALLOC_STARSCAN_PCSCAN_INTERNAL_H_
134