[comp.sys.sequent] semaphores, a new library

andre@htsa.uucp (Andre van der Vlies) (04/19/89)

As we are dissatisfied with the SYSV semaphore package (to sluggish etc.)
and the spin-lock calls DYNIX supports, (very impractical in a class room
situation) we decided to write our own kit. Here it is. I hope you'll find
it useful. 

The archive can best be extracted in its own (new made) directory (e.g. Ask)
I will be pleased with any kind of comment, so please don't hesitate to do so.

	O /
---------x---------cut here---------------------------------------------------
	O \


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	MANIFEST
#	Makefile
#	README
#	ask.3x
#	ask.c
#	ask.h
#	nap.3
#	nap.c
#	pong.c
#	prod_cons.c
# This archive created: Tue Apr 18 20:13:18 1989
export PATH; PATH=/bin:/usr/bin:/usr/ucb:/usr/bin/local
echo shar: "extracting 'MANIFEST'" '(427 characters)'
if test -f 'MANIFEST'
then
	echo shar: "will not over-write existing file 'MANIFEST'"
else
sed 's/^X//' << \SHAR_EOF > 'MANIFEST'
XThis shell-archive should reproduce the following files :
X
X	MANIFEST	What you're reading now
X	README		General information for installing ASK
X	Makefile	Makefile for the libraries and test files
X	ask.3x		Man page for ASK
X	ask.c		Source code for ASK
X	ask.h		Include file for ASK and programs using ASK
X	nap.3		Man page for nap
X	nap.c		Source code for nap
X	pong.c		A little test program
X	prod_cons.c	A somewhat larger test program
SHAR_EOF
if test 427 -ne "`wc -c < 'MANIFEST'`"
then
	echo shar: "error transmitting 'MANIFEST'" '(should have been 427 characters)'
fi
chmod 640 'MANIFEST'
fi
echo shar: "extracting 'Makefile'" '(1969 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
XSOURCES =	ask.c\
X		nap.c\
X		pong.c\
X		prod_cons.c
X
XPOBJECTS =	pong.o
X
XCOBJECTS =	prod_cons.o
X
XLIBASK   =	/usr/lib/libask.a
X
XLIBNAP   =	/usr/lib/libnap.a
X
XAOBJECTS =	ask.o
X
XNOBJECTS =	nap.o
X
XCFLAGS=
X
Xall:	& pong pctest
X
Xpong:	& $(POBJECTS) $(LIBASK) $(LIBNAP)
X	cc -o pong $(POBJECTS) -lask -lnap -lpps
X
Xpctest:	& $(COBJECTS) $(LIBASK)
X	cc -o pctest $(COBJECTS) -lask -lpps
X
X$(LIBASK): & $(AOBJECTS)
X	ar qc libask.a $(AOBJECTS)
X	install -m 0644 libask.a /usr/lib
X	install -m 0644 -c ask.h /usr/include
X	ranlib /usr/lib/libask.a
X
X$(LIBNAP): & $(NOBJECTS)
X	ar qc libnap.a $(NOBJECTS)
X	install -m 0644 libnap.a /usr/lib
X	ranlib /usr/lib/libnap.a
X
Xinstall: & $(LIBNAP) $(LIBASK) ask.3x nap.3
X	install -m 0444 nap.3 /usr/man/man3
X	install -m 0444 ask.3x /usr/man/man3
X
Xclean:
X	rm -f *.o core pong pctest
X
Xdepend: 
X	@echo "	please wait ..."
X	@for i in  $(SOURCES) ; do\
X	    cc -M ${INCPATH} $$i | sed -e 's, \./, ,' | \
X	    awk '{ if ($$1 != prev) { if (rec != "") print rec; \
X		rec = $$0; prev = $$1; } \
X		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
X		else rec = rec " " $$2 } } \
X		END { print rec }'; done >makedep
X	@echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
X	@echo '$$r makedep' >> eddep
X	@echo 'w' >>eddep
X	@ed -  Makefile < eddep ;
X	@rm -f eddep makedep ;
X	@echo ' ' >> Makefile  ;
X	@echo '#  STUFF HERE WILL GO AWAY ON MAKE DEPEND' >> Makefile  ;
X
X# DO NOT DELETE THIS LINE
X 
Xask.o: ask.c /usr/include/stdio.h /usr/include/signal.h
Xask.o: /usr/include/sys/types.h /usr/include/parallel/parallel.h ask.h
Xnap.o: nap.c /usr/include/stdio.h /usr/include/sys/time.h /usr/include/signal.h
Xpong.o: pong.c /usr/include/stdio.h /usr/include/parallel/parallel.h
Xpong.o: /usr/include/ask.h
Xprod_cons.o: prod_cons.c /usr/include/stdio.h /usr/include/sys/types.h
Xprod_cons.o: /usr/include/parallel/parallel.h /usr/include/sys/wait.h
Xprod_cons.o: /usr/include/errno.h /usr/include/sys/errno.h /usr/include/ask.h
X 
X#  STUFF HERE WILL GO AWAY ON MAKE DEPEND
SHAR_EOF
if test 1969 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 1969 characters)'
fi
chmod 750 'Makefile'
fi
echo shar: "extracting 'README'" '(233 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
sed 's/^X//' << \SHAR_EOF > 'README'
XThis directory contains all the file to install libask.a and libnap.a. 
XYou should be able to install the lot by just typing "make all". If you wish
Xto be sure its worth your while, check out the makefile and the two test
Xprograms.
X
SHAR_EOF
if test 233 -ne "`wc -c < 'README'`"
then
	echo shar: "error transmitting 'README'" '(should have been 233 characters)'
