| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_COOPERATIVE_SCHEDULING_MANAGER_H_ |
| #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_COOPERATIVE_SCHEDULING_MANAGER_H_ |
| |
| #include "base/time/tick_clock.h" |
| #include "third_party/blink/renderer/platform/platform_export.h" |
| #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" |
| |
| namespace blink { |
| namespace scheduler { |
| |
| // This class manages the states for cooperative scheduling and decides whether |
| // or not to run a nested loop for reentrant JS execution in cross-site frames. |
| class PLATFORM_EXPORT CooperativeSchedulingManager { |
| USING_FAST_MALLOC(CooperativeSchedulingManager); |
| |
| public: |
| // Reentrant JS execution is not allowed unless there is an instance of this |
| // scoper alive. This is to ensure that reentrant JS execution can only happen |
| // in C++ stacks with a simple, known state. |
| class PLATFORM_EXPORT AllowedStackScope { |
| STACK_ALLOCATED(); |
| |
| public: |
| explicit AllowedStackScope(CooperativeSchedulingManager*); |
| ~AllowedStackScope(); |
| |
| private: |
| CooperativeSchedulingManager* const cooperative_scheduling_manager_; |
| }; |
| |
| // Returns an shared instance for the current thread. |
| static CooperativeSchedulingManager* Instance(); |
| |
| CooperativeSchedulingManager(); |
| virtual ~CooperativeSchedulingManager() = default; |
| |
| // Returns true if reentry is allowed in the current C++ stack. |
| bool InAllowedStackScope() const { return allowed_stack_scope_depth_ > 0; } |
| |
| // Calls to this should be inserted where nested loops can be run safely. |
| // Typically this is is where Blink has not modified any global state that the |
| // nested code could touch. |
| void Safepoint(); |
| |
| // The caller is the owner of the |clock|. The |clock| must outlive the |
| // CooperativeSchedulingManager. |
| void SetTickClockForTesting(const base::TickClock* clock); |
| |
| void set_feature_enabled(bool enabled) { feature_enabled_ = enabled; } |
| |
| protected: |
| virtual void RunNestedLoop(); |
| |
| private: |
| void EnterAllowedStackScope(); |
| void LeaveAllowedStackScope(); |
| void SafepointSlow(); |
| |
| int allowed_stack_scope_depth_ = 0; |
| bool running_nested_loop_ = false; |
| base::TimeTicks wait_until_; |
| const base::TickClock* clock_; |
| bool feature_enabled_ = true; |
| |
| DISALLOW_COPY_AND_ASSIGN(CooperativeSchedulingManager); |
| }; |
| |
| inline void CooperativeSchedulingManager::Safepoint() { |
| if (!InAllowedStackScope()) |
| return; |
| |
| if (clock_->NowTicks() < wait_until_) |
| return; |
| |
| SafepointSlow(); |
| } |
| |
| } // namespace scheduler |
| } // namespace blink |
| |
| #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_SCHEDULER_PUBLIC_COOPERATIVE_SCHEDULING_MANAGER_H_ |