6
These routines simplify the interface to semaphores for use in mutual
7
exclusion and queuing. Hopefully I can also make this portable.
9
An external routine Error is assumed which is called upon an error
10
and tidies up by calling SemSetDestroyAll.
12
In most cases errors cause an internal hard failure (by calling Error).
14
1) make an array of n_sem semaphores, returning the id associated
15
with the entire set. All the semaphore values are initialized to value
16
which should be a positve integer (queuing) or 0 (synchronization).
17
The semaphores in the set are indexed from 0 to n_sem-1.
19
long SemSetCreate(long n_sem, long value)
21
2) Decrement and test the value associated with the semaphore specified by
22
(sem_set_id, sem_num). In effect this:
28
wait in queue for the semaphore
32
void SemWait(long sem_set_id, long sem_num)
34
3) Increment the value associated with the semaphore specified by
35
(sem_set_id, sem_num). If value <= 0 (i.e. there are processes
36
in the queue) this releases the next process.
38
void SemPost(long sem_set_id, long sem_num)
40
4) Return the current value associated with the semaphore sepcified by
41
(sem_set_id, sem_num).
43
long SemValue(long sem_set_id, long sem_num)
45
5) Destroy the set of semaphores. Any other processes that are accessing
46
or try to access the semaphore set should get an error.
47
On the SUN (all system V machines?) the semaphore sets should
48
be destroyed explicitly before the final process exits.
49
0 is returned if OK. -1 implies an error.
51
long SemSetDestroy(long sem_set_id)
53
6) Destroy all the semaphore sets that are known about. This is really
54
meant for an error routine to call to try and tidy up. Though all
55
applications could call it before the last process exits.
56
0 is returned if OK. -1 implies an error.
58
long SemSetDestroyAll()
64
#include <sys/param.h>
67
#include <sys/types.h>
69
#define MAX_SEM_SETS 20
72
/* On the convex a semaphore is a structure but on the apollo
73
it is an array which does not need dereferencing. Use ADDR
74
to generate the address of a semaphore */
81
extern char *mktemp();
83
struct sem_set_struct {
84
int n_sem; /* no. of semaphores in set */
85
semaphore lock[MAX_N_SEM]; /* locks for changing value */
86
semaphore wait[MAX_N_SEM]; /* locks for queing */
87
int value[MAX_N_SEM]; /* values */
90
static int num_sem_set = 0;
91
static struct sem_set_struct *sem_sets;
93
static char template[] = "/tmp/SEMA.XXXXXX";
94
static char *filename = (char *) NULL;
97
/* Initialise sem_sets and allocate associated shmem region */
100
unsigned size = sizeof(struct sem_set_struct) * MAX_SEM_SETS;
103
/* Generate scratch file to identify region ... mustn't do this
106
filename = mktemp(template);
107
if ( (fd = open(filename, O_RDWR|O_CREAT, 0666)) < 0 )
108
Error("InitSemSets: failed to open temporary file",0);
111
sem_sets = (struct sem_set_struct *) mmap((caddr_t) 0, &size,
112
PROT_READ|PROT_WRITE,
113
MAP_ANON|MAP_HASSEMAPHORE|MAP_SHARED, fd, 0);
116
if (sem_sets == (struct sem_set_struct *) 0)
117
Error("InitSemSets: mmap failed", (long) -1);
119
if (sem_sets == (struct sem_set_struct *) -1)
120
Error("InitSemSets: mmap failed", (long) -1);
123
for (i=0; i<MAX_SEM_SETS; i++) {
124
sem_sets[i].n_sem = 0;
125
for (j=0; j<MAX_N_SEM; j++) {
126
mclear(ADDR(sem_sets[i].lock[j]));
127
mclear(ADDR(sem_sets[i].wait[j]));
128
sem_sets[i].value[j] = 0;
133
long SemSetCreate(n_sem, value)
139
/* Check for errors and initialise data if first entry */
141
if ( (n_sem <= 0) || (n_sem >= MAX_N_SEM) )
142
Error("SemSetCreate: n_sem has invalid value",n_sem);
144
if (num_sem_set == 0)
146
else if (num_sem_set >= MAX_SEM_SETS)
147
Error("SemSetCreate: Exceeded man no. of semaphore sets",
150
/* Initialize the values */
152
for (i=0; i<n_sem; i++)
153
sem_sets[num_sem_set].value[i] = value;
155
sem_sets[num_sem_set].n_sem = n_sem;
159
return (long) (num_sem_set - 1);
162
void SemWait(sem_set_id, sem_num)
166
if ( (sem_set_id < 0) || (sem_set_id >= num_sem_set) )
167
Error("SemWait: invalid sem_set_id",sem_set_id);
168
if ( (sem_num < 0) || (sem_num >= sem_sets[sem_set_id].n_sem) )
169
Error("SemWait: invalid semaphore number in set",sem_num);
173
/* Get the lock around the whole semaphore */
175
(void) mset(ADDR(sem_sets[sem_set_id].lock[sem_num]), 1);
177
/* If the value is positive fall thru, else wait */
179
if (sem_sets[sem_set_id].value[sem_num] > 0)
182
(void) mclear(ADDR(sem_sets[sem_set_id].lock[sem_num]));
183
(void) mset(ADDR(sem_sets[sem_set_id].wait[sem_num]), 1);
187
/* Are ready to go ... decrement the value and release lock */
189
sem_sets[sem_set_id].value[sem_num]--;
190
(void) mclear(ADDR(sem_sets[sem_set_id].lock[sem_num]));
194
void SemPost(sem_set_id, sem_num)
200
if ( (sem_set_id < 0) || (sem_set_id >= num_sem_set) )
201
Error("SemPost: invalid sem_set_id",sem_set_id);
202
if ( (sem_num < 0) || (sem_num >= sem_sets[sem_set_id].n_sem) )
203
Error("SemPost: invalid semaphore number in set",sem_num);
205
/* Get the lock around the whole semaphore */
207
(void) mset(ADDR(sem_sets[sem_set_id].lock[sem_num]), 1);
209
/* Read and increment the value. If is now zero wake up
212
sem_sets[sem_set_id].value[sem_num]++;
213
i = sem_sets[sem_set_id].value[sem_num];
215
(void) mclear(ADDR(sem_sets[sem_set_id].lock[sem_num]));
217
(void) mclear(ADDR(sem_sets[sem_set_id].wait[sem_num]));
220
long SemValue(sem_set_id, sem_num)
226
if ( (sem_set_id < 0) || (sem_set_id >= num_sem_set) )
227
Error("SemValue: invalid sem_set_id",sem_set_id);
228
if ( (sem_num < 0) || (sem_num >= sem_sets[sem_set_id].n_sem) )
229
Error("SemValue: invalid semaphore number in set",sem_num);
231
/* There seems no point in getting the lock just to read
232
the value and it seems more useful not to (e.g. debugging) */
234
i = sem_sets[sem_set_id].value[sem_num];
239
long SemSetDestroy(sem_set_id)
243
if ( (sem_set_id < 0) || (sem_set_id >= num_sem_set) )
246
sem_sets[sem_set_id].n_sem = 0;
251
long SemSetDestroyAll()
255
for (i=0; i<num_sem_set; i++)
256
if (sem_sets[i].n_sem)
257
status += SemSetDestroy(i);
262
(void) unlink(filename);
265
status += munmap((char *) sem_sets, 0);