#ifndef LAB_EXCHANGE_H
#define LAB_EXCHANGE_H
#include <errno.h>
#include <semaphore.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>

struct exchange {
    sem_t request;
    sem_t reply;
    sem_t done;
    uint32_t value;
};

static inline int exchange_init(struct exchange *box)
{
    box->value = 0;
    if (sem_init(&box->request, 1, 0) == -1)
        return -1;
    if (sem_init(&box->reply, 1, 0) == -1) {
        int saved = errno;
        sem_destroy(&box->request);
        errno = saved;
        return -1;
    }
    if (sem_init(&box->done, 1, 0) == -1) {
        int saved = errno;
        sem_destroy(&box->reply);
        sem_destroy(&box->request);
        errno = saved;
        return -1;
    }
    return 0;
}

static inline int exchange_wait(sem_t *sem)
{
    struct timespec deadline;
    if (clock_gettime(CLOCK_REALTIME, &deadline) == -1)
        return -1;
    deadline.tv_sec += 15;
    int result;
    do {
        result = sem_timedwait(sem, &deadline);
    } while (result == -1 && errno == EINTR);
    return result;
}

static inline int exchange_server(struct exchange *box)
{
    if (exchange_wait(&box->request) == -1)
        return -1;
    if (box->value != 21) {
        errno = EPROTO;
        return -1;
    }
    box->value *= 2;
    if (sem_post(&box->reply) == -1)
        return -1;
    return exchange_wait(&box->done);
}

static inline int exchange_client(struct exchange *box)
{
    box->value = 21;
    if (sem_post(&box->request) == -1 ||
        exchange_wait(&box->reply) == -1)
        return -1;
    if (box->value != 42) {
        errno = EPROTO;
        return -1;
    }
    puts("reply=42");
    return sem_post(&box->done);
}

static inline int exchange_destroy(struct exchange *box)
{
    int result = 0;
    if (sem_destroy(&box->done) == -1)
        result = -1;
    if (sem_destroy(&box->reply) == -1)
        result = -1;
    if (sem_destroy(&box->request) == -1)
        result = -1;
    return result;
}
#endif
