#include <errno.h>
#include <stdio.h>
#include <time.h>

#include "sem_wrapper.h"

errno_t sem_init_wrapped(sem_t *sem, int pshared, int initial_value)
{
    errno_t errnum;

    int r;
    r = sem_init(sem, pshared, initial_value);
    if (r == -1) {
        errnum = errno;
        perror("sem_init");
        return errnum;
    }

    return EOK;
}

errno_t sem_destroy_wrapped(sem_t *sem)
{
    errno_t errnum;

    int r;
    r = sem_destroy(sem);
    if (r == -1) {
        errnum = errno;
        perror("sem_destroy");
        return errnum;
    }

    return EOK;
}

errno_t sem_post_wrapped(sem_t *sem)
{
    errno_t errnum;

    int r;
    r = sem_post(sem);
    if (r == -1) {
        errnum = errno;
        perror("sem_post");
        return errnum;
    }

    return EOK;
}

static inline void clock_time_normalize(struct timespec *ts)
{
    while (ts->tv_nsec >= 1000000000) {
        ts->tv_nsec -= 1000000000;
        ++ts->tv_sec;
    }
}

errno_t sem_timedwait_wrapped(sem_t *sem, struct timespec *ts_interval)
{
    errno_t r;

    int errnum;

    struct timespec abstime;
    r = clock_gettime(CLOCK_REALTIME, &abstime);
    if (r == -1) {
        errnum = errno;
        perror("clock_gettime");
        return errnum;
    }
    abstime.tv_sec += ts_interval->tv_sec;
    abstime.tv_nsec += ts_interval->tv_nsec;

    clock_time_normalize(&abstime);

    do {
        r = sem_timedwait(sem, &abstime);
    } while ((r == -1) && (errno == EINTR));
    if (r == -1) {
        errnum = errno;
        perror("sem_timedwait");
        return errnum;
    }

    return EOK;
}

errno_t sem_getvalue_wrapped(sem_t *sem, int *value_ptr)
{
    errno_t errnum;

    int r;
    r = sem_getvalue(sem, value_ptr);
    if (r == -1) {
        errnum = errno;
        perror("sem_getvalue");
        return errnum;
    }

    return EOK;
}
