#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/errno.h>

// IPC Resource Keys  (both could be IPC_PRIVATE)
#define SHMKEY 	((key_t)7890)
#define SEMKEY 	((key_t)7891)

// Shared memory size
#define SHMSIZE	27

// Number of semaphores
#define NSEMS	2

// IPC Permissions (rw-rw-rw)
#define PERMS 	0666


main()
{
    int shmid,semid;
    char *a=""; // This will point to a shared memory buffer
    char *b=""; // "Normal" buffer (allocate by malloc)
    int pid,i;
    struct sembuf sop;
    
    // Get a shared memory segment
    if ((shmid = shmget(SHMKEY,SHMSIZE,PERMS|IPC_CREAT))<0) {
	perror("shmget");
	exit(1);
    }

    // Get Semaphores
    if ((semid=semget(SEMKEY,NSEMS,PERMS|IPC_CREAT))<0) {
	perror("semget");
	exit(1);
    }

    // Initialize Semaphores
    if (semctl(semid,0,SETVAL,0)<0 || semctl(semid,1,SETVAL,0)<0) {
	perror("semctl");
	exit(1);
    }

    // Now get a buffer and initialize it with some data
    b=malloc(SHMSIZE);
    for (i=0; i<SHMSIZE-1; i++) b[i]='a'+i;
    b[i]='\0';

    switch(pid = fork()) {

    case -1:
	perror("fork");
	exit(1);

    case 0:
	// Child - attach shared memory 
	if ((a=(char *)shmat(shmid,NULL,0)) == (char *) -1) {
	    perror("shmat");
	    exit(1);
	}

	// Wait(parent)
	sop.sem_num=1;
	sop.sem_op=-1;
	sop.sem_flg=0;
	if (semop(semid,&sop,1)) {
	    perror("semop");
	    exit(1);
	}

	//Scramble data in both private and shared memory
	printf("Child (before):A:<%s> B:<%s>\n",a,b);
	for (i=0;i<SHMSIZE-1;i++) {
	    a[i]='a'+i;
	    b[i]='z'-i;
	}
	a[i]='\0';
	b[i]='\0';

	printf("Child  (after):A:<%s> B:<%s>\n",a,b);

	// Detach Shared Memory
	if (shmdt(a)<0) {
	    perror("shmdt");
	    exit(1);
	}

	// Signal(Child)
	sop.sem_num=0;
	sop.sem_op=1;
	if (semop(semid,&sop,1)) {
	    perror("semop");
	    exit(1);
	}
	exit(0);
	
    default:
	// Parent - Attach Shared Memory
	if ((a = (char *)shmat(shmid,NULL,0)) ==(char *) -1) {
	    perror("shmat");
	    exit(1);
	}
	printf("Parent(before):A:<%s> B:<%s>\n",a,b);

	// Signal(Parent)
	sop.sem_num=1;
	sop.sem_op=1;
	sop.sem_flg=0;
	if (semop(semid,&sop,1)) {
	    perror("semop");
	    exit(1);
	}

	// Wait(Child) - Will modify shared area
	sop.sem_num=0;
	sop.sem_op=-1;
	if (semop(semid,&sop,1)) {
	    perror("semop");
	    exit(1);
	}

	printf("Parent (after):A:<%s> B:<%s>\n",a,b);
	if (shmdt(a)<0) {
	    perror("shmdt");
	    exit(1);
	}
    }

// ALWAYS REMOVE IPC RESOURCES
    semctl(semid,0,IPC_RMID);
    shmctl(shmid,IPC_RMID,NULL);
}