/* **************************************************************************** * Copyright 2019 Open Systems Development BV * * * * Permission is hereby granted, free of charge, to any person obtaining a * * copy of this software and associated documentation files (the "Software"), * * to deal in the Software without restriction, including without limitation * * the rights to use, copy, modify, merge, publish, distribute, sublicense, * * and/or sell copies of the Software, and to permit persons to whom the * * Software is furnished to do so, subject to the following conditions: * * * * The above copyright notice and this permission notice shall be included in * * all copies or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * * DEALINGS IN THE SOFTWARE. * * ***************************************************************************/ #ifndef OSDEV_COMPONENTS_MQTT_LOCKGUARD_H #define OSDEV_COMPONENTS_MQTT_LOCKGUARD_H // std #include // osdev::components::mqtt::measurement #include "measure.h" #include "utils.h" /** * @brief Enable the lock measurements when macro MEASURE_LOCKS is defined. * If the macro is not defined the NOP versions of the measure macros are used. */ #ifdef MEASURE_LOCKS #define OSDEV_COMPONENTS_MEASURELOCK OSDEV_COMPONENTS_MEASUREMENT_MEASURE #define OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC #else #define OSDEV_COMPONENTS_MEASURELOCK OSDEV_COMPONENTS_MEASUREMENT_MEASURE_NOP #define OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC OSDEV_COMPONENTS_MEASUREMENT_MEASURE_SPECIFIC_NOP #endif /** * @brief Create a lockguard for a given mutex in a specific context. * @param mutexVariableName The name of the mutex. * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex. * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances. */ #define OSDEV_COMPONENTS_LOCKGUARD_OBTAINER(mutexVariableName, mutexObtainer) \ OSDEV_COMPONENTS_MEASURELOCK(LOCKGUARD, std::lock_guard Lock__Guard__##mutexVariableName##__(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \ osdev::components::mqtt::apply_unused_parameters(Lock__Guard__##mutexVariableName##__); /** * @brief Create a lockguard for a given mutex in a specific context. * @param mutexVariableName The name of the mutex. * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex. * @param id The id that identifies this specific lock guard. Used for measuring timings. * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock. */ #define OSDEV_COMPONENTS_LOCKGUARD_SPECIFIC_OBTAINER(mutexVariableName, mutexObtainer, id) \ OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC(id, LOCKGUARD, std::lock_guard Lock__Guard__##mutexVariableName##__(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \ osdev::components::mqtt::apply_unused_parameters(Lock__Guard__##mutexVariableName##__); /** * @brief Create a lockguard for a given recursive mutex in a specific context. * @param mutexVariableName The name of the mutex. * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex. * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances. */ #define OSDEV_COMPONENTS_RECURSIVELOCKGUARD_OBTAINER(mutexVariableName, mutexObtainer) \ OSDEV_COMPONENTS_MEASURELOCK(RECURSIVELOCKGUARD, std::lock_guard Lock__Guard__##mutexVariableName##__(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \ osdev::components::mqtt::apply_unused_parameters(Lock__Guard__##mutexVariableName##__); /** * @brief Create a lockguard for a given recursive mutex in a specific context. * @param mutexVariableName The name of the mutex. * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex. * @param id The id that identifies this specific lock guard. Used for measuring timings. * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock. */ #define OSDEV_COMPONENTS_RECURSIVELOCKGUARD_SPECIFIC_OBTAINER(mutexVariableName, mutexObtainer, id) \ OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC(id, RECURSIVELOCKGUARD, std::lock_guard Lock__Guard__##mutexVariableName##__(mutexVariableName), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \ osdev::components::mqtt::apply_unused_parameters(Lock__Guard__##mutexVariableName##__); /** * @brief Create a lockguard for a given bare mutex in a specific context. * @param mutexVariableName The name of the mutex. * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances. */ #define OSDEV_COMPONENTS_LOCKGUARD(mutexVariableName) \ OSDEV_COMPONENTS_LOCKGUARD_OBTAINER(mutexVariableName, mutexVariableName) /** * @brief Create a lockguard for a given bare mutex in a specific context. * @param mutexVariableName The name of the mutex. * @param id The id that identifies this specific lock guard. Used for measuring timings. * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock. */ #define OSDEV_COMPONENTS_LOCKGUARD_SPECIFIC(mutexVariableName, id) \ OSDEV_COMPONENTS_LOCKGUARD_SPECIFIC_OBTAINER(mutexVariableName, mutexVariableName, id) /** * @brief Create a lockguard for a given bare recursive mutex in a specific context. * @param mutexVariableName The name of the mutex. * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances. */ #define OSDEV_COMPONENTS_RECURSIVELOCKGUARD(mutexVariableName) \ OSDEV_COMPONENTS_RECURSIVELOCKGUARD_OBTAINER(mutexVariableName, mutexVariableName) /** * @brief Create a lockguard for a given bare recursive mutex in a specific context. * @param mutexVariableName The name of the mutex. * @param id The id that identifies this specific lock guard. Used for measuring timings. * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances. */ #define OSDEV_COMPONENTS_RECURSIVELOCKGUARD_SPECIFIC(mutexVariableName, id) \ OSDEV_COMPONENTS_RECURSIVELOCKGUARD_SPECIFIC_OBTAINER(mutexVariableName, mutexVariableName, id) /** * @brief Defines the lock name that is used by the OSDEV_COMPONENTS_UNIQUELOCK_* macros */ #define OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName) Unique__Lock__##mutexVariableName##__ /** * @brief Create a uniqeue lock for a given mutex. * @param mutexVariableName The name of the mutex. * @param mutexObtainer The mutex to lock. This can also be a function that returns a mutex. * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances. */ #define OSDEV_COMPONENTS_UNIQUELOCK_CREATE_OBTAINER(mutexVariableName, mutexObtainer) \ OSDEV_COMPONENTS_MEASURELOCK(UNIQUELOCK_CREATE, std::unique_lock OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName)(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \ osdev::components::mqtt::apply_unused_parameters(OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName)); /** * @brief Create a uniqeue lock for a given mutex. * @param mutexVariableName The name of the mutex. * @param mutexObtainer The mutex to lock. This can also be a function that returns mutex. * @param id The id that identifies this specific lock guard. Used for measuring timings. * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock. */ #define OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC_OBTAINER(mutexVariableName, mutexObtainer, id) \ OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC(id, UNIQUELOCK_CREATE, std::unique_lock OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName)(mutexObtainer), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) \ osdev::components::mqtt::apply_unused_parameters(OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName)); /** * @brief Create a uniqeue lock for a given bare mutex. * @param mutexVariableName The name of the mutex. * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances. */ #define OSDEV_COMPONENTS_UNIQUELOCK_CREATE(mutexVariableName) \ OSDEV_COMPONENTS_UNIQUELOCK_CREATE_OBTAINER(mutexVariableName, mutexVariableName) /** * @brief Create a uniqeue lock for a given bare mutex. * @param mutexVariableName The name of the mutex. * @param id The id that identifies this specific unique lock. Used for measuring timings. * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock. */ #define OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC(mutexVariableName, id) \ OSDEV_COMPONENTS_UNIQUELOCK_CREATE_SPECIFIC_OBTAINER(mutexVariableName, mutexVariableName, id) /** * @brief Lock a given uniqeue lock. * @param mutexVariableName The name of the mutex from which the lockname is derived. * If MEASURE_LOCKS is enabled this method uses a static histogram to record the timing of obtaining the lock for all instances. */ #define OSDEV_COMPONENTS_UNIQUELOCK_LOCK(mutexVariableName) \ OSDEV_COMPONENTS_MEASURELOCK(UNIQUELOCK_LOCK, OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName).lock(), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) /** * @brief Lock a given uniqeue lock. * @param mutexVariableName The name of the mutex from which the lockname is derived. * @param id The id that identifies this specific unique lock guard. Used for measuring timings. * If MEASURE_LOCKS is enabled this method uses a specific histogram instance to record the timing of obtaining this lock. */ #define OSDEV_COMPONENTS_UNIQUELOCK_LOCK_SPECIFIC(mutexVariableName, id) \ OSDEV_COMPONENTS_MEASURELOCK_SPECIFIC(id, UNIQUELOCK_LOCK, OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName).lock(), osdev::components::mqtt::measure_locking_tag, osdev::components::mqtt::MeasureLockingValue, 100) /** * @brief Unlock a given uniqeue lock. * @param mutexVariableName The name of the mutex from which the lockname is derived. */ #define OSDEV_COMPONENTS_UNIQUELOCK_UNLOCK(mutexVariableName) \ OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName).unlock(); /** * @brief Unlock a given uniqeue lock. * @param mutexVariableName The name of the mutex from which the lockname is derived. * @param id The id that identifies this specific unique lock guard. Can be used for measuring timings. */ #define OSDEV_COMPONENTS_UNIQUELOCK_UNLOCK_SPECIFIC(mutexVariableName, id) \ OSDEV_COMPONENTS_UNIQUELOCK(mutexVariableName).unlock(); namespace osdev { namespace components { namespace mqtt { /** * @brief Context tag type. */ struct measure_locking_tag { }; /** * @brief Type for measuring lock timings * The unit is microseconds and the values are expected between 0 and 100 microseconds. * This type is used to construct a timing histogram. */ struct MeasureLockingValue { /** * @brief The value type of the timing value. */ using value_type = std::chrono::microseconds; const value_type minValue = value_type(0); ///< Constant mininum value. const value_type maxValue = value_type(100); ///< Constant maximum value. const char* unit = "us"; ///< The value unit. }; } // End namespace mqtt } // End namespace components } // End namespace osdev #endif // OSDEV_COMPONENTS_MQTT_LOCKGUARD_H