pull-prototypes-to-head-20020821
[openafs.git] / src / rx / rx_misc.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID("$Header$");
14
15 #ifdef  KERNEL
16 #include <afs/sysincludes.h>
17 #include <afs/afsincludes.h>
18 #else
19 #ifdef AFS_NT40_ENV
20 #include <winsock2.h>
21 #include <malloc.h>
22 #else
23 #include <sys/param.h>
24 #endif
25 #include <errno.h>
26 #include <afs/errors.h>
27 #include "xdr.h"
28 #ifdef AFS_PTHREAD_ENV
29 #include "rx.h"
30 #endif /* AFS_PTHREAD_ENV */
31 #include <stdlib.h>
32 #ifdef HAVE_STRING_H
33 #include <string.h>
34 #else
35 #ifdef HAVE_STRINGS_H
36 #include <strings.h>
37 #endif
38 #endif
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #endif
43
44 /*
45  * We currently only include below the errors that
46  * affect us the most. We should add to this list
47  * more code mappings, as necessary.
48  */
49
50 /*
51  * Convert from the local (host) to the standard 
52  * (network) system error code.
53  */
54 int hton_syserr_conv(register afs_int32 code)
55 {
56     register afs_int32 err;
57
58     if (code == ENOSPC)
59         err = VDISKFULL;
60 #if !defined(AFS_SUN5_ENV) && !defined(AFS_NT40_ENV) && !defined(AFS_DJGPP_ENV)
61     /* EDQUOT doesn't exist on solaris */
62     else if (code == EDQUOT)
63         err = VOVERQUOTA;
64 #endif
65     else
66         err = code;
67     return err;
68 }
69
70
71 /*
72  * Convert from the standard (Network) format to the
73  * local (host) system error code.
74  */
75 int ntoh_syserr_conv(int code)
76 {
77     register afs_int32 err;
78
79     if (code == VDISKFULL)
80         err = ENOSPC;
81     else if (code == VOVERQUOTA)
82 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_DJGPP_ENV)
83         err = ENOSPC;
84 #else
85         err = EDQUOT;
86 #endif
87     else
88         err = code;
89     return err;
90 }
91
92
93 #ifndef KERNEL
94 /*
95  * We provide the following because some systems (like aix) would fail if we pass
96  * 0 as length.
97  */
98
99 #ifndef osi_alloc
100 #ifdef AFS_PTHREAD_ENV
101 /*
102  * This mutex protects the following global variables:
103  * osi_alloccnt
104  * osi_allocsize
105  */
106      
107 #include <assert.h>
108 pthread_mutex_t osi_malloc_mutex;
109 #define LOCK_MALLOC_STATS assert(pthread_mutex_lock(&osi_malloc_mutex)==0);
110 #define UNLOCK_MALLOC_STATS assert(pthread_mutex_unlock(&osi_malloc_mutex)==0);
111 #else
112 #define LOCK_MALLOC_STATS
113 #define UNLOCK_MALLOC_STATS
114 #endif /* AFS_PTHREAD_ENV */
115 long osi_alloccnt=0, osi_allocsize=0;
116 static const char memZero;
117 char *osi_alloc(afs_int32 x)
118 {
119     /* 
120      * 0-length allocs may return NULL ptr from osi_kalloc, so we special-case
121      * things so that NULL returned iff an error occurred 
122      */
123     if (x == 0) return (char *)&memZero;
124     LOCK_MALLOC_STATS
125     osi_alloccnt++; osi_allocsize += x;
126     UNLOCK_MALLOC_STATS
127     return (char *)(mem_alloc(x));
128 }
129
130 int osi_free(char *x, afs_int32 size)
131 {
132     if ((x == &memZero) || !x) return 0;
133     LOCK_MALLOC_STATS
134     osi_alloccnt--; osi_allocsize -= size;
135     UNLOCK_MALLOC_STATS
136     mem_free(x, size);
137     return 0;
138 }
139 #endif
140 #endif /* KERNEL */
141
142 #if defined(RX_ENABLE_LOCKS) && defined(RX_REFCOUNT_CHECK)
143 int rx_callHoldType = 0;
144 #endif
145
146
147 #ifdef RX_LOCKS_DB
148 /* What follows is a lock database for RX. There is currently room for 400
149  * locks to be held. Routines panic if there is an error. To port, add
150  * RX_LOCKS_DB versions of MUTEX_{ENTER, EXIT, TRYENTER} and CV_*WAIT to
151  * rx_kmutex.h and define lock macros below.
152  */
153 #if (defined(AFS_AIX41_ENV) || (defined(AFS_SGI53_ENV) && defined(MP))) && defined(KERNEL)
154
155 #ifdef AFS_AIX41_ENV
156 Simple_lock rxdb_lock;
157 #define RXDB_LOCK_INIT()        lock_alloc(&rxdb_lock, LOCK_ALLOC_PIN, 1, 0), \
158                                 simple_lock_init(&rxdb_lock)
159 #define RXDB_LOCK_ENTER()       simple_lock(&rxdb_lock)
160 #define RXDB_LOCK_EXIT()        simple_unlock(&rxdb_lock)
161 #else /* AFS_AIX41_ENV */
162 #ifdef AFS_SGI53_ENV
163 afs_kmutex_t rxdb_lock;
164 #define RXDB_LOCK_INIT()        mutex_init(&rxdb_lock, "rxdb lock", 0, 0)
165 #define RXDB_LOCK_ENTER()       AFS_MUTEX_ENTER(&rxdb_lock)
166 #define RXDB_LOCK_EXIT()        mutex_exit(&rxdb_lock)
167 #endif /* AFS_SGI53_ENV */
168 #endif /* AFS_AIX41_ENV */
169
170
171 int RXDB_LockPos = 0;
172
173 #define RXDB_NLOCKS 32
174 struct rxdb_lock_t {
175     afs_int32 id;       /* id of lock holder. */
176     void * a;   /* address of lock. */
177     u_short fileId; /* fileID# of RX file. */
178     u_short line;
179     u_short next; 
180     u_short prev;
181 };
182
183 #define RXDB_HASHSIZE 8
184
185
186 struct rxdb_lock_t rxdb_lockList[RXDB_NLOCKS];
187 short rxdb_idHash[RXDB_HASHSIZE];
188 #define RXDB_IDHASH(id) ((((u_long)id)>>1) & (RXDB_HASHSIZE-1))
189
190 /* Record locations of all locks we enter/exit. */
191 struct rxdb_lockloc_t {
192     u_short fileId; /* fileID# of RX file. */
193     u_short line;
194     u_short next; 
195     u_short prev;
196 };
197 #ifdef RX_LOCKS_COVERAGE
198 #define RXDB_NlockLocs 512
199 #define RXDB_LOCHASHSIZE 256
200 struct rxdb_lockloc_t rxdb_lockLocs[RXDB_NlockLocs];
201 short rxdb_lockLocHash[RXDB_LOCHASHSIZE];
202 #define RXDB_LOCHASH(a) ((((u_long)a)) & (RXDB_LOCHASHSIZE-1))
203 #endif /* RX_LOCKS_COVERAGE */
204
205 /* Element 0 of each of the above arrays serves as the pointer to the list of
206  * free elements.
207  */
208 void
209 rxdb_init(void)
210 {
211     static int initted = 0;
212     int i;
213
214     if (initted)
215         return;
216
217     initted = 1;
218
219     RXDB_LOCK_INIT();
220     RXDB_LOCK_ENTER();
221
222     for (i=1; i<RXDB_NLOCKS-1; i++) {
223         rxdb_lockList[i].next = i + 1;
224         rxdb_lockList[i].prev = i - 1;
225     }
226     rxdb_lockList[0].next = 1;
227     rxdb_lockList[0].prev = 0;
228     rxdb_lockList[RXDB_NLOCKS-1].next = 0;
229     rxdb_lockList[RXDB_NLOCKS-1].prev = RXDB_NLOCKS - 2;
230
231 #ifdef RX_LOCKS_COVERAGE
232     for (i=1; i<RXDB_NlockLocs-1; i++) {
233         rxdb_lockLocs[i].next = i + 1;
234         rxdb_lockLocs[i].prev = i - 1;
235     }
236     rxdb_lockLocs[0].next = 1;
237     rxdb_lockLocs[0].prev = 0;
238     rxdb_lockLocs[RXDB_NlockLocs-1].next = 0;
239     rxdb_lockLocs[RXDB_NlockLocs-1].prev = RXDB_NlockLocs - 2;
240 #endif /* RX_LOCKS_COVERAGE */
241
242     RXDB_LOCK_EXIT();
243 }
244
245 #ifdef RX_LOCKS_COVERAGE
246 void
247 rxdb_RecordLockLocation(fileId, line)
248 afs_int32 fileId, line;
249 {
250     u_short i, j;
251
252     i = RXDB_LOCHASH(line);
253
254     /* Only enter lock location into list once. */
255     for (j=rxdb_lockLocHash[i]; j; j = rxdb_lockLocs[j].next) {
256         if ((rxdb_lockLocs[j].line == line)
257             && (rxdb_lockLocs[j].fileId == fileId))
258             return;
259     }
260         
261     /* Add lock to list. */
262     j = rxdb_lockLocs[0].next;
263     if (j==0) {
264         osi_Panic("rxdb_initLock: used up all the lock locations.\n");
265     }
266
267     /* Fix up free list. */
268     rxdb_lockLocs[0].next = rxdb_lockLocs[j].next;
269
270     /* Put new element at head of list. */
271     rxdb_lockLocs[j].next = rxdb_lockLocHash[i];
272     rxdb_lockLocs[j].prev = 0;
273     if (rxdb_lockLocHash[i]) {
274         rxdb_lockLocs[rxdb_lockLocHash[i]].prev = j;
275     }
276     rxdb_lockLocHash[i] = j;
277
278     /* Set data in element. */
279     rxdb_lockLocs[j].fileId = fileId;
280     rxdb_lockLocs[j].line = line;
281
282 }
283 #endif /* RX_LOCKS_COVERAGE */
284
285
286 /* Set lock as possessed by me. */
287 void
288 rxdb_grablock(a, id, fileId, line)
289 void * a;
290 afs_int32 id;
291 afs_int32 fileId;
292 afs_int32 line;
293 {
294     int i, j, k;
295
296     RXDB_LOCK_ENTER();
297 #ifdef RX_LOCKS_COVERAGE
298     rxdb_RecordLockLocation(fileId, line);
299 #endif /* RX_LOCKS_COVERAGE */
300     /* Is lock already held by anyone? */
301     for (i=0; i<RXDB_HASHSIZE; i++) {
302         for (j=rxdb_idHash[i]; j; j = rxdb_lockList[j].next) {
303             if (rxdb_lockList[j].a == a) {
304                 RXDB_LockPos = j;
305                 osi_Panic("rxdb_grablock: lock already held.");
306             }
307         }
308     }
309
310     i = RXDB_IDHASH(id);
311     j = rxdb_lockList[0].next;
312     if (j==0) {
313         osi_Panic("rxdb_grablock: rxdb_lockList is full.");
314     }
315     rxdb_lockList[0].next = rxdb_lockList[j].next;
316
317     /* Put element at head of list. */
318     rxdb_lockList[j].next = rxdb_idHash[i];
319     rxdb_lockList[j].prev = 0;
320     if (rxdb_idHash[i]) {
321         rxdb_lockList[rxdb_idHash[i]].prev = j;
322     }
323     rxdb_idHash[i] = j;
324
325     /* Set data into element. */
326     rxdb_lockList[j].a = a;
327     rxdb_lockList[j].id = id;
328     rxdb_lockList[j].fileId = fileId;
329     rxdb_lockList[j].line = line;
330
331     RXDB_LOCK_EXIT();
332 }
333
334 /* unlock */
335 rxdb_droplock(a, id, fileId, line)
336 void * a;
337 afs_int32 id;
338 int fileId;
339 int line;
340 {
341     int i, j;
342     int found;
343
344     RXDB_LOCK_ENTER();
345 #ifdef RX_LOCKS_COVERAGE
346     rxdb_RecordLockLocation(fileId, line);
347 #endif /* RX_LOCKS_COVERAGE */
348     found = 0;
349
350     /* Do I have the lock? */
351     i = rxdb_idHash[RXDB_IDHASH(id)];
352     for(j=i;  j; j = rxdb_lockList[j].next) {
353         if (rxdb_lockList[j].a == a) {
354             found = 1;
355             break;
356         }
357     }
358
359     if (!found) {
360         osi_Panic("rxdb_unlock: lock not held by me.\n");
361     }
362
363     /* delete lock from queue. */
364     if (i==j) {
365         /* head of list. */
366         i = RXDB_IDHASH(id);
367         rxdb_idHash[i] = rxdb_lockList[j].next;
368         rxdb_lockList[rxdb_lockList[j].next].prev = 0;
369     }
370     else {
371         if (rxdb_lockList[j].next)
372             rxdb_lockList[rxdb_lockList[j].next].prev = rxdb_lockList[j].prev;
373         rxdb_lockList[rxdb_lockList[j].prev].next = rxdb_lockList[j].next;
374     }
375     /* Put back on free list. */
376     rxdb_lockList[j].next = rxdb_lockList[0].next;
377     rxdb_lockList[j].prev = 0;
378     rxdb_lockList[0].next = j;
379
380     RXDB_LOCK_EXIT();
381 }    
382     
383 #endif /* (AIX41 || SGI53) && KERNEL */
384
385 #endif /* RX_LOCKS_DB */