fi
chmod 640 'README'
fi
echo shar: "extracting 'ask.3x'" '(2008 characters)'
if test -f 'ask.3x'
then
	echo shar: "will not over-write existing file 'ask.3x'"
else
sed 's/^X//' << \SHAR_EOF > 'ask.3x'
X.V=$""$
X.TH ASK 3X "\*V" "89/04/13" "Amsterdam Semaphore Kit"
X.SH NAME
XINITSEM, WAIT, SIGNAL, QUESTION, NOTIFY \- ASK
X.SH SYNOPSIS
X.nf
X.ft 3
X#include <parallel/parallel.h>
X#include <ask.h>
X.PP
X.ft 3
X.B void INITSEM(sem, value)
X.B semaphore *sem;
X.B int	     value;
X.PP
X.B void WAIT(sem)
X.B semaphore *sem;
X.PP
X.B void SIGNAL(sem)
X.B semaphore *sem;
X.PP
X.B QUESTION(sem,limit)
X.B semaphore *sem;
X.B int limit;
X.PP
X.B NOTIFY(sem,resources)
X.B semaphore *sem;
X.B int resources;
X.fi
X.ad b
X.SH DESCRIPTION
XA
X.I general semaphore 
Xpackage for the DYNIX operating system.
X.PP
X.I INITSEM()
X.in +4
Xassigns an initial value 
X.I val 
Xto a semaphore pointed to by
X.I sem.
X.in -4
X.PP
X.I WAIT()
X.in +4
XGains access to a semaphore pointed to by
X.I sem
Xand decrements the value for that semaphore. The process continues 
Xif the value is greater then zero, otherwise it falls asleep until the proces is 
X.I SIGNALed.
X.in -4
X.PP
X.I SIGNAL()
X.in +4
XIncrements the value for the semaphore pointed to by
X.I sem
Xand scans the corresponding queue for processes that are 
X.I WAITing
Xon that semaphore. If there are processes waiting it restarts the
Xfirst process that was asleep on that semaphore.
X.in -4
X.PP
X.I QUESTION()
X.in +4
XTests a semaphore against a
X.I limit.
XIf the limit is not reached yet, (the value of the semaphore is greater then
Xthe limit) the value of the semaphore is decremented. The previous value of
Xthe semaphore is returned.
X.in -4
X.bp
X.I NOTIFY()
X.in +4
XNotify a semaphore that new resources are available.
X.I Notify
Xadds the number of resources to the value of the semaphore.
XIf processes are waiting on this
Xsemaphore, they are restarted first (and the number of resources to add is 
Xadjusted). The adjusted value of the semaphore is returned.
X.in -4
X.SH BUGS
XDo not optimize programms which use 
X.I libask.a.
X.br
X.I SIGUSR2
Xis used for restarting processes, be aware of this !
X.SH FILES
X.nf
X/usr/lib/libpps.a	\-lpps library
X/usr/lib/libask.a	\-lask library
X.DT
X.SH AUTHORS
XAndre v.d Vlies & Hans Trompert
SHAR_EOF
if test 2008 -ne "`wc -c < 'ask.3x'`"
then
	echo shar: "error transmitting 'ask.3x'" '(should have been 2008 characters)'
