/*************************** 

 Biblioteca de funciones para el uso de semaforos en Unix.
 Las funciones regresan un valor de -1 en caso de que algo
 salga mal.  
****/


#include <errno.h>  /* libreria de errores */

/* Funcion que crea un arreglo de n semaforos con llave k */
int make_semas(k, n)
  key_t k; int n;
{

  int semid, i;

  /* Si ya existe un conjunto de de semaforos lo destruye  */
  if ((semid=semget(k, n, 0)) != -1)
     semctl(semid, 0, IPC_RMID);                    /* destruccion del semaforo */
  if ((semid=semget(k, n, IPC_CREAT | 0666)) != -1) {
     for (i=0;  i<n;  i++)
        V(semid, i);
  }
  else 
    return(-1); 
   return semid;
}

/* lock semaforo n del conjunto sem: P(sem[n]) */
P(sem, n) 
  int sem, n;
{
   struct sembuf sop;

   sop.sem_num = n;
   sop.sem_op = -1;
   sop.sem_flg = 0;
   semop(sem, &sop, 1);
} 

/* unlock semaforo n del conjunto sem: V(sem[n]) */
V(sem, n)
  int sem, n;
{
   struct sembuf sop;

   sop.sem_num = n;
   sop.sem_op = 1;
   sop.sem_flg = 0;
   semop(sem, &sop, 1);
}

/* regresa el valor del semaforo sem */
int imp_semval(sem)
  int sem;
{
  int semval;
  union{
    int              val;
    struct semid_ds  *buf;
    ushort           *array;
  } semctl_arg;
 
  semval = semctl(sem, 0,GETVAL, semctl_arg);
  if (semval < 0) 
    return(-1);
  else
    return(semval);
}

/* regresa el valor del semaforo n de  sem */
int valsem_n(sem,n )
  int sem, n;
{
  int semval;
  union{
    int              val;
    struct semid_ds  *buf;
    ushort           *array;
  } semctl_arg;
 
  semval = semctl(sem, n,GETVAL, semctl_arg);
  if (semval < 0)
    return(-1);
  else
    return(semval);
}

/* asigna el valor x, al semaforo n de sem */
int asig_val_sem(sem,n,x)
  int sem, x, n;
{

  union{
    int              val;
    struct semid_ds  *buf;
    ushort           *array;
  } semctl_arg;
  
  semctl_arg.val = x; 
  if (semctl(sem, n, SETVAL, semctl_arg) < 0) 
    return(-1);
  else
    return(0); 
}

/* Funcion que borra el semaforo especificado por sem */
int borra_sem(sem)
  int sem;
{
  int status;

  status = semctl(sem, 0, IPC_RMID);
  if (status < 0)
    return(-1);
  else
    return(status);
}
   
/* operacion general de semaforo, incrementa/decrementa el        */
/* valor especificado (postivo o negativo), pero no puede ser cero */
int sem_op(id, value)
 int  id, value;
{
  static struct sembuf  op_op[1] = {
      0, 99, SEM_UNDO    /* num =O op =99, flg = SEM_UNDO */ 
  };
 
  if ( (op_op[0].sem_op = value) == 0)
    return(-1); 
  else
    if (semop(id, &op_op[0], 1) < 0)
      printf("\n Error %d en el semop \n",errno);
}

/* Implemenmtacion del P(S) de Dijkstra o el DOWN de Tanenbaum */
sem_P(s)
  int s;
{
  sem_op(s, -1);
}

/* Implementacion del V(S) de Dijkstra o el UP de Tanenbaum */
sem_V(s)
  int s;
{
  sem_op(s, 1);
}	

