/* Filename: p1.c
 * Created on Tuesday, Feb. 5, 2002
 *
 * This program demonstrates
 *       How to create a set of semaphores,
 *       How to initialize the semaphores,
 *       How to decrement and increment the semaphore values, and
 *       How to remove semaphores from the system.
 *       
 * System calls to be used:
 *       semget: creates a set of semaphores or 
 *               gains access to an existing set of semaphores
 *       semctl: perform a number of control operations on existing semaphores
 *       semop:  increments and decrements the semaphore values
 *
 * Note: This program is trivial. It is not dealing with multiple processes. 
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h>

/* Solaris needs this semun definition. */
union semun {
  int              val;
  struct semid_ds *buf;
  ushort          *array;
};

int main() {
  int   mysemid;                         /* semaphore identifier */
  key_t mykey;                           /* key for a set of semaphores */
  ushort myarray[] = {1, 0, 0, 0};       /* Initial values for semaphores */
  union semun mysemun;
  struct sembuf mysembuf = { 0, 1, 0};   /* For semaphore operations */
  enum { sem_A, sem_B, sem_C, sem_D };   /* indexes to individual semaphores */

  /* Before creating a set of semaphores, a key value must be prepared. */
  mykey = ftok(".", 'A');  

  /* Then, a set of semaphores can be created using that key value. 
   * In this example, the set is going to contain 4 semaphores. 
   * If the semget call is successful, it will return a semaphore identifier,
   * which is a non-negative integer. Otherwise, -1 will be returned. 
   */ 
  printf("\nsemget: Creating a set of semaphores ");
  printf("using a key 0x%x and a mode 0666\n", mykey);
  mysemid = semget(mykey, 4, IPC_CREAT | 0666);
  if (mysemid == -1 ) {
    perror("semget: error");
    exit(1);  
  }
  printf("semget: Success. identifier for mysemid is %d\n\n", mysemid);

  /* Print information about active semaphores. */
  system("/usr/bin/ipcs -s"); 

  /* Initialize the semaphores. */
  printf("\nsemctl: Initializing the semaphores\n");
  mysemun.array = myarray;
  if (semctl(mysemid, 0, SETALL, mysemun) == -1) {
    perror("semctl: Failed to initialize semaphores.");
    exit(2);
  }
  printf("semctl: Successfully initialized\n");

  /* Silly examples of how to decrement and increment semaphore values */

  printf("\nsemop: Decrementing sem_A\n");
  mysembuf.sem_num = sem_A;    /* Operate on sem_A */
  mysembuf.sem_op = -1;        /* Decrement by 1   */ 
  mysembuf.sem_flg = 0; 
  if (semop(mysemid, &mysembuf, 1) == -1) {
    perror("semop: Failed to decrement sem_A");
    exit(3);
  }
  printf("semop: sem_A decremented\n");

  printf("\nsemop: Incrementing sem_A\n");
  mysembuf.sem_num = sem_A;    /* Operate on sem_A */
  mysembuf.sem_op =  1;        /* Increment by 1   */ 
  mysembuf.sem_flg = 0; 
  if (semop(mysemid, &mysembuf, 1) == -1) {
    perror("semop: Failed to increment sem_A");
    exit(3);
  }
  printf("semop: sem_A incremented\n");

  /* Remove a set of semaphores. */
  printf("\nsemctl: Removing a set of semaphores.  ");
  printf("identifier = %d\n", mysemid);
  if (semctl(mysemid, 0, IPC_RMID, 0) == -1) {
    perror("semctl: Failed to remove semaphores.");
    exit(3);
  }
  printf("semctl: Successfully removed semaphores.\n\n");

  /* Print information about active semaphores. */
  system("/usr/bin/ipcs -s"); 
  printf("\n");
  return 0;
}