fi
chmod 750 'ask.3x'
fi
echo shar: "extracting 'ask.c'" '(5482 characters)'
if test -f 'ask.c'
then
	echo shar: "will not over-write existing file 'ask.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ask.c'
X/*
X**			Amsterdam Semaphore Kit
X**
X** Implemenation of a general semaphore library for Sequent  Balance 
X** 4.2BSD .
X** This package uses SIGUSR2 to restart processes blocked on a semaphore.
X** Processes are queued dynamicly when blocked on a semaphore.
X** Blocking of a process is accomplished by awaiting a SIGUSR2 signal, using
X** the sigblock() and sigpause() calls.
X**
X** User programs using the ASK library must include parallel/parallel.h and
X** compile with -lpps (Parallel Programming Support library).
X**
X**
X** A semaphore is a struct containing a lock, a value and a pointer to a queue.
X** The lock is a spin-lock as provided by the DYNIX Parallel Programming library
X** and is used to protect the semaphore from being accessed by more the one
X** process. The value is the thing the WAIT and SIGNAL calls operate on.
X** The queue holds the process-id's of the processes that WAIT (sleep) on
X** a semaphore. Processes are restarted on a FIFO bases.
X**
X**                    Andre v.d. Vlies
X**                    Algemene Hogeschool Amsterdam
X**                    Technische en Maritieme Faculteit
X**                    andre@htsa.uucp or ...{backbones}!htsa!andre
X*/
X
X#include	<stdio.h>
X#include	<signal.h>
X#include	<sys/types.h>
X#include	<parallel/parallel.h>
X#include	"ask.h"
X
X#define sh_new(p) (p *)shmalloc(sizeof(p))
X#define wake_up(x) kill(x,SIGUSR2)
X#define USR2_MASK 0x40000000
X#define NIL 0
X
Xstatic int gotsig(sig)
Xint sig;
X{
X/* Dummy SIGUSR2 handler */
X}
X
Xvoid INITSEM(sem,val)
XSEMA *sem;
Xint  val;
X{
X	S_INIT_LOCK(&sem->lock);	/* Initialize the semaphore's lock */
X	/* Test for negative initialisation */
X	if ( val < 0 ) {
X		fprintf(stderr,"initsem(%d): Negative initialisation\n",getpid());
X		kill( getpid(),SIGTERM );
X	}
X	sem->value = val;
X	sem->root = NIL;
X}
X
X/*
X** If a process found the value of a semaphore <= 0 it must be added to the 
X** queue of processes , so it can be restarted when the value of that
X** semaphore > 0
X*/
Xstatic void add_to_q(sem)
XSEMA *sem;
X{
X	ITEM	*que,*tmp;
X
X	/*
X	** If shmalloc() fails there's no point in continueing 
X	** notifie the user and kill all related processes
X	*/
X	if ( (que = sh_new(ITEM)) == (ITEM *)-1) {
X		fprintf(stderr,"WAIT: queue-ing of process %d failed\n",getpid());
X		killpg( getpgrp(getpid(),SIGTERM) );
X	}
X	que->pid = getpid();
X	que->next = NIL;
X	if (sem->root == NIL) {
X		sem->root = que;
X	}
X	else {
X		tmp = sem->root;
X		while ( tmp->next )
X			tmp = tmp->next;
X		tmp->next = que;
X	}
X}
X
X/*
X** Remove the first entry from the queue and return its value (pid)
X*/
Xstatic int rem_from_q(sem)
XSEMA *sem;
X{
X	ITEM	*que;
X	int	procid;
X
X	que = sem->root;
X	procid = que->pid;
X	sem->root = que->next;
X	shfree(que);
X	return(procid);
X}
X
X/*
X** WAIT blocks if sem->value < 0 and puts itself on the wait-queue.
X** It is restarted again on receipt of a SIGUSR2
X*/
Xvoid WAIT(sem)
XSEMA *sem;
X{
X	int oldmask,ret;
X	int (*old_usr2)();
X
X	S_LOCK(&sem->lock);
X	if (--sem->value < 0) {
X		add_to_q(sem);
X		/* Set up signal-mask and remember old signal-mask */
X		oldmask = sigblock(USR2_MASK); 
X		S_UNLOCK(&sem->lock);
X		/*
X		** Set up handler when appropiate signal is received 
X		** and remember old handler
X		*/
X		old_usr2 = signal(SIGUSR2, gotsig);
X		/*
X		** Await for signal to arive and restore oldmask - SIGUSR2
X		** when it does
X		*/
X		sigpause(oldmask & ~USR2_MASK); 
X		/*
X		** Restore old hander for SIGUSR2
X		*/
X		signal(SIGUSR2, old_usr2);
X		/* Restore old mask */
X		sigsetmask(oldmask);
X	}
X	else
X		S_UNLOCK(&sem->lock);
X}
X
X/*
X** If sem->value < 0 there are process waiting on this semaphore
X** Find the first fallen asleep and restart it
X*/
Xvoid SIGNAL(sem)
XSEMA *sem;
X{
X	int	proc;
X
X	S_LOCK(&sem->lock);
X	if (sem->value++ < 0) {
X		/* Get pid of process to restart */
X		proc = rem_from_q(sem);
X		/*
X		** Send appropiate signal and if this doen't work out right
X		** kill all related processes
X		*/
X		if (wake_up(proc) == -1 ) {
X			S_UNLOCK(&sem->lock);
X			fprintf(stderr,"SIGNAL: revival of process %d failed\n",proc);
X			killpg( getpgrp(getpid(),SIGTERM) );
X		}
X	}
X	S_UNLOCK(&sem->lock);
X}
X
X/* 
X**  Question the value of a semaphore
X**  If the value of the semaphore is greater then the test-value, decrement
X**  the value of the semaphore.
X**  Always return the last value of the semaphore.
X**
X**  NOTE: It isn't possible to invoke QUESTION with a negative test, nor
X**	  is it possible that QUESTION decrements sem->value beneath its
X**	  test value.
X*/
Xint QUESTION(sem, test)
XSEMA *sem;
Xint test;
X{
X	int	val;
X
X	if ( test < 0 ) {
X		fprintf(stderr,"QUESTION: Illegal test value\n");
X		killpg( getpgrp(getpid(),SIGTERM) );
X	}
X	S_LOCK(&sem->lock);
X	val = sem->value;
X	if ( sem->value > test )
X		--sem->value;
X	S_UNLOCK(&sem->lock);
X	return(val);
X}
X
X/*
X** Notify a semaphore that some _resources_ are added.
X** If processes are waiting on this semaphore wake them up first (and adjust
X** toadd) then add the number of resources to sem->value.
X** Always return the current value of the semaphore.
X*/
X
Xint NOTIFY(sem,toadd)
XSEMA *sem;
Xint toadd;
X{
X	int	proc,
X		val;
X
X	if ( toadd < 0 ) {
X		fprintf(stderr,"NOTIFY: Illegal value\n");
X		killpg( getpgrp(getpid(),SIGTERM) );
X	}
X	S_LOCK(&sem->lock);
X	while ( sem->value < 0 ) {
X		proc = rem_from_q(sem);
X		++sem->value; toadd--;
X		if (wake_up(proc) == -1 ) {
X			S_UNLOCK(&sem->lock);
X			fprintf(stderr,"NOTIFY: revival of process %d failed\n",proc);
X			killpg( getpgrp(getpid(),SIGTERM) );
X		}
X	}
X	sem->value += toadd;
X	val = sem->value;
X	S_UNLOCK(&sem->lock);
X	return(val);
X}	
SHAR_EOF
if test 5482 -ne "`wc -c < 'ask.c'`"
then
	echo shar: "error transmitting 'ask.c'" '(should have been 5482 characters)'
