/* Filename: p2.c
 * Created on Tuesday, Feb. 5, 2002
 *
 * This program demonstrates
 *       How to create a shared memory segment,
 *       How to attach the shared memory,
 *       How to manipulate the shared memory segment,
 *       How to detach the shared memory segment, and
 *       How to remove the shared memory segment from the system.
 *
 * System calls to be used:
 *       shmget: creates a shared memory segment or gains access to an existing segment
 *       shmat:  attaches a shared memory segment into the calling process's data segment
 *       shmdt:  detaches the calling process's data segment from the shared mem segment
 *       shmctl: perform a number of control operations on an existing shared memory segment
 *
 * Note: This program is trivial because it is not dealing with multiple processes. 
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>

int main() {
  int   myshmid;                    /* shared mem identifier */
  key_t mykey;                      /* key  */
  int  *p_i;                        /* pointer to my shared data */
  int   mysize = sizeof(int);       /* size of shared memory */
  int   i; 

  /* Before creating shared memory segment, a key value must be prepared. */
  mykey = ftok(".", 'B');  

  /* Then, a shared memory segment can be created using that key value. 
   * If the shmget call is successful, it will return a non-negative integer.
   * Otherwise, -1 will be returned. 
   */ 
  printf("\nshmget: Creating a shared memory segment ");
  printf("using a key 0x%x and a mode 0666\n", mykey);
  myshmid = shmget(mykey, mysize, IPC_CREAT | 0666);
  if (myshmid == -1 ) {
    perror("shmget: error");
    exit(1);  
  }
  printf("shmget: Success. identifier for my shared mem is %d\n\n", myshmid);
  /* Print information about active shared mem. */
  system("/usr/bin/ipcs -m"); 

  /* Attach the shared memory segment to this process's data segment. */
  printf("\nshmat: Attaching shared mem segment\n");
  if ((p_i = (int *) shmat(myshmid, 0, 0)) == (int *) -1) {
    perror("shmat: Failed to attach.");
    exit(2);
  }
  printf("shmat: Successfully attached\n");

  /* Silly example of reading from and writing to the shared memory */
  *p_i = 100;
  for (i = 0; i < 10; i++) {
      *p_i = (*p_i) * i + 10;
  }

  /* Detach a shared mem segment. */
  if (shmdt((void *) p_i) == -1) {
    perror("shmdt: Failed to detach.");
    exit(3);
  }
  printf("shmdt: Successfully detached\n");
  
  /* Remove a shared mem segment. */
  printf("\nshmctl: Removing a shared mem segment.  identifier = %d\n", myshmid);
  if (shmctl(myshmid, IPC_RMID, 0) == -1) {
    perror("shmctl: Failed to remove shared mem segment.");
    exit(4);
  }
  printf("shmctl: Successfully removed shared mem segment.\n\n");
  /* Print information about active shared mem. */
  system("/usr/bin/ipcs -m"); 
  printf("\n");
  return 0;
}

