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