lockguard.h 12.5 KB
/* Copyright (C) 2019
 *
 * This file is part of the osdev components suite
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
 */
#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