#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)" );
}
}