mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-31 15:50:51 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			628 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			628 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Standalone mutex tester for Berkeley DB mutexes.
 | |
|  */
 | |
| #include "db_config.h"
 | |
| 
 | |
| #include <sys/types.h>
 | |
| #include <sys/mman.h>
 | |
| #include <sys/stat.h>
 | |
| #include <sys/wait.h>
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <fcntl.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
 | |
| #include <pthread.h>
 | |
| #endif
 | |
| 
 | |
| #include "db_int.h"
 | |
| 
 | |
| void  exec_proc();
 | |
| void  tm_file_init();
 | |
| void  map_file();
 | |
| void  run_proc();
 | |
| void *run_thread();
 | |
| void *run_thread_wake();
 | |
| void  tm_mutex_destroy();
 | |
| void  tm_mutex_init();
 | |
| void  tm_mutex_stats();
 | |
| void  unmap_file();
 | |
| 
 | |
| #define	MUTEX_WAKEME	0x80			/* Wake-me flag. */
 | |
| 
 | |
| DB_ENV	 dbenv;					/* Fake out DB. */
 | |
| size_t	 len;					/* Backing file size. */
 | |
| int	 align;					/* Mutex alignment in file. */
 | |
| int	 quit;					/* End-of-test flag. */
 | |
| char	*file = "mutex.file";			/* Backing file. */
 | |
| 
 | |
| int	 maxlocks = 20;				/* -l: Backing locks. */
 | |
| int	 nlocks = 10000;			/* -n: Locks per processes. */
 | |
| int	 nprocs = 20;				/* -p: Processes. */
 | |
| int	 child;					/* -s: Slave. */
 | |
| int	 nthreads = 1;				/* -t: Threads. */
 | |
| int	 verbose;				/* -v: Verbosity. */
 | |
| 
 | |
| int
 | |
| main(argc, argv)
 | |
| 	int argc;
 | |
| 	char *argv[];
 | |
