1 // Copyright (C) 2020 The Android Open Source Project 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 // http://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 #pragma once 15 16 #include <atomic> // for atomic_int 17 #include <unordered_map> // for unordere... 18 19 #include "aemu/base/synchronization/ConditionVariable.h" // for Conditio... 20 #include "aemu/base/synchronization/Lock.h" // for Lock 21 #include "aemu/base/synchronization/MessageChannel.h" // for MessageC... 22 23 namespace android { 24 namespace base { 25 26 typedef void (*MessageAvailableCallback)(void* opaque); 27 28 // A CallbackRegistry can be used to (un)register callbacks, the callbacks 29 // are invoked when the invokeCallbacks is called. A callback is guaranteed 30 // never to be called once unregisterCallback is returned. 31 // 32 // The expectation is that the invokeCallbacks method is called relatively 33 // frequently, since registration only really happens when this method is 34 // invoked. Unregister can block if processing is currently take place to 35 // guarantee that a callback is never called once unregisterCallback returns. 36 // 37 // Only one thread can be actively processing invokeCallbacks, other threads 38 // will block and wait until invokeCallbacks has completed. 39 // 40 // The MessageAvailableCallback functions should not block too long, as this can 41 // cause blocking on the unregister method and invokeCallbacks. 42 // 43 // It is expected that registration and procesessing happen on 44 // two separate threads. 45 class CallbackRegistry { 46 public: 47 CallbackRegistry() = default; 48 ~CallbackRegistry(); 49 50 // Registers the given callback under the `opaque` key. This does not block, 51 // unless the registration queue is filled up. |messageAvailable| Callback 52 // to register. |opaque| Key under which this callback is registered. 53 void registerCallback(MessageAvailableCallback messageAvailable, 54 void* opaque); 55 56 // Unregister the callback identiefied by the `opaque` key. You are 57 // guaranteed that the associated callback will not be invoked after this 58 // function returns. This call can block if: 59 // - processing is currently taking place. 60 // - the message queue is filled to capacity. 61 // 62 // You can safely delete opaque upon return. 63 // 64 // |opaque| Key under which this callback is registered. 65 void unregisterCallback(void* opaque); 66 67 // This will process all the registrations and invoke the callbacks. 68 void invokeCallbacks(); 69 70 // Close the registry, cancelling any pending registrations. 71 void close(); 72 73 // Number of register/unregister slots available before blocking. 74 // (Mainly used by unit tests to make sure we do not overrun the queue) 75 size_t available(); 76 77 // Maximum number of slots max_slots()78 size_t max_slots() { return MAX_QUEUE_SIZE; }; 79 80 // true if we are currently processing requests. processing()81 bool processing() { return mProcessing; } 82 83 private: 84 enum MessageForwarderCommand { 85 MESSAGE_FORWARDER_ADD = 0, 86 MESSAGE_FORWARDER_REMOVE = 1, 87 MESSAGE_UNKNOWN = 2, 88 }; 89 90 struct ForwarderMessage { 91 MessageForwarderCommand cmd; 92 void* data; 93 MessageAvailableCallback callback; 94 }; 95 96 void updateForwarders(); 97 98 static const size_t MAX_QUEUE_SIZE = 64; 99 android::base::MessageChannel<ForwarderMessage, MAX_QUEUE_SIZE> mMessages; 100 android::base::Lock mLock; // protects mStoredForwarders 101 android::base::Lock mProcessingLock; // protects processing. 102 android::base::ConditionVariable mCvRemoval; 103 std::unordered_map<void*, MessageAvailableCallback> mStoredForwarders; 104 bool mProcessing{false}; 105 }; 106 107 } // namespace base 108 } // namespace android 109