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