1 /*-
2  * Copyright (c) 1996, 2020 Oracle and/or its affiliates.  All rights reserved.
3  *
4  * See the file LICENSE for license information.
5  *
6  * $Id$
7  */
8 
9 #include "db_config.h"
10 
11 #include "db_int.h"
12 #include "dbinc/db_page.h"
13 #include "dbinc/db_am.h"
14 
15 #ifdef HAVE_STATISTICS
16 static int __mutex_print_all __P((ENV *, u_int32_t));
17 static const char *__mutex_print_id __P((int));
18 static int __mutex_print_stats __P((ENV *, u_int32_t));
19 static void __mutex_print_summary __P((ENV *));
20 static int __mutex_stat __P((ENV *, DB_MUTEX_STAT **, u_int32_t));
21 
22 static const FN MutexFlagNames[] = {
23 	{ DB_MUTEX_ALLOCATED,		"alloc" },
24 	{ DB_MUTEX_LOCKED,		"locked" },
25 	{ DB_MUTEX_LOGICAL_LOCK,	"logical" },
26 	{ DB_MUTEX_OWNER_DEAD,		"ower-dead" },
27 	{ DB_MUTEX_PROCESS_ONLY,	"process-private" },
28 	{ DB_MUTEX_SELF_BLOCK,		"self-block" },
29 	{ DB_MUTEX_SHARED,		"shared" },
30 	{ 0,				NULL }
31 };
32 
33 /*
34  * __mutex_stat_pp --
35  *	ENV->mutex_stat pre/post processing.
36  *
37  * PUBLIC: int __mutex_stat_pp __P((DB_ENV *, DB_MUTEX_STAT **, u_int32_t));
38  */
39 int
__mutex_stat_pp(dbenv,statp,flags)40 __mutex_stat_pp(dbenv, statp, flags)
41 	DB_ENV *dbenv;
42 	DB_MUTEX_STAT **statp;
43 	u_int32_t flags;
44 {
45 	DB_THREAD_INFO *ip;
46 	ENV *env;
47 	int ret;
48 
49 	env = dbenv->env;
50 
51 	ENV_REQUIRES_CONFIG(env,
52 	    env->mutex_handle, "DB_ENV->mutex_stat", DB_INIT_MUTEX);
53 
54 	if ((ret = __db_fchk(env,
55 	    "DB_ENV->mutex_stat", flags, DB_STAT_CLEAR)) != 0)
56 		return (ret);
57 
58 	ENV_ENTER(env, ip);
59 	REPLICATION_WRAP(env, (__mutex_stat(env, statp, flags)), 0, ret);
60 	ENV_LEAVE(env, ip);
61 	return (ret);
62 }
63 
64 /*
65  * __mutex_stat --
66  *	ENV->mutex_stat.
67  */
68 static int
__mutex_stat(env,statp,flags)69 __mutex_stat(env, statp, flags)
70 	ENV *env;
71 	DB_MUTEX_STAT **statp;
72 	u_int32_t flags;
73 {
74 	DB_MUTEXMGR *mtxmgr;
75 	DB_MUTEXREGION *mtxregion;
76 	DB_MUTEX_STAT *stats;
77 	int ret;
78 
79 	*statp = NULL;
80 	mtxmgr = env->mutex_handle;
81 	mtxregion = mtxmgr->reginfo.primary;
82 
83 	if ((ret = __os_umalloc(env, sizeof(DB_MUTEX_STAT), &stats)) != 0)
84 		return (ret);
85 
86 	MUTEX_SYSTEM_LOCK(env);
87 
88 	/*
89 	 * Most fields are maintained in the underlying region structure.
90 	 * Region size and region mutex are not.
91 	 */
92 	*stats = mtxregion->stat;
93 	stats->st_regsize = mtxmgr->reginfo.rp->size;
94 	stats->st_regmax = mtxmgr->reginfo.rp->max;
95 	__mutex_set_wait_info(env, mtxregion->mtx_region,
96 	    &stats->st_region_wait, &stats->st_region_nowait);
97 	if (LF_ISSET(DB_STAT_CLEAR))
98 		__mutex_clear(env, mtxregion->mtx_region);
99 
100 	MUTEX_SYSTEM_UNLOCK(env);
101 
102 	*statp = stats;
103 	return (0);
104 }
105 
106 /*
107  * __mutex_stat_print_pp --
108  *	ENV->mutex_stat_print pre/post processing.
109  *
110  * PUBLIC: int __mutex_stat_print_pp __P((DB_ENV *, u_int32_t));
111  */
112 int
__mutex_stat_print_pp(dbenv,flags)113 __mutex_stat_print_pp(dbenv, flags)
114 	DB_ENV *dbenv;
115 	u_int32_t flags;
116 {
117 	DB_THREAD_INFO *ip;
118 	ENV *env;
119 	int ret;
120 
121 	env = dbenv->env;
122 
123 	ENV_REQUIRES_CONFIG(env,
124 	    env->mutex_handle, "DB_ENV->mutex_stat_print", DB_INIT_MUTEX);
125 
126 	if ((ret = __db_fchk(env, "DB_ENV->mutex_stat_print",
127 	    flags, DB_STAT_ALL | DB_STAT_ALLOC | DB_STAT_CLEAR)) != 0)
128 		return (ret);
129 
130 	ENV_ENTER(env, ip);
131 	REPLICATION_WRAP(env, (__mutex_stat_print(env, flags)), 0, ret);
132 	ENV_LEAVE(env, ip);
133 	return (ret);
134 }
135 
136 /*
137  * __mutex_stat_print
138  *	ENV->mutex_stat_print method.
139  *
140  * PUBLIC: int __mutex_stat_print __P((ENV *, u_int32_t));
141  */
142 int
__mutex_stat_print(env,flags)143 __mutex_stat_print(env, flags)
144 	ENV *env;
145 	u_int32_t flags;
146 {
147 	u_int32_t orig_flags;
148 	int ret;
149 
150 	orig_flags = flags;
151 	LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM);
152 	if (flags == 0 || LF_ISSET(DB_STAT_ALL)) {
153 		ret = __mutex_print_stats(env, orig_flags);
154 		__mutex_print_summary(env);
155 		if (flags == 0 || ret != 0)
156 			return (ret);
157 	}
158 
159 	if (LF_ISSET(DB_STAT_ALL))
160 		ret = __mutex_print_all(env, orig_flags);
161 
162 	return (0);
163 }
164 
165 static void
__mutex_print_summary(env)166 __mutex_print_summary(env)
167 	ENV *env;
168 {
169 	DB_MUTEX *mutexp;
170 	DB_MUTEXMGR *mtxmgr;
171 	DB_MUTEXREGION *mtxregion;
172 	void *chunk;
173 	db_mutex_t i;
174 	u_int32_t counts[MTX_MAX_ENTRY + 2];
175 	uintmax_t size;
176 	int alloc_id;
177 
178 	mtxmgr = env->mutex_handle;
179 	mtxregion = mtxmgr->reginfo.primary;
180 	memset(counts, 0, sizeof(counts));
181 	size = 0;
182 
183 	if (F_ISSET(env, ENV_PRIVATE)) {
184 		mutexp = (DB_MUTEX *)((uintptr_t)mtxmgr->mutex_array +
185 		    mtxregion->mutex_size);
186 		chunk = NULL;
187 		size = __env_elem_size(env,
188 		    ROFF_TO_P(mtxregion->mutex_off_alloc));
189 		size -= mtxregion->mutex_size;
190 	} else
191 		mutexp = MUTEXP_SET(env, 1);
192 	for (i = 1; i <= mtxregion->stat.st_mutex_cnt; ++i) {
193 		if (!F_ISSET(mutexp, DB_MUTEX_ALLOCATED))
194 			counts[0]++;
195 		else if (mutexp->alloc_id > MTX_MAX_ENTRY)
196 			counts[MTX_MAX_ENTRY + 1]++;
197 		else
198 			counts[mutexp->alloc_id]++;
199 
200 		mutexp = (DB_MUTEX *)((uintptr_t)mutexp +
201 		    mtxregion->mutex_size);
202 		if (F_ISSET(env, ENV_PRIVATE) &&
203 		    (size -= sizeof(*mutexp)) < sizeof(*mutexp)) {
204 			mutexp =
205 			    __env_get_chunk(&mtxmgr->reginfo, &chunk, &size);
206 			mutexp = ALIGNP_INC(mutexp,
207 			    mtxregion->stat.st_mutex_align);
208 		}
209 	}
210 	__db_msg(env, "Mutex counts");
211 	__db_msg(env, "%d\tUnallocated", counts[0]);
212 	for (alloc_id = 1; alloc_id <= MTX_TXN_REGION + 1; alloc_id++)
213 		if (counts[alloc_id] != 0)
214 			__db_msg(env, "%lu\t%s",
215 			    (u_long)counts[alloc_id],
216 			    __mutex_print_id(alloc_id));
217 
218 }
219 
220 /*
221  * __mutex_print_stats --
222  *	Display default mutex region statistics.
223  */
224 static int
__mutex_print_stats(env,flags)225 __mutex_print_stats(env, flags)
226 	ENV *env;
227 	u_int32_t flags;
228 {
229 	DB_MUTEX_STAT *sp;
230 	int ret;
231 
232 	if ((ret = __mutex_stat(env, &sp, LF_ISSET(DB_STAT_CLEAR))) != 0)
233 		return (ret);
234 
235 	if (LF_ISSET(DB_STAT_ALL))
236 		__db_msg(env, "Default mutex region information:");
237 
238 	__db_dlbytes(env, "Mutex region size",
239 	    (u_long)0, (u_long)0, (u_long)sp->st_regsize);
240 	__db_dlbytes(env, "Mutex region max size",
241 	    (u_long)0, (u_long)0, (u_long)sp->st_regmax);
242 	__db_dl_pct(env,
243 	    "The number of region locks that required waiting",
244 	    (u_long)sp->st_region_wait, DB_PCT(sp->st_region_wait,
245 	    sp->st_region_wait + sp->st_region_nowait), NULL);
246 	STAT_ULONG("Mutex alignment", sp->st_mutex_align);
247 	STAT_ULONG("Mutex test-and-set spins", sp->st_mutex_tas_spins);
248 	STAT_ULONG("Mutex initial count", sp->st_mutex_init);
249 	STAT_ULONG("Mutex total count", sp->st_mutex_cnt);
250 	STAT_ULONG("Mutex max count", sp->st_mutex_max);
251 	STAT_ULONG("Mutex free count", sp->st_mutex_free);
252 	STAT_ULONG("Mutex in-use count", sp->st_mutex_inuse);
253 	STAT_ULONG("Mutex maximum in-use count", sp->st_mutex_inuse_max);
254 
255 	__os_ufree(env, sp);
256 
257 	return (0);
258 }
259 
260 /*
261  * __mutex_print_all --
262  *	Display debugging mutex region statistics.
263  */
264 static int
__mutex_print_all(env,flags)265 __mutex_print_all(env, flags)
266 	ENV *env;
267 	u_int32_t flags;
268 {
269 	DB_MSGBUF mb, *mbp;
270 	DB_MUTEX *mutexp;
271 	DB_MUTEXMGR *mtxmgr;
272 	DB_MUTEXREGION *mtxregion;
273 	db_mutex_t i;
274 	uintmax_t size;
275 	void *chunk;
276 
277 	DB_MSGBUF_INIT(&mb);
278 	mbp = &mb;
279 
280 	mtxmgr = env->mutex_handle;
281 	mtxregion = mtxmgr->reginfo.primary;
282 
283 	__db_print_reginfo(env, &mtxmgr->reginfo, "Mutex", flags);
284 	__db_msg(env, "%s", DB_GLOBAL(db_line));
285 
286 	__db_msg(env, "DB_MUTEXREGION structure:");
287 	__mutex_print_debug_single(env,
288 	    "DB_MUTEXREGION region mutex", mtxregion->mtx_region, flags);
289 	STAT_ULONG("Size of the aligned mutex", mtxregion->mutex_size);
290 	STAT_ULONG("Next free mutex", mtxregion->mutex_next);
291 
292 	/*
293 	 * The OOB mutex (MUTEX_INVALID) is 0, skip it.
294 	 *
295 	 * We're not holding the mutex region lock, so we're racing threads of
296 	 * control allocating mutexes.  That's OK, it just means we display or
297 	 * clear statistics while mutexes are moving.
298 	 */
299 	__db_msg(env, "%s", DB_GLOBAL(db_line));
300 	__db_msg(env, "mutex\twait/nowait, pct wait, holder, flags");
301 	size = 0;
302 	if (F_ISSET(env, ENV_PRIVATE)) {
303 		mutexp = (DB_MUTEX *)((uintptr_t)mtxmgr->mutex_array +
304 		    mtxregion->mutex_size);
305 		chunk = NULL;
306 		size = __env_elem_size(env,
307 		    ROFF_TO_P(mtxregion->mutex_off_alloc));
308 		size -= mtxregion->mutex_size;
309 	} else
310 		mutexp = MUTEXP_SET(env, 1);
311 	for (i = 1; i <= mtxregion->stat.st_mutex_cnt; ++i) {
312 		if (F_ISSET(mutexp, DB_MUTEX_ALLOCATED)) {
313 			__db_msgadd(env, mbp, "%5lu\t", (u_long)i);
314 			__mutex_print_debug_stats(env, mbp,
315 			    F_ISSET(env, ENV_PRIVATE) ?
316 			    (db_mutex_t)mutexp : i, flags);
317 			DB_MSGBUF_FLUSH(env, mbp);
318 		}
319 
320 		mutexp = (DB_MUTEX *)((uintptr_t)mutexp +
321 		    mtxregion->mutex_size);
322 		if (F_ISSET(env, ENV_PRIVATE) &&
323 		    (size -= mtxregion->mutex_size) < mtxregion->mutex_size) {
324 			mutexp =
325 			    __env_get_chunk(&mtxmgr->reginfo, &chunk, &size);
326 			mutexp = ALIGNP_INC(mutexp,
327 			    mtxregion->stat.st_mutex_align);
328 		}
329 	}
330 
331 	return (0);
332 }
333 
334 /*
335  * __mutex_print_debug_single --
336  *	Print mutex internal debugging statistics for a single mutex.
337  *
338  * PUBLIC: void __mutex_print_debug_single
339  * PUBLIC:          __P((ENV *, const char *, db_mutex_t, u_int32_t));
340  */
341 void
__mutex_print_debug_single(env,tag,mutex,flags)342 __mutex_print_debug_single(env, tag, mutex, flags)
343 	ENV *env;
344 	const char *tag;
345 	db_mutex_t mutex;
346 	u_int32_t flags;
347 {
348 	DB_MSGBUF mb, *mbp;
349 
350 	DB_MSGBUF_INIT(&mb);
351 	mbp = &mb;
352 
353 	if (LF_ISSET(DB_STAT_SUBSYSTEM))
354 		LF_CLR(DB_STAT_CLEAR);
355 	__db_msgadd(env, mbp, "%lu\t%s ", (u_long)mutex, tag);
356 	__mutex_print_debug_stats(env, mbp, mutex, flags);
357 	DB_MSGBUF_FLUSH(env, mbp);
358 }
359 
360 /*
361  * __mutex_print_debug_stats --
362  *	Print the mutex internal debugging statistics in square bracket,s on a
363  *	followed by the allocation id and flags, on single line. When MUTEX_DIAG
364  *	is on and the mutex is held, append the owner's stack trace.
365  *
366  * PUBLIC: void __mutex_print_debug_stats
367  * PUBLIC:          __P((ENV *, DB_MSGBUF *, db_mutex_t, u_int32_t));
368  */
369 void
__mutex_print_debug_stats(env,mbp,mutex,flags)370 __mutex_print_debug_stats(env, mbp, mutex, flags)
371 	ENV *env;
372 	DB_MSGBUF *mbp;
373 	db_mutex_t mutex;
374 	u_int32_t flags;
375 {
376 	DB_ENV *dbenv;
377 	DB_MUTEX *mutexp;
378 	u_long value;
379 	char buf[DB_THREADID_STRLEN];
380 #if defined(HAVE_SHARED_LATCHES) && (defined(HAVE_MUTEX_HYBRID) || \
381     !defined(HAVE_MUTEX_PTHREADS))
382 	int sharecount;
383 #endif
384 #ifdef MUTEX_DIAG
385 	char timestr[CTIME_BUFLEN];
386 #endif
387 
388 	if (mutex == MUTEX_INVALID) {
389 		__db_msgadd(env, mbp, "[!Set]");
390 		return;
391 	}
392 
393 	dbenv = env->dbenv;
394 	mutexp = MUTEXP_SET(env, mutex);
395 
396 	__db_msgadd(env, mbp, "[");
397 	if ((value = mutexp->mutex_set_wait) < 10000000)
398 		__db_msgadd(env, mbp, "%lu", value);
399 	else
400 		__db_msgadd(env, mbp, "%luM", value / 1000000);
401 	if ((value = mutexp->mutex_set_nowait) < 10000000)
402 		__db_msgadd(env, mbp, "/%lu", value);
403 	else
404 		__db_msgadd(env, mbp, "/%luM", value / 1000000);
405 
406 	__db_msgadd(env, mbp, " %d%% ",
407 	    DB_PCT(mutexp->mutex_set_wait,
408 	    mutexp->mutex_set_wait + mutexp->mutex_set_nowait));
409 
410 #if defined(HAVE_SHARED_LATCHES)
411 	if (F_ISSET(mutexp, DB_MUTEX_SHARED)) {
412 		__db_msgadd(env, mbp, " rd ");
413 		if ((value = mutexp->mutex_set_rd_wait) < 10000000)
414 			__db_msgadd(env, mbp, "%lu", value);
415 		else
416 			__db_msgadd(env, mbp, "%luM", value / 1000000);
417 		if ((value = mutexp->mutex_set_rd_nowait) < 10000000)
418 			__db_msgadd(env, mbp, "/%lu", value);
419 		else
420 			__db_msgadd(env, mbp, "/%luM", value / 1000000);
421 		__db_msgadd(env, mbp, " %d%% ",
422 		    DB_PCT(mutexp->mutex_set_rd_wait,
423 		    mutexp->mutex_set_rd_wait + mutexp->mutex_set_rd_nowait));
424 	}
425 #endif
426 
427 	if (F_ISSET(mutexp, DB_MUTEX_LOCKED))
428 		__db_msgadd(env, mbp, "%s]",
429 		    dbenv->thread_id_string(dbenv,
430 		    mutexp->pid, mutexp->tid, buf));
431 	/* Pthreads-based shared latches do not expose the share count. */
432 #if defined(HAVE_SHARED_LATCHES) && (defined(HAVE_MUTEX_HYBRID) || \
433     !defined(HAVE_MUTEX_PTHREADS))
434 	else if (F_ISSET(mutexp, DB_MUTEX_SHARED) &&
435 	    (sharecount = atomic_read(&mutexp->sharecount)) != 0) {
436 		if (sharecount == 1)
437 			__db_msgadd(env, mbp, "1 reader");
438 		else
439 			__db_msgadd(env, mbp, "%d readers", sharecount);
440 		/* Show the thread which last acquired the latch. */
441 		__db_msgadd(env, mbp, " %s]",
442 		    dbenv->thread_id_string(dbenv,
443 		    mutexp->pid, mutexp->tid, buf));
444 	}
445 #endif
446 	else
447 		__db_msgadd(env, mbp, "!Own]");
448 
449 #ifdef HAVE_MUTEX_HYBRID
450 	if (mutexp->hybrid_wait != 0 || mutexp->hybrid_wakeup != 0)
451 		__db_msgadd(env, mbp, " <wakeups %d/%d>",
452 		    mutexp->hybrid_wait, mutexp->hybrid_wakeup);
453 #endif
454 
455 	if (mutexp->alloc_id != 0)
456 		__db_msgadd(env,
457 		    mbp, ", %s", __mutex_print_id(mutexp->alloc_id));
458 
459 	__db_prflags(env, mbp, mutexp->flags, MutexFlagNames, " (", ")");
460 #ifdef MUTEX_DIAG
461 	if (mutexp->alloc_id != MTX_LOGICAL_LOCK &&
462 	    timespecisset(&mutexp->mutex_history.when)) {
463 		__db_ctimespec(&mutexp->mutex_history.when, timestr);
464 		__db_msgadd(env, mbp, "\nLocked %s", timestr);
465 		if (mutexp->mutex_history.stacktext[0] != '\0')
466 			__db_msgadd(env, mbp, "\n%.*s",
467 			    (int)sizeof(mutexp->mutex_history.stacktext) - 1,
468 			    mutexp->mutex_history.stacktext);
469 	}
470 #endif
471 	if (LF_ISSET(DB_STAT_CLEAR))
472 		__mutex_clear(env, mutex);
473 }
474 
475 static const char *
__mutex_print_id(alloc_id)476 __mutex_print_id(alloc_id)
477 	int alloc_id;
478 {
479 	switch (alloc_id) {
480 	case MTX_APPLICATION:		return ("application allocated");
481 	case MTX_ATOMIC_EMULATION:	return ("atomic emulation");
482 	case MTX_DB_HANDLE:		return ("db handle");
483 	case MTX_ENV_DBLIST:		return ("env dblist");
484 	case MTX_ENV_EXCLDBLIST:	return ("env exclusive dblist");
485 	case MTX_ENV_HANDLE:		return ("env handle");
486 	case MTX_ENV_REGION:		return ("env region");
487 	case MTX_LOCK_REGION:		return ("lock region");
488 	case MTX_LOGICAL_LOCK:		return ("logical lock");
489 	case MTX_LOG_FILENAME:		return ("log filename");
490 	case MTX_LOG_FLUSH:		return ("log flush");
491 	case MTX_LOG_HANDLE:		return ("log handle");
492 	case MTX_LOG_REGION:		return ("log region");
493 	case MTX_LSN_HISTORY:		return ("lsn history");
494 	case MTX_MPOOLFILE_HANDLE:	return ("mpoolfile handle");
495 	case MTX_MPOOL_BH:		return ("mpool buffer");
496 	case MTX_MPOOL_FH:		return ("mpool filehandle");
497 	case MTX_MPOOL_FILE_BUCKET:	return ("mpool file bucket");
498 	case MTX_MPOOL_HANDLE:		return ("mpool handle");
499 	case MTX_MPOOL_HASH_BUCKET:	return ("mpool hash bucket");
500 	case MTX_MPOOL_REGION:		return ("mpool region");
501 	case MTX_MUTEX_REGION:		return ("mutex region");
502 	case MTX_MUTEX_TEST:		return ("mutex test");
503 	case MTX_REPMGR:		return ("replication manager");
504 	case MTX_REP_CHKPT:		return ("replication checkpoint");
505 	case MTX_REP_DATABASE:		return ("replication database");
506 	case MTX_REP_DIAG:		return ("replication diagnostics");
507 	case MTX_REP_EVENT:		return ("replication event");
508 	case MTX_REP_REGION:		return ("replication region");
509 	case MTX_REP_START:		return ("replication role config");
510 	case MTX_REP_WAITER:		return ("replication txn apply");
511 	case MTX_SEQUENCE:		return ("sequence");
512 	case MTX_TWISTER:		return ("twister");
513 	case MTX_TCL_EVENTS:		return ("Tcl events");
514 	case MTX_TXN_ACTIVE:		return ("txn active list");
515 	case MTX_TXN_CHKPT:		return ("transaction checkpoint");
516 	case MTX_TXN_COMMIT:		return ("txn commit");
517 	case MTX_TXN_MVCC:		return ("txn mvcc");
518 	case MTX_TXN_REGION:		return ("txn region");
519 	case 0:				return ("invalid 0 mutex type");
520 	default:			return ("unknown non-zero mutex type");
521 	/* NOTREACHED */
522 	}
523 }
524 
525 /*
526  * __mutex_set_wait_info --
527  *	Return mutex statistics.
528  *
529  * PUBLIC: void __mutex_set_wait_info
530  * PUBLIC:	__P((ENV *, db_mutex_t, uintmax_t *, uintmax_t *));
531  */
532 void
__mutex_set_wait_info(env,mutex,waitp,nowaitp)533 __mutex_set_wait_info(env, mutex, waitp, nowaitp)
534 	ENV *env;
535 	db_mutex_t mutex;
536 	uintmax_t *waitp, *nowaitp;
537 {
538 	DB_MUTEX *mutexp;
539 
540 	if (mutex == MUTEX_INVALID) {
541 		*waitp = 0;
542 		*nowaitp = 0;
543 		return;
544 	}
545 	mutexp = MUTEXP_SET(env, mutex);
546 
547 	*waitp = mutexp->mutex_set_wait;
548 	*nowaitp = mutexp->mutex_set_nowait;
549 }
550 
551 /*
552  * __mutex_clear --
553  *	Clear mutex statistics.
554  *
555  * PUBLIC: void __mutex_clear __P((ENV *, db_mutex_t));
556  */
557 void
__mutex_clear(env,mutex)558 __mutex_clear(env, mutex)
559 	ENV *env;
560 	db_mutex_t mutex;
561 {
562 	DB_MUTEX *mutexp;
563 
564 	if (!MUTEX_ON(env))
565 		return;
566 
567 	mutexp = MUTEXP_SET(env, mutex);
568 
569 	mutexp->mutex_set_wait = mutexp->mutex_set_nowait = 0;
570 #ifdef HAVE_SHARED_LATCHES
571 	mutexp->mutex_set_rd_wait = mutexp->mutex_set_rd_nowait = 0;
572 #endif
573 #ifdef HAVE_MUTEX_HYBRID
574 	mutexp->hybrid_wait = mutexp->hybrid_wakeup = 0;
575 #endif
576 }
577 
578 #else /* !HAVE_STATISTICS */
579 
580 int
__mutex_stat_pp(dbenv,statp,flags)581 __mutex_stat_pp(dbenv, statp, flags)
582 	DB_ENV *dbenv;
583 	DB_MUTEX_STAT **statp;
584 	u_int32_t flags;
585 {
586 	COMPQUIET(statp, NULL);
587 	COMPQUIET(flags, 0);
588 
589 	return (__db_stat_not_built(dbenv->env));
590 }
591 
592 int
__mutex_stat_print_pp(dbenv,flags)593 __mutex_stat_print_pp(dbenv, flags)
594 	DB_ENV *dbenv;
595 	u_int32_t flags;
596 {
597 	COMPQUIET(flags, 0);
598 
599 	return (__db_stat_not_built(dbenv->env));
600 }
601 #endif
602 
603 /*
604  * __mutex_describe
605  *	Fill in a buffer with the mutex #, alloc_id, and any other
606  *	characteristics which are likely to be useful for diagnostics. The
607  *	destination buffer must hold at least DB_MUTEX_DESCRIBE_STRLEN bytes.
608  *
609  * PUBLIC: char *__mutex_describe __P((ENV *, db_mutex_t, char *));
610  */
611 char *
__mutex_describe(env,mutex,dest)612 __mutex_describe(env, mutex, dest)
613 	ENV *env;
614 	db_mutex_t mutex;
615 	char *dest;
616 {
617 	DB_MUTEX *mutexp;
618 	DB_MSGBUF mb, *mbp;
619 	const char *type;
620 
621 	DB_MSGBUF_INIT(&mb);
622 	mbp = &mb;
623 	mutexp = MUTEXP_SET(env, mutex);
624 	type = F_ISSET(mutexp, DB_MUTEX_SHARED) ? "latch" : "mutex";
625 #ifdef HAVE_STATISTICS
626 	__db_msgadd(env, mbp, "%s %s id %ld ",
627 	    __mutex_print_id(mutexp->alloc_id), type, (long)mutex);
628 	__db_prflags(env, mbp, mutexp->flags, MutexFlagNames, " (", ")");
629 #else
630 	__db_msgadd(env, mbp, "%s flags %x id %ld ",
631 	    type, mutexp->flags, (long)mutex);
632 #endif
633 	(void)snprintf(dest, DB_MUTEX_DESCRIBE_STRLEN - 1,
634 	    "%.*s", (int)(mbp->cur - mbp->buf), mbp->buf);
635 	dest[DB_MUTEX_DESCRIBE_STRLEN - 1] = '\0';
636 	return (dest);
637 }
638