Universidad de Costa Rica

Escuela de Ciencias de la Computación e Informática

CI-0122 Sistemas Operativos

Temas

CI0122 / Temas revisados / Semana-06 / ForkAndSems / DP


#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include "Semaphore.h"

    union semun {
       int              val;    /* Value for SETVAL */
       struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
       unsigned short  *array;  /* Array for GETALL, SETALL */
       struct seminfo  *__buf;  /* Buffer for IPC_INFO (Linux-specific) */
    };


/**
 *  Constructs an array of n Unix semaphores initialized to zero
 * @param	int	semaphore quantity
 *
 */
    Semaphore::Semaphore( int n ) {
      int status;
      union semun value;

      id = semget( 0xECC1, n, 0600 | IPC_CREAT );
      this->nsems = n;

      value.val = 1;	// Each semaphore will be initialized to one 
      for ( int i = 0; i < this->nsems; i++ ) {
          status = semctl( id, i, SETVAL, value );
          if ( -1 == status ) {
             perror( "Semaphore::Semaphore(int)" );
          }
      }

    }


/**
 *  Constructs an array of n Unix semaphores initialized to zero using a base key
 * @param	int	key to be added to base key 0xECC1
 * @param	int	semaphore quantity
 *
 */
    Semaphore::Semaphore( int key, int n ) {
      int status;
      union semun value;

      id = semget( 0xECC1 + key, n, 0600 | IPC_CREAT );
      this->nsems = n;

      value.val = 1;
      for ( int i = 0; i < this->nsems; i++ ) {
          status = semctl( id, i, SETVAL, value );
          if ( -1 == status ) {
             perror( "Semaphore::Semaphore(int, int)" );
          }
      }

    }


/**
 * Destroys the semaphore array
 */
    Semaphore::~Semaphore() {
       int status;

       status = semctl( id, 0, IPC_RMID, NULL );
       if ( -1 == status ) {
          perror( "Semaphore::~Semaphore" );
       }

    }


/**
 * Signal operation on semaphore array, will try to add one to each semaphore in the array
 */
    void Semaphore::Signal() {
       int status;
       struct sembuf V[nsems];

       for ( int i = 0; i < nsems; i++ ) {
          V[i].sem_num = i;
          V[i].sem_op  = 1;
          V[i].sem_flg = 0;
       }
       status = semop( id, V, nsems );
       if ( -1 == status ) {
          perror( "Semaphore::Semaphore(int, int)" );
       }
    } 

  
/**
 * Wait operation on semaphore array, will try to substract one to each semaphore in the array
 */
    void Semaphore::Wait() {
       int status;
       struct sembuf P[nsems];

       for ( int i = 0; i < nsems; i++ ) {
          P[i].sem_num = i;
          P[i].sem_op  = -1;
          P[i].sem_flg = 0;
       }
       status = semop( id, P, nsems );
       if ( -1 == status ) {
          perror( "Semaphore::Semaphore(int, int)" );
       }

    }



/**
 * Do a Wait operation on two semaphores, will try to substract one to each semaphore
 * This operation must be atomic, not allowed to block one semaphore and try to block the other
 * The block operation must occur on both semaphores atomically
 */
    void Semaphore::SP( int first, int second ) {
       int status;
       struct sembuf P[ 2 ];

       P[ 0 ].sem_num = first;
       P[ 0 ].sem_op  = -1;
       P[ 0 ].sem_flg = 0;

       P[ 1 ].sem_num = second;
       P[ 1 ].sem_op  = -1;
       P[ 1 ].sem_flg = 0;

       status = semop( this->id, P, 2 );
       if ( -1 == status ) {
          perror( "Semaphore::SP(int, int)" );
       }
    }


/**
 * Do a Signal operation on two semaphores, will try to substract one to each semaphore
 * This operation must be atomic, not allowed to block one semaphore and try to block the other
 * The block operation must occur on both semaphores atomically
 */
    void Semaphore::SV( int first, int second ) {
       int status;
       struct sembuf V[ 2 ];

       V[ 0 ].sem_num = first;
       V[ 0 ].sem_op  = 1;
       V[ 0 ].sem_flg = 0;

       V[ 1 ].sem_num = second;
       V[ 1 ].sem_op  = 1;
       V[ 1 ].sem_flg = 0;

       status = semop( this->id, V, 2 );
       if ( -1 == status ) {
          perror( "Semaphore::SV(int, int)" );
       }
    }