1 // Copyright 2018 The Chromium Authors. All rights reserved. 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 MEDIA_BASE_CALLBACK_REGISTRY_H_ 6 #define MEDIA_BASE_CALLBACK_REGISTRY_H_ 7 8 #include <stdint.h> 9 10 #include <map> 11 #include <memory> 12 13 #include "base/callback.h" 14 #include "base/logging.h" 15 #include "base/macros.h" 16 #include "base/synchronization/lock.h" 17 #include "base/thread_annotations.h" 18 #include "media/base/bind_to_current_loop.h" 19 20 namespace media { 21 22 // A class that keeps a callback registered. The callback will be unregistered 23 // upon destruction of this object. 24 class CallbackRegistration { 25 public: 26 CallbackRegistration() = default; 27 virtual ~CallbackRegistration() = default; 28 29 private: 30 DISALLOW_COPY_AND_ASSIGN(CallbackRegistration); 31 }; 32 33 template <typename Sig> 34 class CallbackRegistry; 35 36 // A helper class that can register, unregister callbacks, and notify registered 37 // callbacks. This class is thread safe: all methods can be called on any 38 // thread. The CallbackRegistry must outlive all CallbackRegistrations returned 39 // by Register(). 40 // TODO(xhwang): This class is similar to base::CallbackList, but is simpler, 41 // and provides thread safety. Consider merging these two. 42 template <typename... Args> 43 class CallbackRegistry<void(Args...)> { 44 public: 45 using CallbackType = base::RepeatingCallback<void(Args...)>; 46 47 CallbackRegistry() = default; 48 ~CallbackRegistry() = default; 49 Register(CallbackType cb)50 std::unique_ptr<CallbackRegistration> Register(CallbackType cb) 51 WARN_UNUSED_RESULT { 52 base::AutoLock lock(lock_); 53 DCHECK(cb); 54 uint32_t registration_id = ++next_registration_id_; 55 DVLOG(1) << __func__ << ": registration_id = " << registration_id; 56 57 // Use BindToCurrentLoop so that the callbacks are always posted to the 58 // thread where Register() is called. Also, this helps avoid reentrancy 59 // and deadlock issues, e.g. Register() is called in one of the callbacks. 60 callbacks_[registration_id] = BindToCurrentLoop(std::move(cb)); 61 62 return std::make_unique<RegistrationImpl>(this, registration_id); 63 } 64 Notify(Args &&...args)65 void Notify(Args&&... args) { 66 DVLOG(1) << __func__; 67 base::AutoLock lock(lock_); 68 for (auto const& entry : callbacks_) 69 entry.second.Run(std::forward<Args>(args)...); 70 } 71 72 private: 73 class RegistrationImpl : public CallbackRegistration { 74 public: RegistrationImpl(CallbackRegistry<void (Args...)> * registry,uint32_t registration_id)75 RegistrationImpl(CallbackRegistry<void(Args...)>* registry, 76 uint32_t registration_id) 77 : registry_(registry), registration_id_(registration_id) {} 78 ~RegistrationImpl()79 ~RegistrationImpl() override { registry_->Unregister(registration_id_); } 80 81 private: 82 CallbackRegistry<void(Args...)>* registry_ = nullptr; 83 uint32_t registration_id_ = 0; 84 85 DISALLOW_COPY_AND_ASSIGN(RegistrationImpl); 86 }; 87 Unregister(uint32_t registration_id)88 void Unregister(uint32_t registration_id) { 89 DVLOG(1) << __func__ << ": registration_id = " << registration_id; 90 base::AutoLock lock(lock_); 91 size_t num_callbacks_removed = callbacks_.erase(registration_id); 92 DCHECK_EQ(num_callbacks_removed, 1u); 93 } 94 95 base::Lock lock_; 96 uint32_t next_registration_id_ GUARDED_BY(lock_) = 0; 97 std::map<uint32_t, CallbackType> callbacks_ GUARDED_BY(lock_); 98 99 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry); 100 }; 101 102 using ClosureRegistry = CallbackRegistry<void()>; 103 104 } // namespace media 105 106 #endif // MEDIA_BASE_CALLBACK_REGISTRY_H_ 107