fi
chmod 750 'ask.c'
fi
echo shar: "extracting 'ask.h'" '(974 characters)'
if test -f 'ask.h'
then
	echo shar: "will not over-write existing file 'ask.h'"
else
sed 's/^X//' << \SHAR_EOF > 'ask.h'
X/*
X**			Amsterdam Semaphore Kit
X**
X** Implemenation of a general semaphore library for Sequent  Balance 
X** 4.2BSD .
X** This package uses SIGUSR2 to restart processes blocked on a semaphore.
X** Processes are queued dynamicly when blocked on a semaphore.
X** Blocking of a process is accomplished by awaiting a SIGUSR2 signal, using
X** the sigblock() and sigpause() calls.
X**
X** User programs using the ASK library must include parallel/parallel.h and
X** compile with -lpps (Parallel Programming Support library).
X**
X**
X**                    Andre v.d. Vlies
X**                    Algemene Hogeschool Amsterdam
X**                    Technische en Maritieme Faculteit
X**                    andre@htsa.uucp or ...{backbones}!htsa!andre
X*/
X
Xvoid	INITSEM();
Xvoid	WAIT();
Xvoid	SIGNAL();
Xint	QUESTION();
Xint	NOTIFY();
X
Xtypedef struct item {
X	int	pid;
X	struct item *next;
X} ITEM;
X
Xtypedef struct sema {
X	slock_t lock;
X	int 	value;
X	ITEM	*root;
X} SEMA;
X
X#define semaphore shared SEMA
SHAR_EOF
if test 974 -ne "`wc -c < 'ask.h'`"
then
	echo shar: "error transmitting 'ask.h'" '(should have been 974 characters)'
