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