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