fi
chmod 750 'ask.h'
fi
echo shar: "extracting 'nap.3'" '(530 characters)'
if test -f 'nap.3'
then
	echo shar: "will not over-write existing file 'nap.3'"
else
sed 's/^X//' << \SHAR_EOF > 'nap.3'
X.TH NAP 3 "89/04/13"
X.SH NAME
Xnap \- milli-second sleep
X.SH SYNOPSIS
X.ft 3
Xnap(msec)
X.br
Xint msec;
X.SH DESCRIPTION
X.I Nap
Xlets a process sleep for \f2msec\fP
Xmilliseconds. The shortest sleep possible is one clock_tick long 
X(system dependend). A shorter sleep will result in no sleep at all. For 
Xintervals longer than 1000 msec's a \f2sleep\fP (3) is preferable.
X
X.PP
X.SH "RETURN VALUE
X.I None.
X.SH "ERRORS
X.I Nap
Xreturns no errors.
X.SH "FILES"
X /usr/lib/libnap.a	-lnap library
X.SH "SEE ALSO"
Xsleep(3)
X.SH "AUTHOR"
XHans Trompert
SHAR_EOF
if test 530 -ne "`wc -c < 'nap.3'`"
then
	echo shar: "error transmitting 'nap.3'" '(should have been 530 characters)'
fi
chmod 440 'nap.3'
fi
echo shar: "extracting 'nap.c'" '(1239 characters)'
if test -f 'nap.c'
then
	echo shar: "will not over-write existing file 'nap.c'"
