5
/* $Header: /tmp/hpctools/ga/tcgmsg/ipcv4.0/sema.c,v 1.17 2003-05-08 15:44:43 edo Exp $ */
8
These routines simplify the interface to semaphores for use in mutual
9
exclusion and queuing. Hopefully I can also make this portable.
11
An external routine Error is assumed which is called upon an error
12
and tidies up by calling SemSetDestroyAll.
14
In most cases errors cause an internal hard failure (by calling Error).
16
1) make an array of n_sem semaphores, returning the id associated
17
with the entire set. All the semaphore values are initialized to value
18
which should be a positve integer (queuing) or 0 (synchronization).
19
The semaphores in the set are indexed from 0 to n_sem-1.
21
long SemSetCreate(long n_sem, long value)
23
2) Decrement and test the value associated with the semaphore specified by
24
(sem_set_id, sem_num). In effect this:
30
wait in queue for the semaphore
34
void SemWait(long sem_set_id, long sem_num)
36
3) Increment the value associated with the semaphore specified by
37
(sem_set_id, sem_num). If value <= 0 (i.e. there are processes
38
in the queue) this releases the next process.
40
void SemPost(long sem_set_id, long sem_num)
42
4) Return the current value associated with the semaphore sepcified by
43
(sem_set_id, sem_num).
45
long SemValue(long sem_set_id, long sem_num)
47
5) Destroy the set of semaphores. Any other processes that are accessing
48
or try to access the semaphore set should get an error.
49
On the SUN (all system V machines?) the semaphore sets should
50
be destroyed explicitly before the final process exits.
51
0 is returned if OK. -1 implies an error.
53
long SemSetDestroy(long sem_set_id)
55
6) Destroy all the semaphore sets that are known about. This is really
56
meant for an error routine to call to try and tidy up. Though all
57
applications could call it before the last process exits.
58
0 is returned if OK. -1 implies an error.
60
long SemSetDestroyAll()
65
#if defined(SYSV) && !defined SGIUS && !defined(SPPLOCKS) && !defined(MACX)
67
/********************************************************************
68
Most system V compatible machines
69
********************************************************************/
73
The value used for our semaphore is equal to the value of the
74
System V semaphore (which is always positive) minus the no. of
75
processes in the queue. That is because our interface was modelled
76
after that of Alliant whose semaphore can take on negative values.
79
#include <sys/types.h>
85
int val; /* value for SETVAL */
86
struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
87
unsigned short int *array; /* array for GETALL, SETALL */
88
struct seminfo *__buf; /* buffer for IPC_INFO */
92
/* this global structure maintains a list of allocated semaphore sets
93
which is used for SemSetDestroyAll */
95
#define MAX_SEM_SETS 20
96
static int sem_set_id_list[MAX_SEM_SETS];
97
static int num_sem_set = 0;
99
#if defined(SGITFP) || defined(SGI64) || defined(KSR) || defined(SOLARIS) || defined (AIX) || defined(LINUX64)
100
# define MAX_N_SEM 512
102
# define MAX_N_SEM 40
105
void InitSemSetList()
106
/* Initialise sem_set_id_list */
110
for (i=0; i<MAX_SEM_SETS; i++)
111
sem_set_id_list[i] = -1;
114
long SemSetCreate(n_sem, value)
121
/* Check for errors and initialise data if first entry */
123
if ( (n_sem <= 0) || (n_sem >= MAX_N_SEM) )
124
Error("SemSetCreate: n_sem has invalid value", (long) n_sem);
126
if (num_sem_set == 0)
128
else if (num_sem_set >= MAX_SEM_SETS)
129
Error("SemSetCreate: Exceeded man no. of semaphore sets",
132
/* Actually make the semaphore set */
134
if ( (semid = semget(IPC_PRIVATE, (int) n_sem, IPC_CREAT | 00600)) < 0)
135
Error("SemSetCreate: failed to create semaphore set", (long) semid);
137
/* Put the semid in the first empty slot in sem_set_id_list */
139
for (i=0; i < MAX_SEM_SETS; i++) {
140
if (sem_set_id_list[i] == -1) {
141
sem_set_id_list[i] = semid;
145
if (i == MAX_SEM_SETS)
146
Error("SemSetCreate: internal error puting semid in list", (long) i);
150
/* Now set the value of all the semaphores */
152
arg.val = (int) value;
153
for (i=0; i<n_sem; i++)
154
if (semctl(semid, i, SETVAL, arg) == -1)
155
Error("SemSetCreate: error setting value for semaphore", (long) i);
160
void SemWait(sem_set_id, sem_num)
166
sops.sem_num = sem_num; /* semaphore no. */
167
sops.sem_op = -1; /* decrement by 1 */
168
sops.sem_flg = 0; /* block */
170
if (semop((int) sem_set_id, &sops, 1) == -1)
171
Error("SemWait: error from semop", (long) -1);
174
void SemPost(sem_set_id, sem_num)
180
sops.sem_num = sem_num; /* semaphore no. */
181
sops.sem_op = 1; /* increment by 1 */
182
sops.sem_flg = 0; /* not used? */
184
if (semop((int) sem_set_id, &sops, 1) == -1)
185
Error("SemPost: error from semop", (long) -1);
188
long SemValue(sem_set_id, sem_num)
192
/* See note at top of SUN code section about semaphore value */
197
if ( (semval = semctl((int) sem_set_id, (int) sem_num, GETVAL, arg)) == -1)
198
Error("SemValue: error getting value for semaphore", (long) sem_num);
200
if ( (semncnt = semctl((int) sem_set_id, (int) sem_num, GETNCNT, arg)) == -1)
201
Error("SemValue: error getting ncnt for semaphore", (long) sem_num);
203
return semval-semncnt;
206
long SemSetDestroy(sem_set_id)
212
/* Remove the sem_set_id from the internal list of ids */
214
for (i=0; i<MAX_SEM_SETS; i++)
215
if (sem_set_id_list[i] == sem_set_id) {
216
sem_set_id_list[i] = -1;
222
/* System call to delete the id */
224
return (long) semctl((int) sem_set_id, 0, IPC_RMID, arg);
227
long SemSetDestroyAll()
231
for (i=0; i<MAX_SEM_SETS; i++)
232
if (sem_set_id_list[i] != -1)
233
status += SemSetDestroy((long) sem_set_id_list[i]);
244
/*************************************************************
245
Alliant Concentrix 5.0 and Concentrix FX/2800
246
*************************************************************/
248
/* This is very specific to the Alliant. */
250
#include <sys/rtsem.h>
251
#include <sys/errno.h>
255
/* On the alliant semaphores are handed out one at a time rather than
256
in sets, so have to maintain sets manually */
258
#define MAX_SEM_SETS 20
259
#define MAX_N_SEM 128
261
static struct sem_set_list_struct {
262
int id[MAX_N_SEM]; /* alliant semaphore id */
263
int n_sem; /* no. of semaphores in set */
264
} sem_set_list[MAX_SEM_SETS];
266
static int num_sem_set = 0;
269
void InitSemSetList()
270
/* Initialise sem_set_list */
274
for (i=0; i<MAX_SEM_SETS; i++) {
275
sem_set_list[i].n_sem = 0;
276
for (j=0; j<MAX_N_SEM; j++)
277
sem_set_list[i].id[j] = -1;
281
long SemSetCreate(n_sem, value)
287
/* Check for errors and initialise data if first entry */
289
if ( (n_sem <= 0) || (n_sem >= MAX_N_SEM) )
290
Error("SemSetCreate: n_sem has invalid value", (long) n_sem);
292
if (num_sem_set == 0)
294
else if (num_sem_set >= MAX_SEM_SETS)
295
Error("SemSetCreate: Exceeded man no. of semaphore sets",
298
/* Find first empty slot in sem_set_list */
300
for (i=0; i < MAX_SEM_SETS; i++)
301
if (sem_set_list[i].n_sem == 0)
304
if (i == MAX_SEM_SETS)
305
Error("SemSetCreate: internal error puting semid in list", (long) i);
307
/* Actually make the semaphore set */
309
for (j=0; j<n_sem; j++) {
310
if ( (semid = sem_create(value, value, SEMQUE_FIFO, 0)) < 0)
311
Error("SemSetCreate: failed to create semaphore", (long) j);
312
sem_set_list[i].id[j] = semid;
320
void SemWait(sem_set_id, sem_num)
325
if (sem_wait(sem_set_list[sem_set_id].id[sem_num]) < 0) {
327
goto interrupted; /* got zapped by a signal ... try again */
329
Error("SemWait: error from sem_wait", (long) -1);
333
void SemPost(sem_set_id, sem_num)
337
if (sem_post(sem_set_list[sem_set_id].id[sem_num]) < 0)
338
Error("SemPost: error from sem_post", (long) -1);
341
long SemValue(sem_set_id, sem_num)
347
if (sem_info(sem_set_list[sem_set_id].id[sem_num], &info, sizeof info) < 0)
348
Error("SemValue: error from sem_info", (long) -1);
353
long SemSetDestroy(sem_set_id)
358
/* Close each semaphore in the set */
360
for (i=0; i<sem_set_list[sem_set_id].n_sem; i++) {
361
status += sem_destroy(sem_set_list[sem_set_id].id[i]);
362
sem_set_list[sem_set_id].id[i] = -1;
365
sem_set_list[sem_set_id].n_sem = 0;
372
return (long) status;
375
long SemSetDestroyAll()
379
for (i=0; i<MAX_SEM_SETS; i++)
380
if (sem_set_list[i].n_sem)
381
status += SemSetDestroy(i);
386
return (long) status;
390
#if (defined(CONVEX) || defined(APOLLO)) && !defined(HPUX)
393
#include <sys/param.h>
394
#include <sys/file.h>
395
#include <sys/mman.h>
396
#include <sys/types.h>
398
#define MAX_SEM_SETS 20
399
#define MAX_N_SEM 100
401
/* On the convex a semaphore is a structure but on the apollo
402
it is an array which does not need dereferencing. Use ADDR
403
to generate the address of a semaphore */
410
extern char *mktemp();
412
struct sem_set_struct {
413
int n_sem; /* no. of semaphores in set */
414
semaphore lock[MAX_N_SEM]; /* locks for changing value */
415
semaphore wait[MAX_N_SEM]; /* locks for queing */
416
int value[MAX_N_SEM]; /* values */
419
static int num_sem_set = 0;
420
static struct sem_set_struct *sem_sets;
422
static char template[] = "/tmp/SEMA.XXXXXX";
423
static char *filename = (char *) NULL;
426
/* Initialise sem_sets and allocate associated shmem region */
429
unsigned size = sizeof(struct sem_set_struct) * MAX_SEM_SETS;
432
/* Generate scratch file to identify region ... mustn't do this
435
filename = mktemp(template);
436
if ( (fd = open(filename, O_RDWR|O_CREAT, 0666)) < 0 )
437
Error("InitSemSets: failed to open temporary file",0);
440
sem_sets = (struct sem_set_struct *) mmap((caddr_t) 0, &size,
441
PROT_READ|PROT_WRITE,
442
MAP_ANON|MAP_HASSEMAPHORE|MAP_SHARED, fd, 0);
445
if (sem_sets == (struct sem_set_struct *) 0)
446
Error("InitSemSets: mmap failed", (long) -1);
448
if (sem_sets == (struct sem_set_struct *) -1)
449
Error("InitSemSets: mmap failed", (long) -1);
452
for (i=0; i<MAX_SEM_SETS; i++) {
453
sem_sets[i].n_sem = 0;
454
for (j=0; j<MAX_N_SEM; j++) {
455
mclear(ADDR(sem_sets[i].lock[j]));
456
mclear(ADDR(sem_sets[i].wait[j]));
457
sem_sets[i].value[j] = 0;
462
long SemSetCreate(n_sem, value)
468
/* Check for errors and initialise data if first entry */
470
if ( (n_sem <= 0) || (n_sem >= MAX_N_SEM) )
471
Error("SemSetCreate: n_sem has invalid value",n_sem);
473
if (num_sem_set == 0)
475
else if (num_sem_set >= MAX_SEM_SETS)
476
Error("SemSetCreate: Exceeded man no. of semaphore sets",
479
/* Initialize the values */
481
for (i=0; i<n_sem; i++)
482
sem_sets[num_sem_set].value[i] = value;
484
sem_sets[num_sem_set].n_sem = n_sem;
488
return (long) (num_sem_set - 1);
491
void SemWait(sem_set_id, sem_num)
495
if ( (sem_set_id < 0) || (sem_set_id >= num_sem_set) )
496
Error("SemWait: invalid sem_set_id",sem_set_id);
497
if ( (sem_num < 0) || (sem_num >= sem_sets[sem_set_id].n_sem) )
498
Error("SemWait: invalid semaphore number in set",sem_num);
502
/* Get the lock around the whole semaphore */
504
(void) mset(ADDR(sem_sets[sem_set_id].lock[sem_num]), 1);
506
/* If the value is positive fall thru, else wait */
508
if (sem_sets[sem_set_id].value[sem_num] > 0)
511
(void) mclear(ADDR(sem_sets[sem_set_id].lock[sem_num]));
512
(void) mset(ADDR(sem_sets[sem_set_id].wait[sem_num]), 1);
516
/* Are ready to go ... decrement the value and release lock */
518
sem_sets[sem_set_id].value[sem_num]--;
519
(void) mclear(ADDR(sem_sets[sem_set_id].lock[sem_num]));
523
void SemPost(sem_set_id, sem_num)
529
if ( (sem_set_id < 0) || (sem_set_id >= num_sem_set) )
530
Error("SemPost: invalid sem_set_id",sem_set_id);
531
if ( (sem_num < 0) || (sem_num >= sem_sets[sem_set_id].n_sem) )
532
Error("SemPost: invalid semaphore number in set",sem_num);
534
/* Get the lock around the whole semaphore */
536
(void) mset(ADDR(sem_sets[sem_set_id].lock[sem_num]), 1);
538
/* Read and increment the value. If is now zero wake up
541
sem_sets[sem_set_id].value[sem_num]++;
542
i = sem_sets[sem_set_id].value[sem_num];
544
(void) mclear(ADDR(sem_sets[sem_set_id].lock[sem_num]));
546
(void) mclear(ADDR(sem_sets[sem_set_id].wait[sem_num]));
549
long SemValue(sem_set_id, sem_num)
555
if ( (sem_set_id < 0) || (sem_set_id >= num_sem_set) )
556
Error("SemValue: invalid sem_set_id",sem_set_id);
557
if ( (sem_num < 0) || (sem_num >= sem_sets[sem_set_id].n_sem) )
558
Error("SemValue: invalid semaphore number in set",sem_num);
560
/* There seems no point in getting the lock just to read
561
the value and it seems more useful not to (e.g. debugging) */
563
i = sem_sets[sem_set_id].value[sem_num];
568
long SemSetDestroy(sem_set_id)
572
if ( (sem_set_id < 0) || (sem_set_id >= num_sem_set) )
575
sem_sets[sem_set_id].n_sem = 0;
580
long SemSetDestroyAll()
584
for (i=0; i<num_sem_set; i++)
585
if (sem_sets[i].n_sem)
586
status += SemSetDestroy(i);
591
(void) unlink(filename);
594
status += munmap((char *) sem_sets, 0);
605
#if defined(SGIUS) || defined(SPPLOCKS)
608
SGI fast US library semaphores ... aren't any faster
609
than system V semaphores ... implement using spin locks
615
static volatile int *val;
620
static usptr_t *arena_ptr;
621
static ulock_t *locks[MAX_SEMA];
622
static char arena_name[NAME_LEN];
624
# define LOCK ussetlock
625
# define UNLOCK usunsetlock
630
extern char *getenv(const char *);
632
long SemSetCreate(long n_sem, long value)
636
if (!(tmp = getenv("ARENA_DIR"))) tmp = "/tmp";
638
sprintf(arena_name,"%s/tcgmsg.arena.%ld",tmp, (long)getpid());
640
(void) usconfig(CONF_ARENATYPE, US_SHAREDONLY);
642
(void) usconfig(CONF_INITUSERS, (unsigned int)SR_clus_info[SR_clus_id].nslave );
644
(void) usconfig(CONF_INITSIZE, 1024*1024);
647
if (!(arena_ptr = usinit(arena_name)))
648
Error("SemSetCreate: failed to create arena", 0L);
650
/* Magic factors of EIGHT here to ensure that values are
651
in different cache lines to avoid aliasing -- good on SGI and Convex */
653
if (!(val = (int *) usmalloc(EIGHT*MAX_SEMA*sizeof(int), arena_ptr)))
654
Error("SemSetCreate: failed to get shmem", (long) (MAX_SEMA*sizeof(int)));
656
for (i=0; i<n_sem; i++) {
657
if (!(locks[i] = usnewlock(arena_ptr)))
658
Error("SemSetCreate: failed to create lock", (long) i);
659
val[i*EIGHT] = (int) value;
664
long SemSetDestroyAll()
666
/* usdetach (arena_ptr);*/
676
#include <sys/param.h>
677
#include <sys/file.h>
678
#include <sys/cnx_mman.h>
679
#include <sys/mman.h>
680
#include <sys/types.h>
689
static lock_t *locks;
691
# define LOCK(x) set_lock(&x.state)
692
# define UNLOCK(x) unset_lock(&x.state)
693
# define INILOCK(x) init_lock(&x.state)
696
void init_lock(int * volatile ip)
701
void set_lock(int * volatile ip)
710
void unset_lock(int *ip)
717
static char template[] = "/tmp/SEMA.XXXXXX";
718
static char *filename = (char *) NULL;
719
static unsigned shmem_size;
721
long SemSetCreate(long n_sem, long value)
724
shmem_size = SIXTEEN*MAX_SEMA*sizeof(int)+MAX_SEMA*sizeof(lock_t);
726
if ( (n_sem <= 0) || (n_sem >= MAX_SEMA) )
727
Error("SemSetCreate: n_sem has invalid value",n_sem);
729
/* allocate shared memory for locks and semaphore val */
730
filename = mktemp(template);
731
if ( (fd = open(filename, O_RDWR|O_CREAT, 0666)) < 0 )
732
Error("SemSetCreate: failed to open temporary file",0);
733
val = (int *) mmap((caddr_t) 0, shmem_size,
734
PROT_READ|PROT_WRITE,
735
MAP_ANONYMOUS|CNX_MAP_SEMAPHORE|MAP_SHARED, fd, 0);
736
locks = (lock_t*)( val + SIXTEEN*MAX_SEMA);
738
/* initialize locks and semaphore values */
739
for (i=0; i<n_sem; i++) {
741
val[i*SIXTEEN] = (int) value;
746
long SemSetDestroyAll()
749
if((int)unlink(filename)==-1)Error("SemSetDestroyAll: unlink failed",0);
750
status = munmap((char *) shmem_size, 0);
751
if(status)status = -1;
758
double __tcgmsg_fred__=0.0;
762
int n = 200; /* This seems optimal */
767
void SemWait(long sem_set_id, long sem_num)
770
int off = sem_num*JUMP;
772
if ( (sem_num < 0) || (sem_num >= MAX_SEMA) )
773
Error("SemWait: invalid sem_num",sem_num);
776
LOCK(locks[sem_num]);
780
UNLOCK(locks[sem_num]);
786
void SemPost(long sem_set_id, long sem_num)
788
int off = sem_num*JUMP;
789
if ( (sem_num < 0) || (sem_num >= MAX_SEMA) )
790
Error("SemPost: invalid sem_num",sem_num);
792
LOCK(locks[sem_num]);
794
UNLOCK(locks[sem_num]);
797
long SemValue(long sem_set_id, long sem_num)
799
Error("SemValue: not implemented", sem_num);
803
long SemSetDestroy(long sem_set_id)
805
return(SemSetDestroyAll());
815
#include <sys/fcntl.h>
816
#include <sys/types.h>
817
#include <sys/mman.h>
818
#include <sys/semaphore.h>
822
static char template[] = "/tmp/SEMA.XXXXXX";
823
static char *filename = (char *) NULL;
824
static unsigned shmem_size;
826
#if defined(NAMED_SEMAPHORES_SUPPORTED)
828
static sem_t *sem_arr;
830
long SemSetCreate(long n_sem, long value)
833
shmem_size = MAX_SEMA*sizeof(sem_t);
835
if ( (n_sem <= 0) || (n_sem >= MAX_SEMA) )
836
Error("SemSetCreate: n_sem has invalid value",n_sem);
838
/* allocate shared memory for locks and semaphore val */
839
filename = mktemp(template);
840
if ( (fd = shm_open(filename, O_CREAT|O_RDWR, 0666)) < 0 )
841
Error("SemSetCreate: failed to open temporary shm file",0);
842
sem_arr = (sem_t*) mmap((caddr_t)0, shmem_size, PROT_READ|PROT_WRITE,
843
MAP_ANON|MAP_HASSEMAPHORE|MAP_SHARED, fd, (off_t)0);
844
if(!sem_arr)Error("SemSetCreate: failed to mmap",0);
846
/* initialize locks and semaphore values */
847
for (i=0; i<n_sem; i++) {
848
if(sem_init(sem_arr+i,1,1)<0)
849
Error("SemSetCreate: sem_init failed",(long)i);
854
long SemSetDestroyAll()
857
if((int)unlink(filename)==-1)Error("SemSetDestroyAll: unlink failed",0);
858
status = munmap((char *) shmem_size, 0);
859
if(status)status = -1;
864
void SemWait(long sem_set_id, long sem_num)
866
if ( (sem_num < 0) || (sem_num >= MAX_SEMA) )
867
Error("SemWait: invalid sem_num",sem_num);
868
if(sem_wait(sem_arr+sem_num)<0)
869
Error("SemWait: failed",sem_num);
872
void SemPost(long sem_set_id, long sem_num)
874
if ( (sem_num < 0) || (sem_num >= MAX_SEMA) )
875
Error("SemPost: invalid sem_num",sem_num);
876
if(sem_post(sem_arr+sem_num)<0)
877
Error("SemPost: failed",sem_num);
881
long SemValue(long sem_set_id, long sem_num)
883
Error("SemValue: not implemented", sem_num);
894
static lock_t *locks;
897
static char template1[] = "/tmp/SEMA1.XXXXXX";
898
static char *filename1 = (char *) NULL;
900
static lock_t *locks;
904
long SemSetCreate(long n_sem, long value)
907
shmem_size = MAX_SEMA*sizeof(lock_t);
909
if ( (n_sem <= 0) || (n_sem >= MAX_SEMA) )
910
Error("SemSetCreate: n_sem has invalid value",n_sem);
912
/* allocate shared memory for locks and semaphore val */
913
locks = (lock_t*) mmap((caddr_t)0, shmem_size, PROT_READ|PROT_WRITE,
914
MAP_ANON|MAP_SHARED, -1, (off_t)0);
915
if(locks == (lock_t*)-1)Error("SemSetCreate: failed to mmap",shmem_size);
917
filename1 = mktemp(template1);
918
sem = sem_open(filename1, O_CREAT|O_EXCL, 0666, 1);
919
if(!sem)Error("SemSetCreate: failed to sem_open",0);
921
/* initialize locks and semaphore values */
922
bzero(locks,shmem_size);
926
long SemSetDestroyAll()
929
status = munmap((char *) locks, shmem_size);
930
if(status)status = -1;
931
sem_unlink(filename1);
935
double __tcgmsg_fred__=0.0;
938
int n = 200; /* This seems optimal */
943
void SemWait(long sem_set_id, long sem_num)
945
int value = 0, count=0;
947
if ( (sem_num < 0) || (sem_num >= MAX_SEMA) )
948
Error("SemWait: invalid sem_num",sem_num);
951
if(sem_wait(sem)<0)Error("SemWait: sem_op error",sem_num);;
952
value = locks[sem_num].state;
954
locks[sem_num].state--;
955
if(sem_post(sem)<0)Error("SemWait: sem_op error",sem_num);;
956
if (value<=0) Dummy();
958
if(count%1000 == 999)usleep(1);
962
void SemPost(long sem_set_id, long sem_num)
964
if ( (sem_num < 0) || (sem_num >= MAX_SEMA) )
965
Error("SemPost: invalid sem_num",sem_num);
967
if(sem_wait(sem)<0)Error("SemPost: sem_op error",sem_num);;
968
locks[sem_num].state++;
969
if(sem_post(sem)<0)Error("SemWait: sem_op error",sem_num);;
972
long SemValue(long sem_set_id, long sem_num)
974
if ( (sem_num < 0) || (sem_num >= MAX_SEMA) )
975
Error("SemVal: invalid sem_num",sem_num);
976
return (long)locks[sem_num].state;