
#include "producer_consumer_20011119.h"


int semid;
int shmid;

int removed_item = 0;

struct sembuf sops[SEM_NUM];

union semun arg;


int main() {

    /*--- pointer auf Shared Memory, erhält man von shmat() ---*/
    prod_con_shm_t *shmPtr;

    /*--- Erzeugung des Shm, falls noch nicht vorhanden,
          Rueckgabe ist die Shared Memory Id (vergleichbar
          mit Dateideskriptor ---*/ 
    if ( 0 > ( shmid = shmget(SHM_KEY,
                              sizeof(prod_con_shm_t),
                              (IPC_CREAT | SHM_PERM)) ) ) {
       perror("consumer: problem with shmget()");
       exit(1);
    }


    /*--- shmat() bildet das Shared Memory in den
          lokalen Adressraum ab, Anfangsadresse
          liegt auf dem Rueckgabewert shmPtr ---*/ 
    if ( 0 > ( shmPtr = shmat(shmid,0,0) ) ) {
       perror("consumer: problem with shmat()");
       exit(1);
    }

    printf("POINTER VALUE shmPtr %04X \n",(int)shmPtr);

    /*--- Erzeugen einer Semaphore, falls noch nicht vorhanden.
      Rueckgabe ist wieder ein "Dateideskriptor" ---*/ 
    if ( 0 > (semid = semget(SEM_KEY,
                             SEM_NUM,
                             (IPC_CREAT | SEM_PERM))) ) {
	perror("consumer: problem with semget()");
        exit(1);
    }

    printf("consumer: INITIALISE SEM_MUTEX=1 AND SEM_FULL = BUFFER_SIZE\n");
    

    /*--- die Vorinitialisierung aller Semaphor-Zähler ist 0.
          MUTEX und FULL muessen also auf 1 bzw BUFFER_SIZE
          gesetzt werden.
          ACHTUNG: falls mehrere Consumer aktiv sind, darf nur der erste
          die Initialisierung vornehmen ---*/ 
    memset(&arg, 0, sizeof(union semun)); 
    arg.val = 1;
    if ( 0 > semctl(semid,SEM_MUTEX,SETVAL,arg) ) {
        perror("consumer: problem with semctl(SEM_MUTEX)");
        exit(1);
    }
    arg.val = BUFFER_SIZE;
    if ( 0 > semctl(semid,SEM_FULL,SETVAL,arg) ) {
        perror("consumer: problem with semctl(SEM_FULL)");
        exit(1);
    }


    /*--- Consumer Schleife ---*/ 
    while(1) {
	printf("consumer: DOWN EMPTY and DOWN MUTEX\n");


        /*--- DOWN auf MUTEX und EMPTY kann als atomare Operation
              implementiert werden. Alternativ kann man beim
              producer.c sehen, wie die Befehle einzeln abgesetzt 
              werden koennen. ---*/  
	sops[0].sem_num = SEM_MUTEX;
	sops[0].sem_op = -1;
	sops[0].sem_flg = 0;  

	sops[1].sem_num = SEM_EMPTY;
	sops[1].sem_op = -1;
	sops[1].sem_flg = 0;  
 
	if ( 0 > semop(semid,&(sops[0]),2) ) {
	    perror("consumer: problem with semop()");
	    exit(1);
	}    


        /*--- nimm einen Item vom Stack ---*/ 
	printf("consumer: remove item %d\n",removed_item++);
        printf("consumer: %s\n", 
               &(shmPtr->userData
		 [--(shmPtr->numItemsInBuffer)][0]));
        
    
	printf("consumer: UP MUTEX and UP FULL\n");
    
   
	sops[0].sem_num = SEM_MUTEX;
	sops[0].sem_op = 1;
	sops[0].sem_flg = 0;  

	sops[1].sem_num = SEM_FULL;
	sops[1].sem_op = 1;
	sops[1].sem_flg = 0;  
 
	if ( 0 > semop(semid,&(sops[0]),2) ) {
	    perror("consumer: problem with semop()");
	    exit(1);
	}
    }

    exit(0);

}





