/*
 * Copyright (c) 2007, Sven Bachmann (dev@mcbachmann.de)
 * All rights reserved.
 *
 * Desc: This program is only an example on how to use named semaphores
 *       in linux. It was developed to show an unbelieving teacher
 *       how far the API is evolved ;-)
 *       The program simulates a family where the father and his 6 childs
 *       are only have 3 chairs (resources) and everytime one of them
 *       decides to stand up, another one sits down for a random time.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Compile:
 *   gcc -lpthread -o semaphore semaphore.c
 *
 * Instead of -lpthread you can also use -lrt. Execute with ./semaphore.
 *
 */

#include <fcntl.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

void steam_engine(pid_t, char*);

int main(void)
{
    sem_t* sema;
    pid_t  pid;
    int i;

    sem_unlink("chair");
    sema = sem_open("chair", O_CREAT, 0666, 3);

    /* create 5 child processes */
    for(i = 5; i >= 1; i--) {

	/* trigger the pseudo-random-generator, or every fork
	 * will use the same pool
	 */
	rand();

	pid = fork();
	if(pid > 0) {
	    break;
	}
    }

    steam_engine(pid, (pid <= 0) ? "Father" : "Child ");

    sem_close(sema);
    return(0);
}

void steam_engine(pid_t pid, char* name)
{
    sem_t* sema;
    int downtime;
    int semval;

    sema = sem_open("chair", 0);
    if(sema == SEM_FAILED) {
	printf("[%s, %5i] FAIL: could not open semaphore 'chair'\n", name, pid);
	return;
    }

    while(1) {
	sem_getvalue(sema, &semval);
	printf("[%s, %5i] WAIT: waiting for semaphore 'chair' (current value: %i)\n", name, pid, semval);

	sem_wait(sema);
	downtime = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
	printf("[%s, %5i] DOWN: got semaphore 'chair', sitting down for %i seconds :-)\n", name, pid, downtime);
	sleep(downtime);

	printf("[%s, %5i] UP  : time to get up, let somebody else sit down...\n", name, pid);
	sem_post(sema);
	sleep(1);
    }
}

