lockguard.h 13.4 KB
/* ****************************************************************************
 * 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 <mutex>

// 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<std::mutex> 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<std::mutex> 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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::mutex> 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<std::mutex> 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