1 #if HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 /*
6 These routines simplify the interface to semaphores for use in mutual
7 exclusion and queuing. Hopefully I can also make this portable.
8
9 An external routine Error is assumed which is called upon an error
10 and tidies up by calling SemSetDestroyAll.
11
12 In most cases errors cause an internal hard failure (by calling Error).
13
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.
18
19 long SemSetCreate(long n_sem, long value)
20
21 2) Decrement and test the value associated with the semaphore specified by
22 (sem_set_id, sem_num). In effect this:
23
24 if (value >= 0) {
25 continue execution
26 }
27 else {
28 wait in queue for the semaphore
29 }
30 decrement value
31
32 void SemWait(long sem_set_id, long sem_num)
33
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.
37
38 void SemPost(long sem_set_id, long sem_num)
39
40 4) Return the current value associated with the semaphore sepcified by
41 (sem_set_id, sem_num).
42
43 long SemValue(long sem_set_id, long sem_num)
44
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.
50
51 long SemSetDestroy(long sem_set_id)
52
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.
57
58 long SemSetDestroyAll()
59 */
60
61 extern void Error();
62
63 /*
64 SGI fast US library semaphores ... aren't any faster
65 than system V semaphores ... implement using spin locks
66 */
67
68 #include <stdio.h>
69 #include <unistd.h>
70 #define MAX_SEMA 512
71 static volatile int *val;
72 #define NAME_LEN 200
73
74 #ifdef SGI
75 # include <ulocks.h>
76 static usptr_t *arena_ptr;
77 static ulock_t *locks[MAX_SEMA];
78 static char arena_name[NAME_LEN];
79 # define EIGHT 8
80 # define LOCK ussetlock
81 # define UNLOCK usunsetlock
82 #define JUMP EIGHT
83
84 #include "sndrcvP.h"
85
86 extern char *getenv(const char *);
87
SemSetCreate(long n_sem,long value)88 long SemSetCreate(long n_sem, long value)
89 {
90 int i;
91 char *tmp;
92 if (!(tmp = getenv("ARENA_DIR"))) tmp = "/tmp";
93
94 sprintf(arena_name,"%s/tcgmsg.arena.%ld",tmp, (long)getpid());
95 #ifdef PRIVATE_ARENA
96 (void) usconfig(CONF_ARENATYPE, US_SHAREDONLY);
97 #endif
98 (void) usconfig(CONF_INITUSERS, (unsigned int)SR_clus_info[SR_clus_id].nslave );
99 #ifdef SGI
100 (void) usconfig(CONF_INITSIZE, 1024*1024);
101 #endif
102
103 if (!(arena_ptr = usinit(arena_name)))
104 Error("SemSetCreate: failed to create arena", 0L);
105
106 /* Magic factors of EIGHT here to ensure that values are
107 in different cache lines to avoid aliasing -- good on SGI and Convex */
108
109 if (!(val = (int *) usmalloc(EIGHT*MAX_SEMA*sizeof(int), arena_ptr)))
110 Error("SemSetCreate: failed to get shmem", (long) (MAX_SEMA*sizeof(int)));
111
112 for (i=0; i<n_sem; i++) {
113 if (!(locks[i] = usnewlock(arena_ptr)))
114 Error("SemSetCreate: failed to create lock", (long) i);
115 val[i*EIGHT] = (int) value;
116 }
117 return 1L;
118 }
119
SemSetDestroyAll()120 long SemSetDestroyAll()
121 {
122 /* usdetach (arena_ptr);*/
123 arena_ptr = 0;
124 unlink(arena_name);
125 return 0;
126 }
127
128 #endif
129
130
131 #ifdef SPPLOCKS
132 #include <sys/param.h>
133 #include <sys/file.h>
134 #include <sys/cnx_mman.h>
135 #include <sys/mman.h>
136 #include <sys/types.h>
137
138 #define SIXTEEN 16
139 #define JUMP SIXTEEN
140 typedef struct{
141 int state;
142 int pad[15];
143 } lock_t;
144
145 static lock_t *locks;
146
147 # define LOCK(x) set_lock(&x.state)
148 # define UNLOCK(x) unset_lock(&x.state)
149 # define INILOCK(x) init_lock(&x.state)
150
151
init_lock(int * volatile ip)152 void init_lock(int * volatile ip)
153 {
154 *ip = 1;
155 }
156
set_lock(int * volatile ip)157 void set_lock(int * volatile ip)
158 {
159 while (1) {
160 while (!(*ip));
161 if (__ldcws32(ip))
162 break;
163 }
164 }
165
unset_lock(int * ip)166 void unset_lock(int *ip)
167 {
168 *ip = 1;
169 asm("sync");
170 }
171
172 static int fd = -1;
173 static char template[] = "/tmp/SEMA.XXXXXX";
174 static char *filename = (char *) NULL;
175 static unsigned shmem_size;
176
SemSetCreate(long n_sem,long value)177 long SemSetCreate(long n_sem, long value)
178 {
179 int i;
180 shmem_size = SIXTEEN*MAX_SEMA*sizeof(int)+MAX_SEMA*sizeof(lock_t);
181
182 if ( (n_sem <= 0) || (n_sem >= MAX_SEMA) )
183 Error("SemSetCreate: n_sem has invalid value",n_sem);
184
185 /* allocate shared memory for locks and semaphore val */
186 filename = mktemp(template);
187 if ( (fd = open(filename, O_RDWR|O_CREAT, 0666)) < 0 )
188 Error("SemSetCreate: failed to open temporary file",0);
189 val = (int *) mmap((caddr_t) 0, shmem_size,
190 PROT_READ|PROT_WRITE,
191 MAP_ANONYMOUS|CNX_MAP_SEMAPHORE|MAP_SHARED, fd, 0);
192 locks = (lock_t*)( val + SIXTEEN*MAX_SEMA);
193
194 /* initialize locks and semaphore values */
195 for (i=0; i<n_sem; i++) {
196 INILOCK(locks[i]);
197 val[i*SIXTEEN] = (int) value;
198 }
199 return 1L;
200 }
201
SemSetDestroyAll()202 long SemSetDestroyAll()
203 {
204 long status=0;
205 if((int)unlink(filename)==-1)Error("SemSetDestroyAll: unlink failed",0);
206 status = munmap((char *) shmem_size, 0);
207 if(status)status = -1;
208 return status;
209 }
210
211 #endif
212
213
214 double __tcgmsg_fred__=0.0;
215
Dummy()216 void Dummy()
217 {
218 int n = 200; /* This seems optimal */
219 while(n--)
220 __tcgmsg_fred__++;
221 }
222
SemWait(long sem_set_id,long sem_num)223 void SemWait(long sem_set_id, long sem_num)
224 {
225 int value = 0;
226 int off = sem_num*JUMP;
227
228 if ( (sem_num < 0) || (sem_num >= MAX_SEMA) )
229 Error("SemWait: invalid sem_num",sem_num);
230
231 while (value<=0) {
232 LOCK(locks[sem_num]);
233 value = val[off];
234 if (value>0)
235 val[off]--;
236 UNLOCK(locks[sem_num]);
237 if (value<=0)
238 Dummy();
239 }
240 }
241
SemPost(long sem_set_id,long sem_num)242 void SemPost(long sem_set_id, long sem_num)
243 {
244 int off = sem_num*JUMP;
245 if ( (sem_num < 0) || (sem_num >= MAX_SEMA) )
246 Error("SemPost: invalid sem_num",sem_num);
247
248 LOCK(locks[sem_num]);
249 val[off]++;
250 UNLOCK(locks[sem_num]);
251 }
252
SemValue(long sem_set_id,long sem_num)253 long SemValue(long sem_set_id, long sem_num)
254 {
255 Error("SemValue: not implemented", sem_num);
256 return 1;
257 }
258
SemSetDestroy(long sem_set_id)259 long SemSetDestroy(long sem_set_id)
260 {
261 return(SemSetDestroyAll());
262 }
263