low_level_scheduling.h (4827B)
1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 // 15 // Core interfaces and definitions used by by low-level interfaces such as 16 // SpinLock. 17 18 #ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ 19 #define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_ 20 21 #include "absl/base/internal/raw_logging.h" 22 #include "absl/base/internal/scheduling_mode.h" 23 #include "absl/base/macros.h" 24 25 // The following two declarations exist so SchedulingGuard may friend them with 26 // the appropriate language linkage. These callbacks allow libc internals, such 27 // as function level statics, to schedule cooperatively when locking. 28 extern "C" bool __google_disable_rescheduling(void); 29 extern "C" void __google_enable_rescheduling(bool disable_result); 30 31 namespace absl { 32 ABSL_NAMESPACE_BEGIN 33 class CondVar; 34 class Mutex; 35 36 namespace synchronization_internal { 37 int MutexDelay(int32_t c, int mode); 38 } // namespace synchronization_internal 39 40 namespace base_internal { 41 42 class SchedulingHelper; // To allow use of SchedulingGuard. 43 class SpinLock; // To allow use of SchedulingGuard. 44 45 // SchedulingGuard 46 // Provides guard semantics that may be used to disable cooperative rescheduling 47 // of the calling thread within specific program blocks. This is used to 48 // protect resources (e.g. low-level SpinLocks or Domain code) that cooperative 49 // scheduling depends on. 50 // 51 // Domain implementations capable of rescheduling in reaction to involuntary 52 // kernel thread actions (e.g blocking due to a pagefault or syscall) must 53 // guarantee that an annotated thread is not allowed to (cooperatively) 54 // reschedule until the annotated region is complete. 55 // 56 // It is an error to attempt to use a cooperatively scheduled resource (e.g. 57 // Mutex) within a rescheduling-disabled region. 58 // 59 // All methods are async-signal safe. 60 class SchedulingGuard { 61 public: 62 // Returns true iff the calling thread may be cooperatively rescheduled. 63 static bool ReschedulingIsAllowed(); 64 SchedulingGuard(const SchedulingGuard&) = delete; 65 SchedulingGuard& operator=(const SchedulingGuard&) = delete; 66 67 private: 68 // Disable cooperative rescheduling of the calling thread. It may still 69 // initiate scheduling operations (e.g. wake-ups), however, it may not itself 70 // reschedule. Nestable. The returned result is opaque, clients should not 71 // attempt to interpret it. 72 // REQUIRES: Result must be passed to a pairing EnableScheduling(). 73 static bool DisableRescheduling(); 74 75 // Marks the end of a rescheduling disabled region, previously started by 76 // DisableRescheduling(). 77 // REQUIRES: Pairs with innermost call (and result) of DisableRescheduling(). 78 static void EnableRescheduling(bool disable_result); 79 80 // A scoped helper for {Disable, Enable}Rescheduling(). 81 // REQUIRES: destructor must run in same thread as constructor. 82 struct ScopedDisable { 83 ScopedDisable() { disabled = SchedulingGuard::DisableRescheduling(); } 84 ~ScopedDisable() { SchedulingGuard::EnableRescheduling(disabled); } 85 86 bool disabled; 87 }; 88 89 // A scoped helper to enable rescheduling temporarily. 90 // REQUIRES: destructor must run in same thread as constructor. 91 class ScopedEnable { 92 public: 93 ScopedEnable(); 94 ~ScopedEnable(); 95 96 private: 97 int scheduling_disabled_depth_; 98 }; 99 100 // Access to SchedulingGuard is explicitly permitted. 101 friend class absl::CondVar; 102 friend class absl::Mutex; 103 friend class SchedulingHelper; 104 friend class SpinLock; 105 friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode); 106 }; 107 108 //------------------------------------------------------------------------------ 109 // End of public interfaces. 110 //------------------------------------------------------------------------------ 111 112 inline bool SchedulingGuard::ReschedulingIsAllowed() { 113 return false; 114 } 115 116 inline bool SchedulingGuard::DisableRescheduling() { 117 return false; 118 } 119 120 inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) { 121 return; 122 } 123 124 inline SchedulingGuard::ScopedEnable::ScopedEnable() 125 : scheduling_disabled_depth_(0) {} 126 inline SchedulingGuard::ScopedEnable::~ScopedEnable() { 127 ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning"); 128 } 129 130 } // namespace base_internal 131 ABSL_NAMESPACE_END 132 } // namespace absl 133 134 #endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_