else
sed 's/^X//' << \SHAR_EOF > 'nap.c'
X#include <stdio.h>
X#include <sys/time.h>
X#include <signal.h>
X
Xint (*signal())();
X
Xnap_sigalrm()
X{
X}
X
X/*
X  nap for milli milliseconds, if milli < 10 a nap of 0 is performed
X*/
Xnap(milli)
Xlong milli;
X{
X  int oldblock;
X  int (*oldalrm)();
X  struct itimerval value;
X  struct itimerval ovalue;
X
X/*
X  set interval timer
X*/
X  value.it_value.tv_sec = milli / 1000;
X  value.it_value.tv_usec = (milli % 1000) * 1000;
X  value.it_interval.tv_sec = 0;
X  value.it_interval.tv_usec = 0;
X
X/*
X  block all signal's execpt SIGTRACE (5th bit in mask)
X*/
X  oldblock = sigblock((int)0xFFFFFFEF);
X/*
X  catch SIGALRM and remember old routine
X*/
X  if((oldalrm = signal(SIGALRM, nap_sigalrm)) == (int(*)())-1)
X    perror("nap");
X  else
X/*
X  initialize real time interval timer and remember old interval timer value's
X*/
X    if(setitimer(ITIMER_REAL, &value, &ovalue))
X      perror("nap");
X    else
X    {
X/*
X  wait for any signal (mask = 0)
X*/
X      sigpause(0);
X/*
X  restore old interval timer values
X*/
X      if(setitimer(ITIMER_REAL, &ovalue, &value))
X        perror("nap");
X/*
X  restore old SIGALRM catch routine
X*/
X      if(signal(SIGALRM, oldalrm) == (int(*)())-1)
X        perror("nap");
X    }
X/*
X  restore old signal mask
X*/
X  return(sigsetmask(oldblock));
X}
SHAR_EOF
if test 1239 -ne "`wc -c < 'nap.c'`"
then
	echo shar: "error transmitting 'nap.c'" '(should have been 1239 characters)'
fi
chmod 750 'nap.c'
fi
echo shar: "extracting 'pong.c'" '(694 characters)'
if test -f 'pong.c'
then
	echo shar: "will not over-write existing file 'pong.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pong.c'
X#include	<stdio.h>
X#include	<parallel/parallel.h>
X#include	<ask.h>
X
Xsemaphore ping,
X	  pong,
X	  pock;
X
Xmain()
X{
X
X	INITSEM(&ping,1);
X	INITSEM(&pong,0);
X	INITSEM(&pock,0);
X	if ( fork() == 0 )
X		pingel();
X	else
X		if( fork () == 0 )
X			pockel();
X		else
X			pongel();
X}
X
X
Xpingel()
X{
X	while (1) {
X		WAIT(&ping);
X		fprintf(stderr, "\n\007ping");
X		nap(400);
X		SIGNAL(&pock);
X	}
X}
X
Xpockel()
X{
X	while(1) {
X		WAIT(&pock);
X		fprintf(stderr, "\n\t\t\t\t\007pock");
X		nap(200);
X		SIGNAL(&pong);
X		WAIT(&pock);
X		fprintf(stderr, "\n\t\t\t\t\007pock");
X		nap(200);
X		SIGNAL(&ping);
X	}
X}
X
Xpongel()
X{
X	while (1) {
X		WAIT(&pong);
X		fprintf(stderr, "\n\t\t\t\t\t\t\t\t\007pong");
X		nap(400);
X		SIGNAL(&pock);
X	}
X}
SHAR_EOF
if test 694 -ne "`wc -c < 'pong.c'`"
then
	echo shar: "error transmitting 'pong.c'" '(should have been 694 characters)'
fi
chmod 750 'pong.c'
fi
echo shar: "extracting 'prod_cons.c'" '(2270 characters)'
if test -f 'prod_cons.c'
then
	echo shar: "will not over-write existing file 'prod_cons.c'"
