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