/* * Copyright (C) 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include // To dump the mutex code to stdout: // // $ clang++ -std=c++2a generate_mutex_order.cpp // $ ./a.out // constexpr const char* mutexes[] { // These mutexes obey partial ordering rules. // 1) AudioFlinger::mutex() -> PatchCommandThread::mutex() -> MelReporter::mutex(). // 2) If both AudioFlinger::mutex() and AudioFlinger::hardwareMutex() must be held, // always take mutex() before hardwareMutex(). // 3) AudioFlinger::clientMutex() protects mClients and mNotificationClients, // must be locked after mutex() and ThreadBase::mutex() if both must be locked // avoids acquiring AudioFlinger::mutex() from inside thread loop. // 4) AudioFlinger -> ThreadBase -> EffectChain -> EffectBase(EffectModule) // 5) EffectHandle -> ThreadBase -> EffectChain -> EffectBase(EffectModule) // 6) AudioFlinger::mutex() -> DeviceEffectManager -> DeviceEffectProxy -> EffectChain // -> AudioFlinger::hardwareMutex() when adding/removing effect to/from HAL // 7) AudioFlinger -> DeviceEffectManager -> DeviceEffectProxy -> DeviceEffectHandle "Spatializer_Mutex", // AP - must come before EffectHandle_Mutex "AudioPolicyEffects_Mutex", // AP - never hold AudioPolicyEffects_Mutex while calling APS, // not sure if this is still true. "EffectHandle_Mutex", // AF - must be after AudioPolicyEffects_Mutex "EffectBase_PolicyMutex", // AF - Held for AudioSystem::registerEffect, must come // after EffectHandle_Mutex and before AudioPolicyService_Mutex "AudioPolicyService_Mutex", // AP "CommandThread_Mutex", // AP "AudioCommand_Mutex", // AP "UidPolicy_Mutex", // AP "AudioFlinger_Mutex", // AF "DeviceEffectManager_Mutex", // AF "DeviceEffectProxy_ProxyMutex", // AF: used for device effects (which have no chain). "DeviceEffectHandle_Mutex", // AF: used for device effects when controlled internally. "PatchCommandThread_Mutex", // AF "ThreadBase_Mutex", // AF "AudioFlinger_ClientMutex", // AF "EffectChain_Mutex", // AF "EffectBase_Mutex", // AF "AudioFlinger_HardwareMutex", // AF: used for HAL, called from AF or DeviceEffectManager "MelReporter_Mutex", // AF // These mutexes are in leaf objects // and are presented afterwards in arbitrary order. "AudioFlinger_UnregisteredWritersMutex", // AF "AsyncCallbackThread_Mutex", // AF "ConfigEvent_Mutex", // AF "OutputTrack_TrackMetadataMutex", // AF "PassthruPatchRecord_ReadMutex", // AF "PatchCommandThread_ListenerMutex", // AF "PlaybackThread_AudioTrackCbMutex", // AF "AudioPolicyService_NotificationClientsMutex", // AP "MediaLogNotifier_Mutex", // AF "OtherMutex", // DO NOT CHANGE THIS: OtherMutex is used for mutexes without a specified order. // An OtherMutex will always be the lowest order mutex and cannot acquire // another named mutex while being held. }; using namespace std; // Utility program to print out the mutex // ordering and exclusion as listed above. int main() { cout << "// Lock order\n"; cout << "enum class MutexOrder : uint32_t {\n"; for (size_t i = 0; i < std::size(mutexes); ++i) { cout << " k" << mutexes[i] << " = " << i << ",\n"; } cout << " kSize = " << std::size(mutexes) << ",\n"; cout << "};\n"; cout << "\n// Lock by name\n"; cout << "inline constexpr const char* const gMutexNames[] = {\n"; for (size_t i = 0; i < std::size(mutexes); ++i) { cout << " \"" << mutexes[i] << "\",\n"; } cout << "};\n"; cout << "\n// Forward declarations\n"; cout << "class AudioMutexAttributes;\n"; cout << "template class mutex_impl;\n"; cout << "using mutex = mutex_impl;\n"; cout << "\n// Capabilities in priority order\n" << "// (declaration only, value is nullptr)\n"; const char *last = nullptr; for (auto mutex : mutexes) { if (last == nullptr) { cout << "inline mutex* " << mutex << ";\n"; } else { cout << "inline mutex* " << mutex << "\n ACQUIRED_AFTER(android::audio_utils::" << last << ");\n"; } last = mutex; } cout << "\n"; cout << "// Exclusion by capability\n"; last = nullptr; for (size_t i = 0; i < std::size(mutexes); ++i) { // exclusion is defined in reverse order of priority. auto mutex = mutexes[std::size(mutexes) - i - 1]; if (last == nullptr) { cout << "#define EXCLUDES_BELOW_" << mutex << "\n"; } else { cout << "#define EXCLUDES_BELOW_" << mutex << " \\\n EXCLUDES_" << last << "\n"; } cout << "#define EXCLUDES_" << mutex << " \\\n EXCLUDES(android::audio_utils::" << mutex << ")" << " \\\n EXCLUDES_BELOW_" << mutex << "\n\n"; last = mutex; } cout << "#define EXCLUDES_AUDIO_ALL" << " \\\n EXCLUDES_" << last << "\n\n"; return 0; }