/*
 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
 *
 * This software is dual-licensed to you under the MIT License (MIT) and
 * the Universal Permissive License (UPL). See the LICENSE file in the root
 * directory for license terms. You may choose either license, or both.
 */

#include <errno.h>
#include <stdio.h>
#include <pthread.h>
#include "util/util_memory.h"
#include "iotcs_port_mutex.h"

#include "log/log.h"
#define IOTCSP_MODULE_LOG_CHANNEL LOG_CHANNEL_PORT_MUTEX
#include "log/log_template.h"

static void error_handler(int error, char* msg) {
    LOG_CRITS(msg);
    switch (error) {
        case EINVAL: LOG_CRITS(" Type - EINVAL");
            break;
        case EPERM: LOG_CRITS(" Type - EPERM");
            break;
        case EDEADLK: LOG_CRITS(" Type - EDEADLK");
            break;
        case ENOMEM: LOG_CRITS(" Type - ENOMEM");
            break;
        case EBUSY: LOG_CRITS(" Type - EBUSY");
            break;
        case EAGAIN: LOG_CRITS(" Type - EAGAIN");
            break;
        default: LOG_CRITS(" Type - UNKNOWN");
            break;
    }
}

iotcs_port_mutex iotcs_port_mutex_create(void) {
    pthread_mutex_t* mutex = (pthread_mutex_t*) util_malloc(sizeof (pthread_mutex_t));

    int ret = pthread_mutex_init(mutex, NULL);

    if (ret != 0) {
        error_handler(ret, "create_mutex failed - pthread_mutex_init");
        return NULL;
    }

    return (iotcs_port_mutex) mutex;
}

void iotcs_port_mutex_destroy(iotcs_port_mutex mutex) {
    if (mutex) {
        int ret = pthread_mutex_destroy(mutex);

        util_free(mutex);

        if (ret != 0) {
            error_handler(ret, "destroy_mutex failed - pthread_mutex_destroy");
        }
    }
}

void iotcs_port_mutex_lock(iotcs_port_mutex mutex) {
    int ret = pthread_mutex_lock(mutex);

    while (ret == EAGAIN) {
        ret = pthread_mutex_lock(mutex);
    }

    if (ret != 0) {
        error_handler(ret, "lock_mutex failed - iotcs_port_mutex_lock");
    }
}

void iotcs_port_mutex_unlock(iotcs_port_mutex mutex) {
    int ret = pthread_mutex_unlock(mutex);

    if (ret != 0) {
        error_handler(ret, "unlock_mutex failed - iotcs_port_mutex_unlock");
    }
}
