/* SPDX-License-Identifier: BSD-2-Clause */

#ifndef SRC_PKCS11_MUTEX_H_
#define SRC_PKCS11_MUTEX_H_
#include "config.h"
#include <assert.h>

#include "log.h"
#include "pkcs11.h"
#include "utils.h"

/**
 * Set's the mutex handlers. The mutex handlers default to internal
 * pthread mutexes unless specifically set, or cleared by setting NULL.
 * @param create
 *  The handler for creating a MUTEX.
 * @param destroy
 *  The handler for destroying a MUTEX.
 * @param lock
 *  The handler for locking a MUTEX.
 * @param unlock
 *  The handler for unlocking a MUTEX.
 */
void mutex_set_handlers(CK_CREATEMUTEX create,
        CK_DESTROYMUTEX destroy,
        CK_LOCKMUTEX lock,
        CK_UNLOCKMUTEX unlock);

/**
 * Allocates and initializes a mutex.
 * @param mutex
 *  The pointer to store the mutext at.
 * @return
 *  CKR_OK on success.
 */
CK_RV mutex_create(void **mutex);

/**
 * Deallocates and destroys a mutex.
 * @param mutex
 *  The mutex to deallocate.
 * @return
 *  CKR_OK on success.
 */
CK_RV mutex_destroy(void *mutex);

/**
 * locks a mutex.
 * @param mutex
 *  The mutex to lock.
 * @return
 *  CKR_OK on success.
 */
CK_RV mutex_lock(void *mutex);

/**
 * unlocks a mutex.
 * @param mutex
 *  The mutex to unlock.
 * @return
 *  CKR_OK on success.
 */
CK_RV mutex_unlock(void *mutex);

static inline void _mutex_lock_fatal(void *mutex) {

    CK_RV rv = mutex_lock(mutex);
    assert(rv == CKR_OK);
    UNUSED(rv);
}

static inline void _mutex_unlock_fatal(void *mutex) {

    CK_RV rv = mutex_unlock(mutex);
    assert(rv == CKR_OK);
    UNUSED(rv);
}

#ifndef NDEBUG
/*
 * debugging lock macros, the LOGV is on the top line to report lineno correctly
 */
#define mutex_lock_fatal(mutex) do { LOGV("LOCK(%p)-attempt", mutex); \
        _mutex_lock_fatal(mutex); \
        LOGV("LOCK(%p)-aquired", mutex); \
    } while (0)

#define mutex_unlock_fatal(mutex) do { LOGV("UNLOCK(%p)-attempt", mutex); \
        _mutex_unlock_fatal(mutex); \
        LOGV("UNLOCK(%p)-released", mutex); \
    } while (0)
#else
#define mutex_lock_fatal(mutex) _mutex_lock_fatal(mutex)
#define mutex_unlock_fatal(mutex) _mutex_unlock_fatal(mutex)
#endif
#endif /* SRC_PKCS11_MUTEX_H_ */
