/*
 * Implementação de mutex locks e variáveis de condição
 * utilizando semáforos.
 * Estrutura dinâmica para compartilhamento de semáforos.
 */

#include <stdlib.h>
#include "mutex_lista.h"

int mutex_init(mutex_t *lock, mutexattr_t* attr) {
  return sem_init(&lock->sem, 0, 1);
}

int mutex_destroy(mutex_t *lock) {
  return sem_destroy(&lock->sem);
}

int mutex_lock(mutex_t *lock) {
  return sem_wait(&lock->sem);
}

int mutex_unlock(mutex_t *lock) {
  return sem_post(&lock->sem);
}


/*------------------------------------------------------*/

int cond_init(cond_t *cond, condattr_t* attr) {
  mutex_init(&cond->lock, NULL);
  cond->signal = cond->wait = NULL;
  return 0;
}

int cond_destroy(cond_t *cond) {
  node_t *r;
  mutex_destroy(&cond->lock);
  if (cond->signal) {
    sem_destroy(&cond->signal->sem);
    sem_destroy(&cond->signal->sem);
    free(cond->signal);
  } 
  if (cond->wait) {
    sem_destroy(&cond->wait->sem);
    sem_destroy(&cond->wait->sem);
    free(cond->wait);
  } 
  return 0;
}

int cond_wait(cond_t *cond, 
              mutex_t *mutex_externo) {
  node_t* n;
  mutex_lock(&cond->lock);
  if (!cond->wait) {
    cond->wait = malloc(sizeof(node_t));
    sem_init(&n->sem, 0, 0);
    cond->n_wait = 0;
  }
  n = cond->wait;
  n->n_wait++;
  mutex_unlock(&cond->lock);                  
  mutex_unlock(mutex_externo);
  sem_wait(&n->sem);
  mutex_lock(&cond->lock);
  n->n_signal--;
  if (n->n_wait == 0 && n->n_signal == 0) {
    sem_destroy(&n->sem);
    free(n);
  }
  return 0;
}

int cond_signal(cond_t *cond){
  mutex_lock(&cond->lock);
  if (!cond->signal &&) {
    
|| cond->signal->n_wait <= cond->signal-> ) {
    sem_post(&cond->first->sem);
    cond->first = cond->first->next;
  }
  mutex_unlock(&cond->lock);
  return 0;  
}

int cond_broadcast(cond_t *cond){
  mutex_lock(&cond->lock);
  while (cond->first) {
    sem_post(&cond->first->sem);
    cond->first = cond->first->next;
  }
  mutex_unlock(&cond->lock);  
  return 0;  
}