/*
 * producer.c
 *
 * abgeleitet aus
 * http://users.actcom.co.il/~choo/lupg/tutorials/multi-process/sem-mutex.c
 * Beschreibung: http://users.actcom.co.il/~choo/lupg/tutorials/multi-process/
 * multi-process.html
 * Änderungen: H.-G. Eßer
 */

#include <stdio.h>	 /* standard I/O routines.              */
#include <stdlib.h>      /* rand() and srand() functions        */
#include <unistd.h>	 /* fork(), etc.                        */
#include <time.h>	 /* nanosleep(), etc.                   */
#include <sys/types.h>   /* various type definitions.           */
#include <sys/ipc.h>     /* general SysV IPC structures         */
#include <sys/sem.h>	 /* semaphore functions and structs.    */

#define NUM_LOOPS	20	 /* number of loops to perform. */

union semun { int val; struct semid_ds *buf; unsigned short  *array; };

int main(int argc, char* argv[])
{
    int sem_set_id;	      /* ID of the semaphore set.       */
    key_t semkey;             /* key for named semaphore set    */
    union semun sem_val;      /* semaphore value, for semctl(). */
    int child_pid;	      /* PID of our child process.      */
    int i;		      /* counter for loop operation.    */
    struct sembuf sem_op;     /* structure for semaphore ops.   */
    int rc;		      /* return value of system calls.  */
    struct timespec delay;    /* used for wasting time.         */

    /* create a public semaphore set with one semaphore in it, */
    /* with access only to the owner.                           */
    semkey = ftok("/tmp", 'a');
    sem_set_id = semget(semkey, 1, 0);
    if (sem_set_id == -1) {
	perror("main: semget");
	exit(1);
    }
    printf("semaphore set created, semaphore set id '%d'.\n", sem_set_id);

    /* intialize the first (and single) semaphore in our set to '0'. */
    sem_val.val = 0;
    rc = semctl(sem_set_id, 0, SETVAL, sem_val);

    for (i=0; i<NUM_LOOPS; i++) {
	printf("producer: '%d'\n", i);
	fflush(stdout);
	/* increase the value of the semaphore by 1. */
	sem_op.sem_num = 0;
	sem_op.sem_op = 1;
	sem_op.sem_flg = 0;
	semop(sem_set_id, &sem_op, 1);
	/* pause execution for a little bit, to allow the */
	/* child process to run and handle some requests. */
	/* this is done about 25% of the time.            */
	if (rand() > 3*(RAND_MAX/4)) {
	    delay.tv_sec = 0;
	    delay.tv_nsec = 10;
	    nanosleep(&delay, NULL);
	}
    }
    return 0;
}

