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