else
sed 's/^X//' << \SHAR_EOF > 'prod_cons.c'
X#include	<stdio.h>
X#include	<sys/types.h>
X#include	<parallel/parallel.h>
X#include	<sys/wait.h>
X#include	<errno.h>
X#include	<ask.h>
X
X
X#define MAX_PROC 4
X#define MAXBUF 2048
X
X
X
Xshared char     buf[MAXBUF];
Xshared int      next_in, next_out;
X
Xsemaphore       MUTEX, FULL, EMPTY, WMUTEX, no_of_chars;
X
Xmain()
X{
X	int             i;
X	int             no_of_cons;
X	int             no_of_prod;
X	int             chars;
X	int             tot = 0;
X
X	init();
X	fprintf(stderr, "How many consumers ? ");
X	scanf("%d", &no_of_cons);
X	fprintf(stderr, "How many producers ? ");
X	scanf("%d", &no_of_prod);
X
X	for (i = 1; i <= no_of_cons; i++) {
X		fprintf(stderr, "How much items for consumer %d ? ", i);
X		scanf("%d", &chars);
X		if ((fork()) == 0)
X			consumer(chars);
X	}
X
X
X	/* Fork four producers */
X
X	for (i = 1; i <= no_of_prod; i++) {
X		if ((fork()) == 0)
X			producer(i);
X	}
X
X	/* Wait for producers and consumers to finish their task */
X
X	while (wait((union wait *) 0) != -1);
X	printf("\n");
X	exit();
X}
X
X
X
X
X/* Initialize semaphores used */
X
Xinit()
X{
X	srandom(time(0));
X	next_in = 0;
X	next_out = 0;
X	/* Initialize semaphores */
X	INITSEM(&MUTEX, 1);
X	INITSEM(&EMPTY, MAXBUF);
X	INITSEM(&FULL, 0);
X	INITSEM(&WMUTEX, 1);
X	INITSEM(&no_of_chars, 0);
X}
X
X
X
X
X
Xconsumer(j)
X	int             j;
X{
X	char            data;
X	int             i;
X	char           *recbuf = (char *) malloc(j);
X
X
X	NOTIFY(&no_of_chars,j);
X	for (i = 0; i < j; i++) {
X		remove(&data);
X		recbuf[i] = data;
X	}
X	recbuf[i] = '\0';
X
X
X	WAIT(&WMUTEX);
X	printf("\n*****cons[%d] = %s count = %d\n", getpid(), recbuf, i);
X	SIGNAL(&WMUTEX);
X	printf("*****consumer[%d] with pid= %d: exiting\n", j, getpid());
X	exit();
X}
X
X
X
Xproducer(j)
X	int             j;
X{
X	int             count = 0;
X
X	while (1) {
X		if (QUESTION(&no_of_chars, 0) != 0) {
X			deposit('@' + j);
X			count++;
X		} else break;
X	}
X	printf("***producer[%d] with pid= %d produced %d %c 's: exiting\n", j,
X	       getpid(), count, '@' + j);
X	exit();
X}
X
X
X
X
X
X
Xremove(item)
X	char           *item;
X{
X	WAIT(&FULL);
X	WAIT(&MUTEX);
X	*item = buf[next_out];
X	next_out = (next_out + 1) % MAXBUF;
X	SIGNAL(&MUTEX);
X	SIGNAL(&EMPTY);
X}
X
X
Xdeposit(item)
X	char            item;
X{
X	WAIT(&EMPTY);
X	WAIT(&MUTEX);
X	buf[next_in] = item;
X	next_in = (next_in + 1) % MAXBUF;
X	SIGNAL(&MUTEX);
X	SIGNAL(&FULL);
X}
SHAR_EOF
if test 2270 -ne "`wc -c < 'prod_cons.c'`"
then
	echo shar: "error transmitting 'prod_cons.c'" '(should have been 2270 characters)'
fi
chmod 750 'prod_cons.c'
fi
exit 0
#	End of shell archive

	O /
---------x---------and here---------------------------------------------------
	O \
-- 
                    Andre v.d. Vlies
                    Algemene Hogeschool Amsterdam
                    Technische en Maritieme Faculteit
                    andre@htsa.uucp or ...{backbones}!htsa!andre