Version information for db-2 library.
[kopensolaris-gnu/glibc.git] / db2 / lock / lock_region.c
1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 1996, 1997, 1998
5  *      Sleepycat Software.  All rights reserved.
6  */
7
8 #include "config.h"
9
10 #ifndef lint
11 static const char sccsid[] = "@(#)lock_region.c 10.15 (Sleepycat) 6/2/98";
12 #endif /* not lint */
13
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
16
17 #include <ctype.h>
18 #include <errno.h>
19 #include <string.h>
20 #endif
21
22 #include "db_int.h"
23 #include "shqueue.h"
24 #include "db_shash.h"
25 #include "lock.h"
26 #include "common_ext.h"
27
28 static u_int32_t __lock_count_locks __P((DB_LOCKREGION *));
29 static u_int32_t __lock_count_objs __P((DB_LOCKREGION *));
30 static void      __lock_dump_locker __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *));
31 static void      __lock_dump_object __P((DB_LOCKTAB *, DB_LOCKOBJ *, FILE *));
32 static const char *__lock_dump_status __P((db_status_t));
33 static void      __lock_reset_region __P((DB_LOCKTAB *));
34 static int       __lock_tabinit __P((DB_ENV *, DB_LOCKREGION *));
35
36 int
37 lock_open(path, flags, mode, dbenv, ltp)
38         const char *path;
39         u_int32_t flags;
40         int mode;
41         DB_ENV *dbenv;
42         DB_LOCKTAB **ltp;
43 {
44         DB_LOCKTAB *lt;
45         u_int32_t lock_modes, maxlocks, regflags;
46         int ret;
47
48         /* Validate arguments. */
49 #ifdef HAVE_SPINLOCKS
50 #define OKFLAGS (DB_CREATE | DB_THREAD)
51 #else
52 #define OKFLAGS (DB_CREATE)
53 #endif
54         if ((ret = __db_fchk(dbenv, "lock_open", flags, OKFLAGS)) != 0)
55                 return (ret);
56
57         /* Create the lock table structure. */
58         if ((lt = (DB_LOCKTAB *)__db_calloc(1, sizeof(DB_LOCKTAB))) == NULL) {
59                 __db_err(dbenv, "%s", strerror(ENOMEM));
60                 return (ENOMEM);
61         }
62         lt->dbenv = dbenv;
63
64         /* Grab the values that we need to compute the region size. */
65         lock_modes = DB_LOCK_RW_N;
66         maxlocks = DB_LOCK_DEFAULT_N;
67         regflags = REGION_SIZEDEF;
68         if (dbenv != NULL) {
69                 if (dbenv->lk_modes != 0) {
70                         lock_modes = dbenv->lk_modes;
71                         regflags = 0;
72                 }
73                 if (dbenv->lk_max != 0) {
74                         maxlocks = dbenv->lk_max;
75                         regflags = 0;
76                 }
77         }
78
79         /* Join/create the lock region. */
80         lt->reginfo.dbenv = dbenv;
81         lt->reginfo.appname = DB_APP_NONE;
82         if (path == NULL)
83                 lt->reginfo.path = NULL;
84         else
85                 if ((lt->reginfo.path = (char *)__db_strdup(path)) == NULL)
86                         goto err;
87         lt->reginfo.file = DB_DEFAULT_LOCK_FILE;
88         lt->reginfo.mode = mode;
89         lt->reginfo.size =
90             LOCK_REGION_SIZE(lock_modes, maxlocks, __db_tablesize(maxlocks));
91         lt->reginfo.dbflags = flags;
92         lt->reginfo.addr = NULL;
93         lt->reginfo.fd = -1;
94         lt->reginfo.flags = regflags;
95
96         if ((ret = __db_rattach(&lt->reginfo)) != 0)
97                 goto err;
98
99         /* Now set up the pointer to the region. */
100         lt->region = lt->reginfo.addr;
101
102         /* Initialize the region if we created it. */
103         if (F_ISSET(&lt->reginfo, REGION_CREATED)) {
104                 lt->region->maxlocks = maxlocks;
105                 lt->region->nmodes = lock_modes;
106                 if ((ret = __lock_tabinit(dbenv, lt->region)) != 0)
107                         goto err;
108         } else {
109                 /* Check for an unexpected region. */
110                 if (lt->region->magic != DB_LOCKMAGIC) {
111                         __db_err(dbenv,
112                             "lock_open: %s: bad magic number", path);
113                         ret = EINVAL;
114                         goto err;
115                 }
116         }
117
118         /* Check for automatic deadlock detection. */
119         if (dbenv != NULL && dbenv->lk_detect != DB_LOCK_NORUN) {
120                 if (lt->region->detect != DB_LOCK_NORUN &&
121                     dbenv->lk_detect != DB_LOCK_DEFAULT &&
122                     lt->region->detect != dbenv->lk_detect) {
123                         __db_err(dbenv,
124                     "lock_open: incompatible deadlock detector mode");
125                         ret = EINVAL;
126                         goto err;
127                 }
128                 if (lt->region->detect == DB_LOCK_NORUN)
129                         lt->region->detect = dbenv->lk_detect;
130         }
131
132         /* Set up remaining pointers into region. */
133         lt->conflicts = (u_int8_t *)lt->region + sizeof(DB_LOCKREGION);
134         lt->hashtab =
135             (DB_HASHTAB *)((u_int8_t *)lt->region + lt->region->hash_off);
136         lt->mem = (void *)((u_int8_t *)lt->region + lt->region->mem_off);
137
138         UNLOCK_LOCKREGION(lt);
139         *ltp = lt;
140         return (0);
141
142 err:    if (lt->reginfo.addr != NULL) {
143                 UNLOCK_LOCKREGION(lt);
144                 (void)__db_rdetach(&lt->reginfo);
145                 if (F_ISSET(&lt->reginfo, REGION_CREATED))
146                         (void)lock_unlink(path, 1, dbenv);
147         }
148
149         if (lt->reginfo.path != NULL)
150                 FREES(lt->reginfo.path);
151         FREE(lt, sizeof(*lt));
152         return (ret);
153 }
154
155 /*
156  * __lock_tabinit --
157  *      Initialize the lock region.
158  */
159 static int
160 __lock_tabinit(dbenv, lrp)
161         DB_ENV *dbenv;
162         DB_LOCKREGION *lrp;
163 {
164         struct __db_lock *lp;
165         struct lock_header *tq_head;
166         struct obj_header *obj_head;
167         DB_LOCKOBJ *op;
168         u_int32_t i, nelements;
169         const u_int8_t *conflicts;
170         u_int8_t *curaddr;
171
172         conflicts = dbenv == NULL || dbenv->lk_conflicts == NULL ?
173             db_rw_conflicts : dbenv->lk_conflicts;
174
175         lrp->table_size = __db_tablesize(lrp->maxlocks);
176         lrp->magic = DB_LOCKMAGIC;
177         lrp->version = DB_LOCKVERSION;
178         lrp->id = 0;
179         /*
180          * These fields (lrp->maxlocks, lrp->nmodes) are initialized
181          * in the caller, since we had to grab those values to size
182          * the region.
183          */
184         lrp->need_dd = 0;
185         lrp->detect = DB_LOCK_NORUN;
186         lrp->numobjs = lrp->maxlocks;
187         lrp->nlockers = 0;
188         lrp->mem_bytes = ALIGN(STRING_SIZE(lrp->maxlocks), sizeof(size_t));
189         lrp->increment = lrp->hdr.size / 2;
190         lrp->nconflicts = 0;
191         lrp->nrequests = 0;
192         lrp->nreleases = 0;
193         lrp->ndeadlocks = 0;
194
195         /*
196          * As we write the region, we've got to maintain the alignment
197          * for the structures that follow each chunk.  This information
198          * ends up being encapsulated both in here as well as in the
199          * lock.h file for the XXX_SIZE macros.
200          */
201         /* Initialize conflict matrix. */
202         curaddr = (u_int8_t *)lrp + sizeof(DB_LOCKREGION);
203         memcpy(curaddr, conflicts, lrp->nmodes * lrp->nmodes);
204         curaddr += lrp->nmodes * lrp->nmodes;
205
206         /*
207          * Initialize hash table.
208          */
209         curaddr = (u_int8_t *)ALIGNP(curaddr, LOCK_HASH_ALIGN);
210         lrp->hash_off = curaddr - (u_int8_t *)lrp;
211         nelements = lrp->table_size;
212         __db_hashinit(curaddr, nelements);
213         curaddr += nelements * sizeof(DB_HASHTAB);
214
215         /*
216          * Initialize locks onto a free list. Since locks contains mutexes,
217          * we need to make sure that each lock is aligned on a MUTEX_ALIGNMENT
218          * boundary.
219          */
220         curaddr = (u_int8_t *)ALIGNP(curaddr, MUTEX_ALIGNMENT);
221         tq_head = &lrp->free_locks;
222         SH_TAILQ_INIT(tq_head);
223
224         for (i = 0; i++ < lrp->maxlocks;
225             curaddr += ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT)) {
226                 lp = (struct __db_lock *)curaddr;
227                 lp->status = DB_LSTAT_FREE;
228                 SH_TAILQ_INSERT_HEAD(tq_head, lp, links, __db_lock);
229         }
230
231         /* Initialize objects onto a free list.  */
232         obj_head = &lrp->free_objs;
233         SH_TAILQ_INIT(obj_head);
234
235         for (i = 0; i++ < lrp->maxlocks; curaddr += sizeof(DB_LOCKOBJ)) {
236                 op = (DB_LOCKOBJ *)curaddr;
237                 SH_TAILQ_INSERT_HEAD(obj_head, op, links, __db_lockobj);
238         }
239
240         /*
241          * Initialize the string space; as for all shared memory allocation
242          * regions, this requires size_t alignment, since we store the
243          * lengths of malloc'd areas in the area.
244          */
245         curaddr = (u_int8_t *)ALIGNP(curaddr, sizeof(size_t));
246         lrp->mem_off = curaddr - (u_int8_t *)lrp;
247         __db_shalloc_init(curaddr, lrp->mem_bytes);
248         return (0);
249 }
250
251 int
252 lock_close(lt)
253         DB_LOCKTAB *lt;
254 {
255         int ret;
256
257         if ((ret = __db_rdetach(&lt->reginfo)) != 0)
258                 return (ret);
259
260         if (lt->reginfo.path != NULL)
261                 FREES(lt->reginfo.path);
262         FREE(lt, sizeof(*lt));
263
264         return (0);
265 }
266
267 int
268 lock_unlink(path, force, dbenv)
269         const char *path;
270         int force;
271         DB_ENV *dbenv;
272 {
273         REGINFO reginfo;
274         int ret;
275
276         memset(&reginfo, 0, sizeof(reginfo));
277         reginfo.dbenv = dbenv;
278         reginfo.appname = DB_APP_NONE;
279         if (path != NULL && (reginfo.path = (char *)__db_strdup(path)) == NULL)
280                 return (ENOMEM);
281         reginfo.file = DB_DEFAULT_LOCK_FILE;
282         ret = __db_runlink(&reginfo, force);
283         if (reginfo.path != NULL)
284                 FREES(reginfo.path);
285         return (ret);
286 }
287
288 /*
289  * __lock_validate_region --
290  *      Called at every interface to verify if the region has changed size,
291  *      and if so, to remap the region in and reset the process' pointers.
292  *
293  * PUBLIC: int __lock_validate_region __P((DB_LOCKTAB *));
294  */
295 int
296 __lock_validate_region(lt)
297         DB_LOCKTAB *lt;
298 {
299         int ret;
300
301         if (lt->reginfo.size == lt->region->hdr.size)
302                 return (0);
303
304         /* Detach/reattach the region. */
305         if ((ret = __db_rreattach(&lt->reginfo, lt->region->hdr.size)) != 0)
306                 return (ret);
307
308         /* Reset region information. */
309         lt->region = lt->reginfo.addr;
310         __lock_reset_region(lt);
311
312         return (0);
313 }
314
315 /*
316  * __lock_grow_region --
317  *      We have run out of space; time to grow the region.
318  *
319  * PUBLIC: int __lock_grow_region __P((DB_LOCKTAB *, int, size_t));
320  */
321 int
322 __lock_grow_region(lt, which, howmuch)
323         DB_LOCKTAB *lt;
324         int which;
325         size_t howmuch;
326 {
327         struct __db_lock *newl;
328         struct lock_header *lock_head;
329         struct obj_header *obj_head;
330         DB_LOCKOBJ *op;
331         DB_LOCKREGION *lrp;
332         float lock_ratio, obj_ratio;
333         size_t incr, oldsize, used, usedmem;
334         u_int32_t i, newlocks, newmem, newobjs, usedlocks, usedobjs;
335         u_int8_t *curaddr;
336         int ret;
337
338         lrp = lt->region;
339         oldsize = lrp->hdr.size;
340         incr = lrp->increment;
341
342         /* Figure out how much of each sort of space we have. */
343         usedmem = lrp->mem_bytes - __db_shalloc_count(lt->mem);
344         usedobjs = lrp->numobjs - __lock_count_objs(lrp);
345         usedlocks = lrp->maxlocks - __lock_count_locks(lrp);
346
347         /*
348          * Figure out what fraction of the used space belongs to each
349          * different type of "thing" in the region.  Then partition the
350          * new space up according to this ratio.
351          */
352         used = usedmem +
353             usedlocks * ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT) +
354             usedobjs * sizeof(DB_LOCKOBJ);
355
356         lock_ratio = usedlocks *
357             ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT) / (float)used;
358         obj_ratio = usedobjs * sizeof(DB_LOCKOBJ) / (float)used;
359
360         newlocks = (u_int32_t)(lock_ratio *
361             incr / ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT));
362         newobjs = (u_int32_t)(obj_ratio * incr / sizeof(DB_LOCKOBJ));
363         newmem = incr -
364             (newobjs * sizeof(DB_LOCKOBJ) +
365             newlocks * ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT));
366
367         /*
368          * Make sure we allocate enough memory for the object being
369          * requested.
370          */
371         switch (which) {
372         case DB_LOCK_LOCK:
373                 if (newlocks == 0) {
374                         newlocks = 10;
375                         incr += newlocks * sizeof(struct __db_lock);
376                 }
377                 break;
378         case DB_LOCK_OBJ:
379                 if (newobjs == 0) {
380                         newobjs = 10;
381                         incr += newobjs * sizeof(DB_LOCKOBJ);
382                 }
383                 break;
384         case DB_LOCK_MEM:
385                 if (newmem < howmuch * 2) {
386                         incr += howmuch * 2 - newmem;
387                         newmem = howmuch * 2;
388                 }
389                 break;
390         }
391
392         newmem += ALIGN(incr, sizeof(size_t)) - incr;
393         incr = ALIGN(incr, sizeof(size_t));
394
395         /*
396          * Since we are going to be allocating locks at the beginning of the
397          * new chunk, we need to make sure that the chunk is MUTEX_ALIGNMENT
398          * aligned.  We did not guarantee this when we created the region, so
399          * we may need to pad the old region by extra bytes to ensure this
400          * alignment.
401          */
402         incr += ALIGN(oldsize, MUTEX_ALIGNMENT) - oldsize;
403
404         __db_err(lt->dbenv,
405             "Growing lock region: %lu locks %lu objs %lu bytes",
406             (u_long)newlocks, (u_long)newobjs, (u_long)newmem);
407
408         if ((ret = __db_rgrow(&lt->reginfo, oldsize + incr)) != 0)
409                 return (ret);
410         lt->region = lt->reginfo.addr;
411         __lock_reset_region(lt);
412
413         /* Update region parameters. */
414         lrp = lt->region;
415         lrp->increment = incr << 1;
416         lrp->maxlocks += newlocks;
417         lrp->numobjs += newobjs;
418         lrp->mem_bytes += newmem;
419
420         curaddr = (u_int8_t *)lrp + oldsize;
421         curaddr = (u_int8_t *)ALIGNP(curaddr, MUTEX_ALIGNMENT);
422
423         /* Put new locks onto the free list. */
424         lock_head = &lrp->free_locks;
425         for (i = 0; i++ < newlocks;
426             curaddr += ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT)) {
427                 newl = (struct __db_lock *)curaddr;
428                 SH_TAILQ_INSERT_HEAD(lock_head, newl, links, __db_lock);
429         }
430
431         /* Put new objects onto the free list.  */
432         obj_head = &lrp->free_objs;
433         for (i = 0; i++ < newobjs; curaddr += sizeof(DB_LOCKOBJ)) {
434                 op = (DB_LOCKOBJ *)curaddr;
435                 SH_TAILQ_INSERT_HEAD(obj_head, op, links, __db_lockobj);
436         }
437
438         *((size_t *)curaddr) = newmem - sizeof(size_t);
439         curaddr += sizeof(size_t);
440         __db_shalloc_free(lt->mem, curaddr);
441
442         return (0);
443 }
444
445 static void
446 __lock_reset_region(lt)
447         DB_LOCKTAB *lt;
448 {
449         lt->conflicts = (u_int8_t *)lt->region + sizeof(DB_LOCKREGION);
450         lt->hashtab =
451             (DB_HASHTAB *)((u_int8_t *)lt->region + lt->region->hash_off);
452         lt->mem = (void *)((u_int8_t *)lt->region + lt->region->mem_off);
453 }
454
455 /*
456  * lock_stat --
457  *      Return LOCK statistics.
458  */
459 int
460 lock_stat(lt, gspp, db_malloc)
461         DB_LOCKTAB *lt;
462         DB_LOCK_STAT **gspp;
463         void *(*db_malloc) __P((size_t));
464 {
465         DB_LOCKREGION *rp;
466
467         *gspp = NULL;
468
469         if ((*gspp = db_malloc == NULL ?
470             (DB_LOCK_STAT *)__db_malloc(sizeof(**gspp)) :
471             (DB_LOCK_STAT *)db_malloc(sizeof(**gspp))) == NULL)
472                 return (ENOMEM);
473
474         /* Copy out the global statistics. */
475         LOCK_LOCKREGION(lt);
476
477         rp = lt->region;
478         (*gspp)->st_magic = rp->magic;
479         (*gspp)->st_version = rp->version;
480         (*gspp)->st_maxlocks = rp->maxlocks;
481         (*gspp)->st_nmodes = rp->nmodes;
482         (*gspp)->st_numobjs = rp->numobjs;
483         (*gspp)->st_nlockers = rp->nlockers;
484         (*gspp)->st_nconflicts = rp->nconflicts;
485         (*gspp)->st_nrequests = rp->nrequests;
486         (*gspp)->st_nreleases = rp->nreleases;
487         (*gspp)->st_ndeadlocks = rp->ndeadlocks;
488         (*gspp)->st_region_nowait = rp->hdr.lock.mutex_set_nowait;
489         (*gspp)->st_region_wait = rp->hdr.lock.mutex_set_wait;
490         (*gspp)->st_refcnt = rp->hdr.refcnt;
491         (*gspp)->st_regsize = rp->hdr.size;
492
493         UNLOCK_LOCKREGION(lt);
494
495         return (0);
496 }
497
498 static u_int32_t
499 __lock_count_locks(lrp)
500         DB_LOCKREGION *lrp;
501 {
502         struct __db_lock *newl;
503         u_int32_t count;
504
505         count = 0;
506         for (newl = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock);
507             newl != NULL;
508             newl = SH_TAILQ_NEXT(newl, links, __db_lock))
509                 count++;
510
511         return (count);
512 }
513
514 static u_int32_t
515 __lock_count_objs(lrp)
516         DB_LOCKREGION *lrp;
517 {
518         DB_LOCKOBJ *obj;
519         u_int32_t count;
520
521         count = 0;
522         for (obj = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
523             obj != NULL;
524             obj = SH_TAILQ_NEXT(obj, links, __db_lockobj))
525                 count++;
526
527         return (count);
528 }
529
530 #define LOCK_DUMP_CONF          0x001           /* Conflict matrix. */
531 #define LOCK_DUMP_FREE          0x002           /* Display lock free list. */
532 #define LOCK_DUMP_LOCKERS       0x004           /* Display lockers. */
533 #define LOCK_DUMP_MEM           0x008           /* Display region memory. */
534 #define LOCK_DUMP_OBJECTS       0x010           /* Display objects. */
535 #define LOCK_DUMP_ALL           0x01f           /* Display all. */
536
537 /*
538  * __lock_dump_region --
539  *
540  * PUBLIC: void __lock_dump_region __P((DB_LOCKTAB *, char *, FILE *));
541  */
542 void
543 __lock_dump_region(lt, area, fp)
544         DB_LOCKTAB *lt;
545         char *area;
546         FILE *fp;
547 {
548         struct __db_lock *lp;
549         DB_LOCKOBJ *op;
550         DB_LOCKREGION *lrp;
551         u_int32_t flags, i, j;
552         int label;
553
554         /* Make it easy to call from the debugger. */
555         if (fp == NULL)
556                 fp = stderr;
557
558         for (flags = 0; *area != '\0'; ++area)
559                 switch (*area) {
560                 case 'A':
561                         LF_SET(LOCK_DUMP_ALL);
562                         break;
563                 case 'c':
564                         LF_SET(LOCK_DUMP_CONF);
565                         break;
566                 case 'f':
567                         LF_SET(LOCK_DUMP_FREE);
568                         break;
569                 case 'l':
570                         LF_SET(LOCK_DUMP_LOCKERS);
571                         break;
572                 case 'm':
573                         LF_SET(LOCK_DUMP_MEM);
574                         break;
575                 case 'o':
576                         LF_SET(LOCK_DUMP_OBJECTS);
577                         break;
578                 }
579
580         lrp = lt->region;
581
582         fprintf(fp, "%s\nLock region parameters\n", DB_LINE);
583         fprintf(fp, "%s: %lu, %s: %lu, %s: %lu, %s: %lu\n%s: %lu, %s: %lu\n",
584             "table size", (u_long)lrp->table_size,
585             "hash_off", (u_long)lrp->hash_off,
586             "increment", (u_long)lrp->increment,
587             "mem_off", (u_long)lrp->mem_off,
588             "mem_bytes", (u_long)lrp->mem_bytes,
589             "need_dd", (u_long)lrp->need_dd);
590
591         if (LF_ISSET(LOCK_DUMP_CONF)) {
592                 fprintf(fp, "\n%s\nConflict matrix\n", DB_LINE);
593                 for (i = 0; i < lrp->nmodes; i++) {
594                         for (j = 0; j < lrp->nmodes; j++)
595                                 fprintf(fp, "%lu\t",
596                                     (u_long)lt->conflicts[i * lrp->nmodes + j]);
597                         fprintf(fp, "\n");
598                 }
599         }
600
601         if (LF_ISSET(LOCK_DUMP_LOCKERS | LOCK_DUMP_OBJECTS)) {
602                 fprintf(fp, "%s\nLock hash buckets\n", DB_LINE);
603                 for (i = 0; i < lrp->table_size; i++) {
604                         label = 1;
605                         for (op = SH_TAILQ_FIRST(&lt->hashtab[i], __db_lockobj);
606                             op != NULL;
607                             op = SH_TAILQ_NEXT(op, links, __db_lockobj)) {
608                                 if (LF_ISSET(LOCK_DUMP_LOCKERS) &&
609                                     op->type == DB_LOCK_LOCKER) {
610                                         if (label) {
611                                                 fprintf(fp,
612                                                     "Bucket %lu:\n", (u_long)i);
613                                                 label = 0;
614                                         }
615                                         __lock_dump_locker(lt, op, fp);
616                                 }
617                                 if (LF_ISSET(LOCK_DUMP_OBJECTS) &&
618                                     op->type == DB_LOCK_OBJTYPE) {
619                                         if (label) {
620                                                 fprintf(fp,
621                                                     "Bucket %lu:\n", (u_long)i);
622                                                 label = 0;
623                                         }
624                                         __lock_dump_object(lt, op, fp);
625                                 }
626                         }
627                 }
628         }
629
630         if (LF_ISSET(LOCK_DUMP_FREE)) {
631                 fprintf(fp, "%s\nLock free list\n", DB_LINE);
632                 for (lp = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock);
633                     lp != NULL;
634                     lp = SH_TAILQ_NEXT(lp, links, __db_lock))
635                         fprintf(fp, "0x%x: %lu\t%lu\t%s\t0x%x\n", (u_int)lp,
636                             (u_long)lp->holder, (u_long)lp->mode,
637                             __lock_dump_status(lp->status), (u_int)lp->obj);
638
639                 fprintf(fp, "%s\nObject free list\n", DB_LINE);
640                 for (op = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
641                     op != NULL;
642                     op = SH_TAILQ_NEXT(op, links, __db_lockobj))
643                         fprintf(fp, "0x%x\n", (u_int)op);
644         }
645
646         if (LF_ISSET(LOCK_DUMP_MEM))
647                 __db_shalloc_dump(lt->mem, fp);
648 }
649
650 static void
651 __lock_dump_locker(lt, op, fp)
652         DB_LOCKTAB *lt;
653         DB_LOCKOBJ *op;
654         FILE *fp;
655 {
656         struct __db_lock *lp;
657         u_int32_t locker;
658         void *ptr;
659
660         ptr = SH_DBT_PTR(&op->lockobj);
661         memcpy(&locker, ptr, sizeof(u_int32_t));
662         fprintf(fp, "L %lx", (u_long)locker);
663
664         lp = SH_LIST_FIRST(&op->heldby, __db_lock);
665         if (lp == NULL) {
666                 fprintf(fp, "\n");
667                 return;
668         }
669         for (; lp != NULL; lp = SH_LIST_NEXT(lp, locker_links, __db_lock))
670                 __lock_printlock(lt, lp, 0);
671 }
672
673 static void
674 __lock_dump_object(lt, op, fp)
675         DB_LOCKTAB *lt;
676         DB_LOCKOBJ *op;
677         FILE *fp;
678 {
679         struct __db_lock *lp;
680         u_int32_t j;
681         u_int8_t *ptr;
682         u_int ch;
683
684         ptr = SH_DBT_PTR(&op->lockobj);
685         for (j = 0; j < op->lockobj.size; ptr++, j++) {
686                 ch = *ptr;
687                 fprintf(fp, isprint(ch) ? "%c" : "\\%o", ch);
688         }
689         fprintf(fp, "\n");
690
691         fprintf(fp, "H:");
692         for (lp =
693             SH_TAILQ_FIRST(&op->holders, __db_lock);
694             lp != NULL;
695             lp = SH_TAILQ_NEXT(lp, links, __db_lock))
696                 __lock_printlock(lt, lp, 0);
697         lp = SH_TAILQ_FIRST(&op->waiters, __db_lock);
698         if (lp != NULL) {
699                 fprintf(fp, "\nW:");
700                 for (; lp != NULL; lp = SH_TAILQ_NEXT(lp, links, __db_lock))
701                         __lock_printlock(lt, lp, 0);
702         }
703 }
704
705 static const char *
706 __lock_dump_status(status)
707         db_status_t status;
708 {
709         switch (status) {
710         case DB_LSTAT_ABORTED:
711                 return ("aborted");
712         case DB_LSTAT_ERR:
713                 return ("err");
714         case DB_LSTAT_FREE:
715                 return ("free");
716         case DB_LSTAT_HELD:
717                 return ("held");
718         case DB_LSTAT_NOGRANT:
719                 return ("nogrant");
720         case DB_LSTAT_PENDING:
721                 return ("pending");
722         case DB_LSTAT_WAITING:
723                 return ("waiting");
724         }
725         return ("unknown status");
726 }