| {
 | |
| 	extern int optind;
 | |
| 	extern char *optarg;
 | |
| 	pid_t pid;
 | |
| 	int ch, eval, i, status;
 | |
| 	char *tmpath;
 | |
| 
 | |
| 	tmpath = argv[0];
 | |
| 	while ((ch = getopt(argc, argv, "l:n:p:st:v")) != EOF)
 | |
| 		switch(ch) {
 | |
| 		case 'l':
 | |
| 			maxlocks = atoi(optarg);
 | |
| 			break;
 | |
| 		case 'n':
 | |
| 			nlocks = atoi(optarg);
 | |
| 			break;
 | |
| 		case 'p':
 | |
| 			nprocs = atoi(optarg);
 | |
| 			break;
 | |
| 		case 's':
 | |
| 			child = 1;
 | |
| 			break;
 | |
| 		case 't':
 | |
| 			nthreads = atoi(optarg);
 | |
| #if !defined(HAVE_MUTEX_PTHREADS) && !defined(BUILD_PTHREADS_ANYWAY)
 | |
| 			if (nthreads != 1) {
 | |
| 				(void)fprintf(stderr,
 | |
| 	"tm: pthreads not available or not compiled for this platform.\n");
 | |
| 				return (EXIT_FAILURE);
 | |
| 			}
 | |
| #endif
 | |
| 			break;
 | |
| 		case 'v':
 | |
| 			verbose = 1;
 | |
| 			break;
 | |
| 		case '?':
 | |
| 		default:
 | |
| 			(void)fprintf(stderr,
 | |
|     "usage: tm [-v] [-l maxlocks] [-n locks] [-p procs] [-t threads]\n");
 | |
| 			return (EXIT_FAILURE);
 | |
| 		}
 | |
| 	argc -= optind;
 | |
| 	argv += optind;
 | |
| 
 | |
| 	/*
 | |
| 	 * The file layout:
 | |
| 	 *	DB_MUTEX[1]		per-thread mutex array lock
 | |
| 	 *	DB_MUTEX[nthreads]	per-thread mutex array
 | |
| 	 *	DB_MUTEX[maxlocks]	per-lock mutex array
 | |
| 	 *	u_long[maxlocks][2]	per-lock ID array
 | |
| 	 */
 | |
| 	align = ALIGN(sizeof(DB_MUTEX) * 2, MUTEX_ALIGN);
 | |
| 	len =
 | |
| 	    align * (1 + nthreads +  maxlocks) + sizeof(u_long) * maxlocks * 2;
 | |
| 	printf(
 | |
|     "mutex alignment %d, structure alignment %d, backing file %lu bytes\n",
 | |
| 	    MUTEX_ALIGN, align, (u_long)len);
 | |
| 
 | |
| 	if (child) {
 | |
| 		run_proc();
 | |
| 		return (EXIT_SUCCESS);
 | |
| 	}
 | |
| 
 | |
| 	tm_file_init();
 | |
| 	tm_mutex_init();
 | |
| 
 | |
| 	printf(
 | |
| 	    "%d proc, %d threads/proc, %d lock requests from %d locks:\n",
 | |
| 	    nprocs, nthreads, nlocks, maxlocks);
 | |
| 	for (i = 0; i < nprocs; ++i)
 | |
| 		switch (fork()) {
 | |
| 		case -1:
 | |
| 			perror("fork");
 | |
| 			return (EXIT_FAILURE);
 | |
| 		case 0:
 | |
| 			exec_proc(tmpath);
 | |
| 			break;
 | |
| 		default:
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 	eval = EXIT_SUCCESS;
 | |
| 	while ((pid = wait(&status)) != (pid_t)-1) {
 | |
| 		fprintf(stderr,
 | |
| 		    "%lu: exited %d\n", (u_long)pid, WEXITSTATUS(status));
 | |
| 		if (WEXITSTATUS(status) != 0)
 | |
| 			eval = EXIT_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	tm_mutex_stats();
 | |
| 	tm_mutex_destroy();
 | |
| 
 | |
| 	printf("tm: exit status: %s\n",
 | |
| 	    eval == EXIT_SUCCESS ? "success" : "failed!");
 | |
| 	return (eval);
 | |
| }
 | |
| 
 | |
| void
 | |
| exec_proc(tmpath)
 | |
| 	char *tmpath;
 | |
| {
 | |
| 	char *argv[10], **ap, b_l[10], b_n[10], b_t[10];
 | |
| 
 | |
| 	ap = &argv[0];
 | |
| 	*ap++ = "tm";
 | |
| 	sprintf(b_l, "-l%d", maxlocks);
 | |
| 	*ap++ = b_l;
 | |
| 	sprintf(b_n, "-n%d", nlocks);
 | |
| 	*ap++ = b_n;
 | |
| 	*ap++ = "-s";
 | |
| 	sprintf(b_t, "-t%d", nthreads);
 | |
| 	*ap++ = b_t;
 | |
| 	if (verbose)
 | |
| 		*ap++ = "-v";
 | |
| 
 | |
| 	*ap = NULL;
 | |
| 	execvp(tmpath, argv);
 | |
| 
 | |
| 	fprintf(stderr, "%s: %s\n", tmpath, strerror(errno));
 | |
| 	exit(EXIT_FAILURE);
 | |
| }
 | |
| 
 | |
| void
 | |
| run_proc()
 | |
| {
 | |
| #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
 | |
| 	pthread_t *kidsp, wakep;
 | |
| 	int i, status;
 | |
| 	void *retp;
 | |
| #endif
 | |
| 	__os_sleep(&dbenv, 3, 0);		/* Let everyone catch up. */
 | |
| 
 | |
| 	srand((u_int)time(NULL) / getpid());	/* Initialize random numbers. */
 | |
| 
 | |
| 	if (nthreads == 1)			/* Simple case. */
 | |
| 		exit((int)run_thread((void *)0));
 | |
| 
 | |
| #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
 | |
| 	/*
 | |
| 	 * Spawn off threads.  We have nthreads all locking and going to
 | |
| 	 * sleep, and one other thread cycling through and waking them up.
 | |
| 	 */
 | |
| 	if ((kidsp =
 | |
| 	    (pthread_t *)calloc(sizeof(pthread_t), nthreads)) == NULL) {
 | |
| 		fprintf(stderr, "tm: %s\n", strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| 	for (i = 0; i < nthreads; i++)
 | |
| 		if ((errno = pthread_create(
 | |
| 		    &kidsp[i], NULL, run_thread, (void *)i)) != 0) {
 | |
| 			fprintf(stderr, "tm: failed spawning thread %d: %s\n",
 | |
| 			    i, strerror(errno));
 | |
| 			exit(EXIT_FAILURE);
 | |
| 		}
 | |
| 
 | |
| 	if ((errno = pthread_create(
 | |
| 	    &wakep, NULL, run_thread_wake, (void *)0)) != 0) {
 | |
| 		fprintf(stderr, "tm: failed spawning wakeup thread: %s\n",
 | |
| 		    strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| 
 | |
| 	/* Wait for the threads to exit. */
 | |
| 	status = 0;
 | |
| 	for (i = 0; i < nthreads; i++) {
 | |
| 		pthread_join(kidsp[i], &retp);
 | |
| 		if (retp != NULL) {
 | |
| 			fprintf(stderr,
 | |
| 			    "tm: thread %d exited with error\n", i);
 | |
| 			status = EXIT_FAILURE;
 | |
| 		}
 | |
| 	}
 | |
| 	free(kidsp);
 | |
| 
 | |
| 	/* Signal wakeup thread to stop. */
 | |
| 	quit = 1;
 | |
| 	pthread_join(wakep, &retp);
 | |
| 	if (retp != NULL) {
 | |
| 		fprintf(stderr, "tm: wakeup thread exited with error\n");
 | |
| 		status = EXIT_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	exit(status);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void *
 | |
| run_thread(arg)
 | |
| 	void *arg;
 | |
| {
 | |
| 	DB_MUTEX *gm_addr, *lm_addr, *tm_addr, *mp;
 | |
| 	u_long gid1, gid2, *id_addr;
 | |
| 	int fd, i, lock, id, nl, remap;
 | |
| 
 | |
| 	/* Set local and global per-thread ID. */
 | |
| 	id = (int)arg;
 | |
| 	gid1 = (u_long)getpid();
 | |
| #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
 | |
| 	gid2 = (u_long)pthread_self();
 | |
| #else
 | |
| 	gid2 = 0;
 | |
| #endif
 | |
| 	printf("\tPID: %lu; TID: %lx; ID: %d\n", gid1, gid2, id);
 | |
| 
 | |
| 	nl = nlocks;
 | |
| 	for (gm_addr = NULL, remap = 0;;) {
 | |
| 		/* Map in the file as necessary. */
 | |
| 		if (gm_addr == NULL) {
 | |
| 			map_file(&gm_addr, &tm_addr, &lm_addr, &id_addr, &fd);
 | |
| 			remap = (rand() % 100) + 35;
 | |
| 		}
 | |
| 
 | |
| 		/* Select and acquire a data lock. */
 | |
| 		lock = rand() % maxlocks;
 | |
| 		mp = (DB_MUTEX *)((u_int8_t *)lm_addr + lock * align);
 | |
| 		if (verbose)
 | |
| 			printf("%lu/%lx: %03d\n", gid1, gid2, lock);
 | |
| 
 | |
| 		if (__db_mutex_lock(&dbenv, mp)) {
 | |
| 			fprintf(stderr,
 | |
| 			    "%lu/%lx: never got lock\n", gid1, gid2);
 | |
| 			return ((void *)EXIT_FAILURE);
 | |
| 		}
 | |
| 		if (id_addr[lock * 2] != 0) {
 | |
| 			fprintf(stderr,
 | |
| 			    "RACE! (%lu/%lx granted lock %d held by %lu/%lx)\n",
 | |
| 			    gid1, gid2,
 | |
| 			    lock, id_addr[lock * 2], id_addr[lock * 2 + 1]);
 | |
| 			return ((void *)EXIT_FAILURE);
 | |
| 		}
 | |
| 		id_addr[lock * 2] = gid1;
 | |
| 		id_addr[lock * 2 + 1] = gid2;
 | |
| 
 | |
| 		/*
 | |
| 		 * Pretend to do some work, periodically checking to see if
 | |
| 		 * we still hold the mutex.
 | |
| 		 */
 | |
| 		for (i = 0; i < 3; ++i) {
 | |
| 			__os_sleep(&dbenv, 0, rand() % 3);
 | |
| 			if (id_addr[lock * 2] != gid1 ||
 | |
| 			    id_addr[lock * 2 + 1] != gid2) {
 | |
| 				fprintf(stderr,
 | |
| 			    "RACE! (%lu/%lx stole lock %d from %lu/%lx)\n",
 | |
| 				    id_addr[lock * 2],
 | |
| 				    id_addr[lock * 2 + 1], lock, gid1, gid2);
 | |
| 				return ((void *)EXIT_FAILURE);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
 | |
| 		/*
 | |
| 		 * Test self-blocking and unlocking by other threads/processes:
 | |
| 		 *
 | |
| 		 *	acquire the global lock
 | |
| 		 *	set our wakeup flag
 | |
| 		 *	release the global lock
 | |
| 		 *	acquire our per-thread lock
 | |
| 		 *
 | |
| 		 * The wakeup thread will wake us up.
 | |
| 		 */
 | |
| 		if (__db_mutex_lock(&dbenv, gm_addr)) {
 | |
| 			fprintf(stderr, "%lu/%lx: global lock\n", gid1, gid2);
 | |
| 			return ((void *)EXIT_FAILURE);
 | |
| 		}
 | |
| 		mp = (DB_MUTEX *)((u_int8_t *)tm_addr + id * align);
 | |
| 		F_SET(mp, MUTEX_WAKEME);
 | |
| 		if (__db_mutex_unlock(&dbenv, gm_addr)) {
 | |
| 			fprintf(stderr,
 | |
| 			    "%lu/%lx: per-thread wakeup failed\n", gid1, gid2);
 | |
| 			return ((void *)EXIT_FAILURE);
 | |
| 		}
 | |
| 		if (__db_mutex_lock(&dbenv, mp)) {
 | |
| 			fprintf(stderr,
 | |
| 			    "%lu/%lx: per-thread lock\n", gid1, gid2);
 | |
| 			return ((void *)EXIT_FAILURE);
 | |
| 		}
 | |
| 		/* Time passes... */
 | |
| 		if (F_ISSET(mp, MUTEX_WAKEME)) {
 | |
| 			fprintf(stderr, "%lu/%lx: %03d wakeup flag still set\n",
 | |
| 			    gid1, gid2, id);
 | |
| 			return ((void *)EXIT_FAILURE);
 | |
| 		}
 | |
| #endif
 | |
| 
 | |
| 		/* Release the data lock. */
 | |
| 		id_addr[lock * 2] = id_addr[lock * 2 + 1] = 0;
 | |
| 		mp = (DB_MUTEX *)((u_int8_t *)lm_addr + lock * align);
 | |
| 		if (__db_mutex_unlock(&dbenv, mp)) {
 | |
| 			fprintf(stderr, "%lu/%lx: wakeup failed\n", gid1, gid2);
 | |
| 			return ((void *)EXIT_FAILURE);
 | |
| 		}
 | |
| 
 | |
| 		if (--nl % 100 == 0)
 | |
| 			fprintf(stderr, "%lu/%lx: %d\n", gid1, gid2, nl);
 | |
| 
 | |
| 		if (nl == 0 || --remap == 0) {
 | |
| 			unmap_file((void *)gm_addr, fd);
 | |
| 			gm_addr = NULL;
 | |
| 
 | |
| 			if (nl == 0)
 | |
| 				break;
 | |
| 
 | |
| 			__os_sleep(&dbenv, rand() % 3, 0);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return (NULL);
 | |
| }
 | |
| 
 | |
| #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
 | |
| /*
 | |
|  * run_thread_wake --
 | |
|  *	Thread to wake up other threads that are sleeping.
 | |
|  */
 | |
| void *
 | |
| run_thread_wake(arg)
 | |
| 	void *arg;
 | |
| {
 | |
| 	DB_MUTEX *gm_addr, *tm_addr, *mp;
 | |
| 	int fd, id;
 | |
| 
 | |
| 	arg = NULL;
 | |
| 	map_file(&gm_addr, &tm_addr, NULL, NULL, &fd);
 | |
| 
 | |
| 	/* Loop, waking up sleepers and periodically sleeping ourselves. */
 | |
| 	while (!quit) {
 | |
| 		id = 0;
 | |
| 
 | |
| 		/* Acquire the global lock. */
 | |
| retry:		if (__db_mutex_lock(&dbenv, gm_addr)) {
 | |
| 			fprintf(stderr, "wt: global lock failed\n");
 | |
| 			return ((void *)EXIT_FAILURE);
 | |
| 		}
 | |
| 
 | |
| next:		mp = (DB_MUTEX *)((u_int8_t *)tm_addr + id * align);
 | |
| 		if (F_ISSET(mp, MUTEX_WAKEME)) {
 | |
| 			F_CLR(mp, MUTEX_WAKEME);
 | |
| 			if (__db_mutex_unlock(&dbenv, mp)) {
 | |
| 				fprintf(stderr, "wt: wakeup failed\n");
 | |
| 				return ((void *)EXIT_FAILURE);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (++id < nthreads && id % 3 != 0)
 | |
| 			goto next;
 | |
| 
 | |
| 		if (__db_mutex_unlock(&dbenv, gm_addr)) {
 | |
| 			fprintf(stderr, "wt: global unlock failed\n");
 | |
| 			return ((void *)EXIT_FAILURE);
 | |
| 		}
 | |
| 
 | |
| 		__os_sleep(&dbenv, 0, 500);
 | |
| 
 | |
| 		if (id < nthreads)
 | |
| 			goto retry;
 | |
| 	}
 | |
| 	return (NULL);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /*
 | |
|  * tm_file_init --
 | |
|  *	Initialize the backing file.
 | |
|  */
 | |
| void
 | |
| tm_file_init()
 | |
| {
 | |
| 	int fd;
 | |
| 
 | |
| 
 | |
| 	/* Initialize the backing file. */
 | |
| 	printf("Create the backing file...\n");
 | |
| #ifdef	HAVE_QNX
 | |
| 	(void)shm_unlink(file);
 | |
| 	if ((fd = shm_open(file, O_CREAT | O_RDWR | O_TRUNC,
 | |
| #else
 | |
| 	(void)remove(file);
 | |
| 	if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC,
 | |
| #endif
 | |
| 
 | |
| 	    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1) {
 | |
| 		(void)fprintf(stderr, "%s: open: %s\n", file, strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| 	if (lseek(fd, (off_t)len, SEEK_SET) != len || write(fd, &fd, 1) != 1) {
 | |
| 		(void)fprintf(stderr,
 | |
| 		    "%s: seek/write: %s\n", file, strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| 	(void)close(fd);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * tm_mutex_init --
 | |
|  *	Initialize the mutexes.
 | |
|  */
 | |
| void
 | |
| tm_mutex_init()
 | |
| {
 | |
| 	DB_MUTEX *gm_addr, *lm_addr, *mp, *tm_addr;
 | |
| 	int fd, i;
 | |
| 
 | |
| 	map_file(&gm_addr, &tm_addr, &lm_addr, NULL, &fd);
 | |
| 
 | |
| 	printf("Initialize the global mutex...\n");
 | |
| 	if (__db_mutex_init_int(&dbenv, gm_addr, 0, 0)) {
 | |
| 		fprintf(stderr,
 | |
| 		    "__db_mutex_init (global): %s\n", strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| 
 | |
| 	printf("Initialize the per-thread mutexes...\n");
 | |
| 	for (i = 1, mp = tm_addr;
 | |
| 	    i <= nthreads; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align)) {
 | |
| 		if (__db_mutex_init_int(&dbenv, mp, 0, MUTEX_SELF_BLOCK)) {
 | |
| 			fprintf(stderr, "__db_mutex_init (per-thread %d): %s\n",
 | |
| 			    i, strerror(errno));
 | |
| 			exit(EXIT_FAILURE);
 | |
| 		}
 | |
| 		if (__db_mutex_lock(&dbenv, mp)) {
 | |
| 			fprintf(stderr,
 | |
| 			    "__db_mutex_init (per-thread %d) lock: %s\n",
 | |
| 			    i, strerror(errno));
 | |
| 			exit(EXIT_FAILURE);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	printf("Initialize the per-lock mutexes...\n");
 | |
| 	for (i = 1, mp = lm_addr;
 | |
| 	    i <= maxlocks; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align))
 | |
| 		if (__db_mutex_init_int(&dbenv, mp, 0, 0)) {
 | |
| 			fprintf(stderr, "__db_mutex_init (per-lock: %d): %s\n",
 | |
| 			    i, strerror(errno));
 | |
| 			exit(EXIT_FAILURE);
 | |
| 		}
 | |
| 
 | |
| 	unmap_file((void *)gm_addr, fd);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * tm_mutex_destroy --
 | |
|  *	Destroy the mutexes.
 | |
|  */
 | |
| void
 | |
| tm_mutex_destroy()
 | |
| {
 | |
| 	DB_MUTEX *gm_addr, *lm_addr, *mp, *tm_addr;
 | |
| 	int fd, i;
 | |
| 
 | |
| 	map_file(&gm_addr, &tm_addr, &lm_addr, NULL, &fd);
 | |
| 
 | |
| 	printf("Destroy the global mutex...\n");
 | |
| 	if (__db_mutex_destroy(gm_addr)) {
 | |
| 		fprintf(stderr,
 | |
| 		    "__db_mutex_destroy (global): %s\n", strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| 
 | |
| 	printf("Destroy the per-thread mutexes...\n");
 | |
| 	for (i = 1, mp = tm_addr;
 | |
| 	    i <= nthreads; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align)) {
 | |
| 		if (__db_mutex_destroy(mp)) {
 | |
| 			fprintf(stderr,
 | |
| 			    "__db_mutex_destroy (per-thread %d): %s\n",
 | |
| 			    i, strerror(errno));
 | |
| 			exit(EXIT_FAILURE);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	printf("Destroy the per-lock mutexes...\n");
 | |
| 	for (i = 1, mp = lm_addr;
 | |
| 	    i <= maxlocks; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align))
 | |
| 		if (__db_mutex_destroy(mp)) {
 | |
| 			fprintf(stderr,
 | |
| 			    "__db_mutex_destroy (per-lock: %d): %s\n",
 | |
| 			    i, strerror(errno));
 | |
| 			exit(EXIT_FAILURE);
 | |
| 		}
 | |
| 
 | |
| 	unmap_file((void *)gm_addr, fd);
 | |
| #ifdef HAVE_QNX
 | |
| 	(void)shm_unlink(file);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * tm_mutex_stats --
 | |
|  *	Display mutex statistics.
 | |
|  */
 | |
| void
 | |
| tm_mutex_stats()
 | |
| {
 | |
| 	DB_MUTEX *gm_addr, *lm_addr, *mp;
 | |
| 	int fd, i;
 | |
| 
 | |
| 	map_file(&gm_addr, NULL, &lm_addr, NULL, &fd);
 | |
| 
 | |
| 	printf("Per-lock mutex statistics...\n");
 | |
| 	for (i = 1, mp = lm_addr;
 | |
| 	    i <= maxlocks; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align))
 | |
| 		printf("mutex %2d: wait: %lu; no wait %lu\n", i,
 | |
| 		    (u_long)mp->mutex_set_wait, (u_long)mp->mutex_set_nowait);
 | |
| 
 | |
| 	unmap_file((void *)gm_addr, fd);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * map_file --
 | |
|  *	Map in the backing file.
 | |
|  */
 | |
| void
 | |
| map_file(gm_addrp, tm_addrp, lm_addrp, id_addrp, fdp)
 | |
| 	DB_MUTEX **gm_addrp, **tm_addrp, **lm_addrp;
 | |
| 	u_long **id_addrp;
 | |
| 	int *fdp;
 | |
| {
 | |
| 	void *maddr;
 | |
| 	int fd;
 | |
| 
 | |
| #ifndef MAP_FAILED
 | |
| #define	MAP_FAILED	(void *)-1
 | |
| #endif
 | |
| #ifndef MAP_FILE
 | |
| #define	MAP_FILE	0
 | |
| #endif
 | |
| #ifdef	HAVE_QNX
 | |
| 	if ((fd = shm_open(file, O_RDWR, 0)) == -1) {
 | |
| #else
 | |
| 	if ((fd = open(file, O_RDWR, 0)) == -1) {
 | |
| #endif
 | |
| 		fprintf(stderr, "%s: open %s\n", file, strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| 
 | |
| 	maddr = mmap(NULL, len,
 | |
| 	    PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, (off_t)0);
 | |
| 	if (maddr == MAP_FAILED) {
 | |
| 		fprintf(stderr, "%s: mmap: %s\n", file, strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| 
 | |
| 	if (gm_addrp != NULL)
 | |
| 		*gm_addrp = (DB_MUTEX *)maddr;
 | |
| 	maddr = (u_int8_t *)maddr + align;
 | |
| 	if (tm_addrp != NULL)
 | |
| 		*tm_addrp = (DB_MUTEX *)maddr;
 | |
| 	maddr = (u_int8_t *)maddr + align * nthreads;
 | |
| 	if (lm_addrp != NULL)
 | |
| 		*lm_addrp = (DB_MUTEX *)maddr;
 | |
| 	maddr = (u_int8_t *)maddr + align * maxlocks;
 | |
| 	if (id_addrp != NULL)
 | |
| 		*id_addrp = (u_long *)maddr;
 | |
| 	if (fdp != NULL)
 | |
| 		*fdp = fd;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * unmap_file --
 | |
|  *	Discard backing file map.
 | |
|  */
 | |
| void
 | |
| unmap_file(maddr, fd)
 | |
| 	void *maddr;
 | |
| 	int fd;
 | |
| {
 | |
| 	if (munmap(maddr, len) != 0) {
 | |
| 		fprintf(stderr, "munmap: %s\n", strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| 	if (close(fd) != 0) {
 | |
| 		fprintf(stderr, "close: %s\n", strerror(errno));
 | |
| 		exit(EXIT_FAILURE);
 | |
| 	}
 | |
| }
 | 
