1 // Copyright 2024 Google LLC 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 #ifndef SANDBOXED_API_SANDBOX2_UTIL_DEADLINE_MANAGER_H_ 16 #define SANDBOXED_API_SANDBOX2_UTIL_DEADLINE_MANAGER_H_ 17 18 #include <cstddef> 19 #include <memory> 20 21 #include "absl/base/no_destructor.h" 22 #include "absl/base/thread_annotations.h" 23 #include "absl/container/btree_set.h" 24 #include "absl/flags/declare.h" 25 #include "absl/functional/function_ref.h" 26 #include "absl/strings/string_view.h" 27 #include "absl/synchronization/mutex.h" 28 #include "absl/time/time.h" 29 #include "sandboxed_api/util/thread.h" 30 31 ABSL_DECLARE_FLAG(int, sandbox2_deadline_manager_signal); 32 33 namespace sandbox2 { 34 35 class DeadlineManager; 36 37 // Interface for managing the deadline for a blocking syscall. The syscall 38 // should be interruptible by a signal. On deadline expiration deadline manager 39 // repeatedly sends a signal to the thread running potentially running the 40 // blocking syscall until the provided functor returns. This repetition resolves 41 // the race between signaling syscall execution and actually invoking the 42 // blocking syscall. 43 // 44 // If the deadline is unlikely to be changed between multiple blocking syscalls, 45 // it's more efficient to reuse a single registration object. 46 class DeadlineRegistration { 47 public: 48 explicit DeadlineRegistration(DeadlineManager& manager); 49 50 DeadlineRegistration(const DeadlineRegistration&) = delete; 51 DeadlineRegistration& operator=(const DeadlineRegistration&) = delete; 52 53 // ANDROID: move assignment operator of 'DeadlineRegistration' is implicitly 54 // deleted because field 'manager_' is of reference type 'DeadlineManager &' 55 DeadlineRegistration(DeadlineRegistration&&) = delete; 56 DeadlineRegistration& operator=(DeadlineRegistration&&) = delete; 57 58 ~DeadlineRegistration(); 59 60 // Executes a blocking syscall. 61 // The function is executed only if the deadline is not expired already. 62 // The syscall will be interrupted after the deadline. 63 void ExecuteBlockingSyscall(absl::FunctionRef<void()> blocking_fn); 64 65 // Sets the deadline for the blocking syscall. 66 // The deadline is rounded up to the next resolution boundary. 67 // Can be called from a different thread concurrently with a running blocking 68 // syscall. 69 void SetDeadline(absl::Time deadline); 70 71 private: 72 friend class DeadlineManager; 73 74 struct Data { 75 absl::Mutex mutex; 76 // Changed only under both DeadlineManager::queue_mutex_ and Data::mutex. 77 absl::Time deadline = absl::InfiniteFuture(); 78 pid_t ABSL_GUARDED_BY(mutex) tid = -1; 79 bool ABSL_GUARDED_BY(mutex) in_blocking_fn = false; 80 int ABSL_GUARDED_BY(mutex) notification_attempt = 0; 81 }; 82 83 DeadlineManager& manager_; 84 absl::Time last_deadline_ = absl::InfiniteFuture(); 85 std::unique_ptr<Data> data_ = std::make_unique<Data>(); 86 }; 87 88 // Engine for delivering deadline notifications to threads. Runs a separate 89 // thread which manages all the registered deadlines. 90 // All deadlines are rounded up to resolution of DeadlineManager (10 ms) for the 91 // purpose of batching notifications and reducing wakeups of the manager thread. 92 class DeadlineManager { 93 public: 94 // Returns the global instance of the deadline manager. instance()95 static DeadlineManager& instance() { 96 static absl::NoDestructor<DeadlineManager> manager{ 97 "deadline_manager-global"}; 98 return *manager; 99 } 100 // Creates and starts the manager. 101 explicit DeadlineManager(absl::string_view name); 102 103 DeadlineManager(const DeadlineManager&) = delete; 104 DeadlineManager& operator=(const DeadlineManager&) = delete; 105 106 DeadlineManager(DeadlineManager&&) = delete; 107 DeadlineManager& operator=(DeadlineManager&&) = delete; 108 109 ~DeadlineManager(); 110 111 // Adjusts the deadline for the registration. 112 // Prefer to use DeadlineRegistration::SetDeadline. 113 void AdjustDeadline(DeadlineRegistration& registration, absl::Time deadline); 114 115 private: 116 friend class DeadlineRegistration; 117 static constexpr absl::Duration kResolution = absl::Milliseconds(10); 118 119 struct ByDeadline { operatorByDeadline120 bool operator()(const DeadlineRegistration::Data* a, 121 const DeadlineRegistration::Data* b) const { 122 return a->deadline < b->deadline || (a->deadline == b->deadline && a < b); 123 } 124 }; 125 126 static void RegisterSignalHandler(); 127 static void SignalHandler(int signal); 128 static void VerifySignalHandler(); 129 Register(DeadlineRegistration & registration)130 void Register(DeadlineRegistration& registration) { 131 absl::MutexLock lock(®istration_mutex_); 132 ++registered_deadlines_; 133 } Unregister(DeadlineRegistration & registration)134 void Unregister(DeadlineRegistration& registration) { 135 { 136 absl::MutexLock lock(&queue_mutex_); 137 queue_.erase(registration.data_.get()); 138 } 139 absl::MutexLock lock(®istration_mutex_); 140 --registered_deadlines_; 141 } 142 void Run(); 143 144 static int signal_nr_; 145 sapi::Thread thread_; 146 absl::Mutex queue_mutex_; 147 bool cancelled_ ABSL_GUARDED_BY(queue_mutex_) = false; 148 // We only need an adjustable heap, but there is no widely available 149 // implementation ¯\_(ツ)_/¯. Asymptotically it's the same and it should not 150 // matter at our scale. 151 absl::btree_set<DeadlineRegistration::Data*, ByDeadline> ABSL_GUARDED_BY( 152 queue_mutex_) queue_; 153 absl::Mutex registration_mutex_; 154 size_t registered_deadlines_ ABSL_GUARDED_BY(registration_mutex_) = 0; 155 }; 156 157 } // namespace sandbox2 158 159 #endif // SANDBOXED_API_SANDBOX2_UTIL_DEADLINE_MANAGER_H_ 160