summaryrefslogtreecommitdiff
path: root/storage/bdb/mutex/tm.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/bdb/mutex/tm.c')
-rw-r--r--storage/bdb/mutex/tm.c1020
1 files changed, 0 insertions, 1020 deletions
diff --git a/storage/bdb/mutex/tm.c b/storage/bdb/mutex/tm.c
deleted file mode 100644
index ce685c8b7b7..00000000000
--- a/storage/bdb/mutex/tm.c
+++ /dev/null
@@ -1,1020 +0,0 @@
-/*
- * Standalone mutex tester for Berkeley DB mutexes.
- *
- * $Id: tm.c,v 12.10 2005/10/21 17:53:04 bostic Exp $
- */
-#include "db_config.h"
-
-#ifndef NO_SYSTEM_INCLUDES
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#if defined(MUTEX_THREAD_TEST)
-#include <pthread.h>
-#endif
-#endif
-
-#include "db_int.h"
-
-#ifdef DB_WIN32
-extern int getopt(int, char * const *, const char *);
-
-typedef HANDLE os_pid_t;
-typedef HANDLE os_thread_t;
-
-#define os_thread_create(thrp, attr, func, arg) \
- (((*(thrp) = CreateThread(NULL, 0, \
- (LPTHREAD_START_ROUTINE)(func), (arg), 0, NULL)) == NULL) ? -1 : 0)
-#define os_thread_join(thr, statusp) \
- ((WaitForSingleObject((thr), INFINITE) == WAIT_OBJECT_0) && \
- GetExitCodeThread((thr), (LPDWORD)(statusp)) ? 0 : -1)
-#define os_thread_self() GetCurrentThreadId()
-
-#else /* !DB_WIN32 */
-
-typedef pid_t os_pid_t;
-
-#ifdef MUTEX_THREAD_TEST
-typedef pthread_t os_thread_t;
-#endif
-
-#define os_thread_create(thrp, attr, func, arg) \
- pthread_create((thrp), (attr), (func), (arg))
-#define os_thread_join(thr, statusp) pthread_join((thr), (statusp))
-#define os_thread_self() pthread_self()
-#endif
-
-#define OS_BAD_PID (os_pid_t)-1
-
-#define TESTDIR "TESTDIR" /* Working area */
-#define MT_FILE "TESTDIR/mutex.file"
-#define MT_FILE_QUIT "TESTDIR/mutex.file.quit"
-
-/*
- * The backing file layout:
- * TM[1] per-thread mutex array lock
- * TM[nthreads] per-thread mutex array
- * TM[maxlocks] per-lock mutex array
- */
-typedef struct {
- db_mutex_t mutex; /* Mutex. */
- u_long id; /* Holder's ID. */
- u_int wakeme; /* Request to awake. */
-} TM;
-
-DB_ENV *dbenv; /* Backing environment */
-size_t len; /* Backing file size. */
-
-u_int8_t *gm_addr; /* Global mutex */
-u_int8_t *lm_addr; /* Locker mutexes */
-u_int8_t *tm_addr; /* Thread mutexes */
-
-#ifdef MUTEX_THREAD_TEST
-os_thread_t *kidsp; /* Locker threads */
-os_thread_t wakep; /* Wakeup thread */
-#endif
-
-int maxlocks = 20; /* -l: Backing locks. */
-int nlocks = 10000; /* -n: Locks per processes. */
-int nprocs = 20; /* -p: Processes. */
-int nthreads = 1; /* -t: Threads. */
-int verbose; /* -v: Verbosity. */
-
-int locker_start(u_long);
-int locker_wait(void);
-void map_file(u_int8_t **, u_int8_t **, u_int8_t **, DB_FH **);
-os_pid_t os_spawn(const char *, char *const[]);
-int os_wait(os_pid_t *, int);
-void *run_lthread(void *);
-void *run_wthread(void *);
-os_pid_t spawn_proc(u_long, char *, char *);
-void tm_env_close(void);
-int tm_env_init(void);
-void tm_file_init(void);
-void tm_mutex_destroy(void);
-void tm_mutex_init(void);
-void tm_mutex_stats(void);
-void unmap_file(u_int8_t *, DB_FH *);
-int usage(void);
-int wakeup_start(u_long);
-int wakeup_wait(void);
-
-int
-main(argc, argv)
- int argc;
- char *argv[];
-{
- enum {LOCKER, WAKEUP, PARENT} rtype;
- extern int optind;
- extern char *optarg;
- os_pid_t wakeup_pid, *pids;
- u_long id;
- DB_FH *fhp, *map_fhp;
- int ch, err, i;
- char *p, *tmpath, cmd[1024];
-
- rtype = PARENT;
- id = 0;
- tmpath = argv[0];
- while ((ch = getopt(argc, argv, "l:n:p:T:t:v")) != EOF)
- switch (ch) {
- case 'l':
- maxlocks = atoi(optarg);
- break;
- case 'n':
- nlocks = atoi(optarg);
- break;
- case 'p':
- nprocs = atoi(optarg);
- break;
- case 't':
- if ((nthreads = atoi(optarg)) == 0)
- nthreads = 1;
-#if !defined(MUTEX_THREAD_TEST)
- if (nthreads != 1) {
- (void)fprintf(stderr,
- "tm: thread support not available or not compiled for this platform.\n");
- return (EXIT_FAILURE);
- }
-#endif
- break;
- case 'T':
- if (!memcmp(optarg, "locker", sizeof("locker") - 1))
- rtype = LOCKER;
- else if (
- !memcmp(optarg, "wakeup", sizeof("wakeup") - 1))
- rtype = WAKEUP;
- else
- return (usage());
- if ((p = strchr(optarg, '=')) == NULL)
- return (usage());
- id = atoi(p + 1);
- break;
- case 'v':
- verbose = 1;
- break;
- case '?':
- default:
- return (usage());
- }
- argc -= optind;
- argv += optind;
-
- /*
- * If we're not running a multi-process test, we should be running
- * a multi-thread test.
- */
- if (nprocs == 1 && nthreads == 1) {
- fprintf(stderr,
- "tm: running in a single process requires multiple threads\n");
- return (EXIT_FAILURE);
- }
-
- len = sizeof(TM) * (1 + nthreads * nprocs + maxlocks);
-
- /*
- * In the multi-process test, the parent spawns processes that exec
- * the original binary, ending up here. Each process joins the DB
- * environment separately and then calls the supporting function.
- */
- if (rtype == LOCKER || rtype == WAKEUP) {
- __os_sleep(dbenv, 3, 0); /* Let everyone catch up. */
- /* Initialize random numbers. */
- srand((u_int)time(NULL) % getpid());
-
- if (tm_env_init() != 0) /* Join the environment. */
- exit(EXIT_FAILURE);
- /* Join the backing file. */
- map_file(&gm_addr, &tm_addr, &lm_addr, &map_fhp);
- if (verbose)
- printf(
- "Backing file: global (%#lx), threads (%#lx), locks (%#lx)\n",
- (u_long)gm_addr, (u_long)tm_addr, (u_long)lm_addr);
-
- if ((rtype == LOCKER ?
- locker_start(id) : wakeup_start(id)) != 0)
- exit(EXIT_FAILURE);
- if ((rtype == LOCKER ? locker_wait() : wakeup_wait()) != 0)
- exit(EXIT_FAILURE);
-
- unmap_file(gm_addr, map_fhp); /* Detach from backing file. */
-
- tm_env_close(); /* Detach from environment. */
-
- exit(EXIT_SUCCESS);
- }
-
- /*
- * The following code is only executed by the original parent process.
- *
- * Clean up from any previous runs.
- */
- snprintf(cmd, sizeof(cmd), "rm -rf %s", TESTDIR);
- (void)system(cmd);
- snprintf(cmd, sizeof(cmd), "mkdir %s", TESTDIR);
- (void)system(cmd);
-
- printf(
- "tm: %d processes, %d threads/process, %d lock requests from %d locks\n",
- nprocs, nthreads, nlocks, maxlocks);
- printf("tm: backing file %lu bytes\n", (u_long)len);
-
- if (tm_env_init() != 0) /* Create the environment. */
- exit(EXIT_FAILURE);
-
- tm_file_init(); /* Initialize backing file. */
-
- /* Map in the backing file. */
- map_file(&gm_addr, &tm_addr, &lm_addr, &map_fhp);
- if (verbose)
- printf(
- "backing file: global (%#lx), threads (%#lx), locks (%#lx)\n",
- (u_long)gm_addr, (u_long)tm_addr, (u_long)lm_addr);
-
- tm_mutex_init(); /* Initialize mutexes. */
-
- if (nprocs > 1) { /* Run the multi-process test. */
- /* Allocate array of locker process IDs. */
- if ((pids = calloc(nprocs, sizeof(os_pid_t))) == NULL) {
- fprintf(stderr, "tm: %s\n", strerror(errno));
- goto fail;
- }
-
- /* Spawn locker processes and threads. */
- for (i = 0; i < nprocs; ++i) {
- if ((pids[i] =
- spawn_proc(id, tmpath, "locker")) == OS_BAD_PID) {
- fprintf(stderr,
- "tm: failed to spawn a locker\n");
- goto fail;
- }
- id += nthreads;
- }
-
- /* Spawn wakeup process/thread. */
- if ((wakeup_pid =
- spawn_proc(id, tmpath, "wakeup")) == OS_BAD_PID) {
- fprintf(stderr, "tm: failed to spawn waker\n");
- goto fail;
- }
- ++id;
-
- /* Wait for all lockers to exit. */
- if ((err = os_wait(pids, nprocs)) != 0) {
- fprintf(stderr, "locker wait failed with %d\n", err);
- goto fail;
- }
-
- /* Signal wakeup process to exit. */
- if ((err = __os_open(
- dbenv, MT_FILE_QUIT, DB_OSO_CREATE, 0664, &fhp)) != 0) {
- fprintf(stderr, "tm: open %s\n", db_strerror(err));
- goto fail;
- }
- (void)__os_closehandle(dbenv, fhp);
-
- /* Wait for wakeup process/thread. */
- if ((err = os_wait(&wakeup_pid, 1)) != 0) {
- fprintf(stderr,
- "%lu: exited %d\n", (u_long)wakeup_pid, err);
- goto fail;
- }
- } else { /* Run the single-process test. */
- /* Spawn locker threads. */
- if (locker_start(0) != 0)
- goto fail;
-
- /* Spawn wakeup thread. */
- if (wakeup_start(nthreads) != 0)
- goto fail;
-
- /* Wait for all lockers to exit. */
- if (locker_wait() != 0)
- goto fail;
-
- /* Signal wakeup process to exit. */
- if ((err = __os_open(
- dbenv, MT_FILE_QUIT, DB_OSO_CREATE, 0664, &fhp)) != 0) {
- fprintf(stderr, "tm: open %s\n", db_strerror(err));
- goto fail;
- }
- (void)__os_closehandle(dbenv, fhp);
-
- /* Wait for wakeup thread. */
- if (wakeup_wait() != 0)
- goto fail;
- }
-
- tm_mutex_stats(); /* Display run statistics. */
- tm_mutex_destroy(); /* Destroy mutexes. */
-
- unmap_file(gm_addr, map_fhp); /* Detach from backing file. */
-
- tm_env_close(); /* Detach from environment. */
-
- printf("tm: test succeeded\n");
- return (EXIT_SUCCESS);
-
-fail: printf("tm: FAILED!\n");
- return (EXIT_FAILURE);
-}
-
-int
-locker_start(id)
- u_long id;
-{
-#if defined(MUTEX_THREAD_TEST)
- int err, i;
-
- /*
- * Spawn off threads. We have nthreads all locking and going to
- * sleep, and one other thread cycling through and waking them up.
- */
- if ((kidsp =
- (os_thread_t *)calloc(sizeof(os_thread_t), nthreads)) == NULL) {
- fprintf(stderr, "tm: %s\n", strerror(errno));
- return (1);
- }
- for (i = 0; i < nthreads; i++)
- if ((err = os_thread_create(
- &kidsp[i], NULL, run_lthread, (void *)(id + i))) != 0) {
- fprintf(stderr, "tm: failed spawning thread: %s\n",
- db_strerror(err));
- return (1);
- }
- return (0);
-#else
- return (run_lthread((void *)id) == NULL ? 0 : 1);
-#endif
-}
-
-int
-locker_wait()
-{
-#if defined(MUTEX_THREAD_TEST)
- int i;
- void *retp;
-
- /* Wait for the threads to exit. */
- for (i = 0; i < nthreads; i++) {
- os_thread_join(kidsp[i], &retp);
- if (retp != NULL) {
- fprintf(stderr, "tm: thread exited with error\n");
- return (1);
- }
- }
- free(kidsp);
-#endif
- return (0);
-}
-
-void *
-run_lthread(arg)
- void *arg;
-{
- TM *gp, *mp, *tp;
- u_long id, tid;
- int err, i, lock, nl;
-
- id = (uintptr_t)arg;
-#if defined(MUTEX_THREAD_TEST)
- tid = (u_long)os_thread_self();
-#else
- tid = 0;
-#endif
- printf("Locker: ID %03lu (PID: %lu; TID: %lx)\n",
- id, (u_long)getpid(), tid);
-
- gp = (TM *)gm_addr;
- tp = (TM *)(tm_addr + id * sizeof(TM));
-
- for (nl = nlocks; nl > 0;) {
- /* Select and acquire a data lock. */
- lock = rand() % maxlocks;
- mp = (TM *)(lm_addr + lock * sizeof(TM));
- if (verbose)
- printf("%03lu: lock %d (mtx: %lu)\n",
- id, lock, (u_long)mp->mutex);
-
- if ((err = dbenv->mutex_lock(dbenv, mp->mutex)) != 0) {
- fprintf(stderr, "%03lu: never got lock %d: %s\n",
- id, lock, db_strerror(err));
- return ((void *)1);
- }
- if (mp->id != 0) {
- fprintf(stderr,
- "RACE! (%03lu granted lock %d held by %03lu)\n",
- id, lock, mp->id);
- return ((void *)1);
- }
- mp->id = id;
-
- /*
- * 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 (mp->id != id) {
- fprintf(stderr,
- "RACE! (%03lu stole lock %d from %03lu)\n",
- mp->id, lock, id);
- return ((void *)1);
- }
- }
-
- /*
- * 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 ((err = dbenv->mutex_lock(dbenv, gp->mutex)) != 0) {
- fprintf(stderr,
- "%03lu: global lock: %s\n", id, db_strerror(err));
- return ((void *)1);
- }
- if (tp->id != 0 && tp->id != id) {
- fprintf(stderr,
- "%03lu: per-thread mutex isn't mine, owned by %03lu\n",
- id, tp->id);
- return ((void *)1);
- }
- tp->id = id;
- if (verbose)
- printf("%03lu: self-blocking (mtx: %lu)\n",
- id, (u_long)tp->mutex);
- if (tp->wakeme) {
- fprintf(stderr,
- "%03lu: wakeup flag incorrectly set\n", id);
- return ((void *)1);
- }
- tp->wakeme = 1;
- if ((err = dbenv->mutex_unlock(dbenv, gp->mutex)) != 0) {
- fprintf(stderr,
- "%03lu: global unlock: %s\n", id, db_strerror(err));
- return ((void *)1);
- }
- if ((err = dbenv->mutex_lock(dbenv, tp->mutex)) != 0) {
- fprintf(stderr, "%03lu: per-thread lock: %s\n",
- id, db_strerror(err));
- return ((void *)1);
- }
- /* Time passes... */
- if (tp->wakeme) {
- fprintf(stderr, "%03lu: wakeup flag not cleared\n", id);
- return ((void *)1);
- }
-
- if (verbose)
- printf("%03lu: release %d (mtx: %lu)\n",
- id, lock, (u_long)mp->mutex);
-
- /* Release the data lock. */
- mp->id = 0;
- if ((err = dbenv->mutex_unlock(dbenv, mp->mutex)) != 0) {
- fprintf(stderr,
- "%03lu: lock release: %s\n", id, db_strerror(err));
- return ((void *)1);
- }
-
- if (--nl % 100 == 0) {
- fprintf(stderr, "%03lu: %d\n", id, nl);
- /*
- * Windows buffers stderr and the output looks wrong
- * without this.
- */
- fflush(stderr);
- }
- }
-
- return (NULL);
-}
-
-int
-wakeup_start(id)
- u_long id;
-{
-#if defined(MUTEX_THREAD_TEST)
- int err;
-
- /*
- * Spawn off wakeup thread.
- */
- if ((err = os_thread_create(
- &wakep, NULL, run_wthread, (void *)id)) != 0) {
- fprintf(stderr, "tm: failed spawning wakeup thread: %s\n",
- db_strerror(err));
- return (1);
- }
- return (0);
-#else
- return (run_wthread((void *)id) == NULL ? 0 : 1);
-#endif
-}
-
-int
-wakeup_wait()
-{
-#if defined(MUTEX_THREAD_TEST)
- void *retp;
-
- /*
- * A file is created when the wakeup thread is no longer needed.
- */
- os_thread_join(wakep, &retp);
- if (retp != NULL) {
- fprintf(stderr, "tm: wakeup thread exited with error\n");
- return (1);
- }
-#endif
- return (0);
-}
-
-/*
- * run_wthread --
- * Thread to wake up other threads that are sleeping.
- */
-void *
-run_wthread(arg)
- void *arg;
-{
- TM *gp, *tp;
- u_long id, tid;
- int check_id, err;
-
- id = (uintptr_t)arg;
-#if defined(MUTEX_THREAD_TEST)
- tid = (u_long)os_thread_self();
-#else
- tid = 0;
-#endif
- printf("Wakeup: ID %03lu (PID: %lu; TID: %lx)\n",
- id, (u_long)getpid(), tid);
-
- gp = (TM *)gm_addr;
-
- /* Loop, waking up sleepers and periodically sleeping ourselves. */
- for (check_id = 0;; ++check_id) {
- /* Check to see if the locking threads have finished. */
- if (__os_exists(MT_FILE_QUIT, NULL) == 0)
- break;
-
- /* Check for ID wraparound. */
- if (check_id == nthreads * nprocs)
- check_id = 0;
-
- /* Check for a thread that needs a wakeup. */
- tp = (TM *)(tm_addr + check_id * sizeof(TM));
- if (!tp->wakeme)
- continue;
-
- if (verbose) {
- printf("%03lu: wakeup thread %03lu (mtx: %lu)\n",
- id, tp->id, (u_long)tp->mutex);
- fflush(stdout);
- }
-
- /* Acquire the global lock. */
- if ((err = dbenv->mutex_lock(dbenv, gp->mutex)) != 0) {
- fprintf(stderr,
- "wakeup: global lock: %s\n", db_strerror(err));
- return ((void *)1);
- }
-
- tp->wakeme = 0;
- if ((err = dbenv->mutex_unlock(dbenv, tp->mutex)) != 0) {
- fprintf(stderr,
- "wakeup: unlock: %s\n", db_strerror(err));
- return ((void *)1);
- }
-
- if ((err = dbenv->mutex_unlock(dbenv, gp->mutex))) {
- fprintf(stderr,
- "wakeup: global unlock: %s\n", db_strerror(err));
- return ((void *)1);
- }
-
- __os_sleep(dbenv, 0, rand() % 3);
- }
- return (NULL);
-}
-
-/*
- * tm_env_init --
- * Create the backing database environment.
- */
-int
-tm_env_init()
-{
- u_int32_t flags;
- int ret;
- char *home;
-
- /*
- * Create an environment object and initialize it for error
- * reporting.
- */
- if ((ret = db_env_create(&dbenv, 0)) != 0) {
- fprintf(stderr, "tm: %s\n", db_strerror(ret));
- return (1);
- }
- dbenv->set_errfile(dbenv, stderr);
- dbenv->set_errpfx(dbenv, "tm");
-
- /* Allocate enough mutexes. */
- if ((ret = dbenv->mutex_set_increment(dbenv,
- 1 + nthreads * nprocs + maxlocks)) != 0) {
- dbenv->err(dbenv, ret, "dbenv->mutex_set_increment");
- return (1);
- }
-
- flags = DB_CREATE;
- if (nprocs == 1) {
- home = NULL;
- flags |= DB_PRIVATE;
- } else
- home = TESTDIR;
- if (nthreads != 1)
- flags |= DB_THREAD;
- if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) {
- dbenv->err(dbenv, ret, "environment open: %s", home);
- return (1);
- }
-
- return (0);
-}
-
-/*
- * tm_env_close --
- * Close the backing database environment.
- */
-void
-tm_env_close()
-{
- (void)dbenv->close(dbenv, 0);
-}
-
-/*
- * tm_file_init --
- * Initialize the backing file.
- */
-void
-tm_file_init()
-{
- DB_FH *fhp;
- int err;
- size_t nwrite;
-
- /* Initialize the backing file. */
- if (verbose)
- printf("Create the backing file.\n");
-
- (void)unlink(MT_FILE);
-
- if ((err = __os_open(dbenv, MT_FILE,
- DB_OSO_CREATE | DB_OSO_TRUNC, 0666, &fhp)) == -1) {
- (void)fprintf(stderr,
- "%s: open: %s\n", MT_FILE, db_strerror(err));
- exit(EXIT_FAILURE);
- }
-
- if ((err = __os_seek(dbenv, fhp,
- 0, 0, len, 0, DB_OS_SEEK_SET)) != 0 ||
- (err = __os_write(dbenv, fhp, &err, 1, &nwrite)) != 0 ||
- nwrite != 1) {
- (void)fprintf(stderr,
- "%s: seek/write: %s\n", MT_FILE, db_strerror(err));
- exit(EXIT_FAILURE);
- }
- (void)__os_closehandle(dbenv, fhp);
-}
-
-/*
- * tm_mutex_init --
- * Initialize the mutexes.
- */
-void
-tm_mutex_init()
-{
- TM *mp;
- int err, i;
-
- if (verbose)
- printf("Allocate the global mutex: ");
- mp = (TM *)gm_addr;
- if ((err = dbenv->mutex_alloc(dbenv, 0, &mp->mutex)) != 0) {
- fprintf(stderr,
- "DB_ENV->mutex_alloc (global): %s\n", db_strerror(err));
- exit(EXIT_FAILURE);
- }
- if (verbose)
- printf("%lu\n", (u_long)mp->mutex);
-
- if (verbose)
- printf(
- "Allocate %d per-thread, self-blocking mutexes: ",
- nthreads * nprocs);
- for (i = 0; i < nthreads * nprocs; ++i) {
- mp = (TM *)(tm_addr + i * sizeof(TM));
- if ((err = dbenv->mutex_alloc(
- dbenv, DB_MUTEX_SELF_BLOCK, &mp->mutex)) != 0) {
- fprintf(stderr,
- "DB_ENV->mutex_alloc (per-thread %d): %s\n",
- i, db_strerror(err));
- exit(EXIT_FAILURE);
- }
- if ((err = dbenv->mutex_lock(dbenv, mp->mutex)) != 0) {
- fprintf(stderr,
- "DB_ENV->mutex_lock (per-thread %d): %s\n",
- i, db_strerror(err));
- exit(EXIT_FAILURE);
- }
- if (verbose)
- printf("%lu ", (u_long)mp->mutex);
- }
- if (verbose)
- printf("\n");
-
- if (verbose)
- printf("Allocate %d per-lock mutexes: ", maxlocks);
- for (i = 0; i < maxlocks; ++i) {
- mp = (TM *)(lm_addr + i * sizeof(TM));
- if ((err = dbenv->mutex_alloc(dbenv, 0, &mp->mutex)) != 0) {
- fprintf(stderr,
- "DB_ENV->mutex_alloc (per-lock: %d): %s\n",
- i, db_strerror(err));
- exit(EXIT_FAILURE);
- }
- if (verbose)
- printf("%lu ", (u_long)mp->mutex);
- }
- if (verbose)
- printf("\n");
-}
-
-/*
- * tm_mutex_destroy --
- * Destroy the mutexes.
- */
-void
-tm_mutex_destroy()
-{
- TM *gp, *mp;
- int err, i;
-
- if (verbose)
- printf("Destroy the global mutex.\n");
- gp = (TM *)gm_addr;
- if ((err = dbenv->mutex_free(dbenv, gp->mutex)) != 0) {
- fprintf(stderr,
- "DB_ENV->mutex_free (global): %s\n", db_strerror(err));
- exit(EXIT_FAILURE);
- }
-
- if (verbose)
- printf("Destroy the per-thread mutexes.\n");
- for (i = 0; i < nthreads * nprocs; ++i) {
- mp = (TM *)(tm_addr + i * sizeof(TM));
- if ((err = dbenv->mutex_free(dbenv, mp->mutex)) != 0) {
- fprintf(stderr,
- "DB_ENV->mutex_free (per-thread %d): %s\n",
- i, db_strerror(err));
- exit(EXIT_FAILURE);
- }
- }
-
- if (verbose)
- printf("Destroy the per-lock mutexes.\n");
- for (i = 0; i < maxlocks; ++i) {
- mp = (TM *)(lm_addr + i * sizeof(TM));
- if ((err = dbenv->mutex_free(dbenv, mp->mutex)) != 0) {
- fprintf(stderr,
- "DB_ENV->mutex_free (per-lock: %d): %s\n",
- i, db_strerror(err));
- exit(EXIT_FAILURE);
- }
- }
-
- (void)unlink(MT_FILE);
-}
-
-/*
- * tm_mutex_stats --
- * Display mutex statistics.
- */
-void
-tm_mutex_stats()
-{
-#ifdef HAVE_STATISTICS
- TM *mp;
- int i;
- u_int32_t set_wait, set_nowait;
-
- printf("Per-lock mutex statistics.\n");
- for (i = 0; i < maxlocks; ++i) {
- mp = (TM *)(lm_addr + i * sizeof(TM));
- __mutex_set_wait_info(dbenv, mp->mutex, &set_wait, &set_nowait);
- printf("mutex %2d: wait: %lu; no wait %lu\n", i,
- (u_long)set_wait, (u_long)set_nowait);
- }
-#endif
-}
-
-/*
- * map_file --
- * Map in the backing file.
- */
-void
-map_file(gm_addrp, tm_addrp, lm_addrp, fhpp)
- u_int8_t **gm_addrp, **tm_addrp, **lm_addrp;
- DB_FH **fhpp;
-{
- void *addr;
- DB_FH *fhp;
- int err;
-
-#ifndef MAP_FAILED
-#define MAP_FAILED (void *)-1
-#endif
-#ifndef MAP_FILE
-#define MAP_FILE 0
-#endif
- if ((err = __os_open(dbenv, MT_FILE, 0, 0, &fhp)) != 0) {
- fprintf(stderr, "%s: open %s\n", MT_FILE, db_strerror(err));
- exit(EXIT_FAILURE);
- }
-
- if ((err = __os_mapfile(dbenv, MT_FILE, fhp, len, 0, &addr)) != 0) {
- fprintf(stderr, "%s: mmap: %s\n", MT_FILE, db_strerror(err));
- exit(EXIT_FAILURE);
- }
-
- *gm_addrp = (u_int8_t *)addr;
- addr = (u_int8_t *)addr + sizeof(TM);
- *tm_addrp = (u_int8_t *)addr;
- addr = (u_int8_t *)addr + sizeof(TM) * (nthreads * nprocs);
- *lm_addrp = (u_int8_t *)addr;
-
- if (fhpp != NULL)
- *fhpp = fhp;
-}
-
-/*
- * unmap_file --
- * Discard backing file map.
- */
-void
-unmap_file(addr, fhp)
- u_int8_t *addr;
- DB_FH *fhp;
-{
- int err;
-
- if ((err = __os_unmapfile(dbenv, addr, len)) != 0) {
- fprintf(stderr, "munmap: %s\n", db_strerror(err));
- exit(EXIT_FAILURE);
- }
- if ((err = __os_closehandle(dbenv, fhp)) != 0) {
- fprintf(stderr, "close: %s\n", db_strerror(err));
- exit(EXIT_FAILURE);
- }
-}
-
-/*
- * usage --
- *
- */
-int
-usage()
-{
- (void)fprintf(stderr, "%s\n\t%s\n",
- "usage: tm [-v] [-l maxlocks]",
- "[-n locks] [-p procs] [-T locker=ID|wakeup=ID] [-t threads]");
- return (EXIT_FAILURE);
-}
-
-/*
- * os_wait --
- * Wait for an array of N procs.
- */
-int
-os_wait(procs, nprocs)
- os_pid_t *procs;
- int nprocs;
-{
- int i, status;
-#if defined(DB_WIN32)
- DWORD ret;
-#endif
-
- status = 0;
-
-#if defined(DB_WIN32)
- do {
- ret = WaitForMultipleObjects(nprocs, procs, FALSE, INFINITE);
- i = ret - WAIT_OBJECT_0;
- if (i < 0 || i >= nprocs)
- return (__os_get_errno());
-
- if ((GetExitCodeProcess(procs[i], &ret) == 0) || (ret != 0))
- return (ret);
-
- /* remove the process handle from the list */
- while (++i < nprocs)
- procs[i - 1] = procs[i];
- } while (--nprocs);
-#elif !defined(HAVE_VXWORKS)
- do {
- if ((i = wait(&status)) == -1)
- return (__os_get_errno());
-
- if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0) {
- for (i = 0; i < nprocs; i++)
- kill(procs[i], SIGKILL);
- return (WEXITSTATUS(status));
- }
- } while (--nprocs);
-#endif
-
- return (0);
-}
-
-os_pid_t
-spawn_proc(id, tmpath, typearg)
- u_long id;
- char *tmpath, *typearg;
-{
- char lbuf[16], nbuf[16], pbuf[16], tbuf[16], Tbuf[256];
- char *const vbuf = verbose ? "-v" : NULL;
- char *args[] = { NULL /* tmpath */,
- "-l", NULL /* lbuf */, "-n", NULL /* nbuf */,
- "-p", NULL /* pbuf */, "-t", NULL /* tbuf */,
- "-T", NULL /* Tbuf */, NULL /* vbuf */,
- NULL
- };
-
- args[0] = tmpath;
- snprintf(lbuf, sizeof(lbuf), "%d", maxlocks);
- args[2] = lbuf;
- snprintf(nbuf, sizeof(nbuf), "%d", nlocks);
- args[4] = nbuf;
- snprintf(pbuf, sizeof(pbuf), "%d", nprocs);
- args[6] = pbuf;
- snprintf(tbuf, sizeof(tbuf), "%d", nthreads);
- args[8] = tbuf;
- snprintf(Tbuf, sizeof(Tbuf), "%s=%lu", typearg, id);
- args[10] = Tbuf;
- args[11] = vbuf;
-
- return (os_spawn(tmpath, args));
-}
-
-os_pid_t
-os_spawn(path, argv)
- const char *path;
- char *const argv[];
-{
- os_pid_t pid;
- int status;
-
- COMPQUIET(pid, 0);
- COMPQUIET(status, 0);
-
-#ifdef HAVE_VXWORKS
- fprintf(stderr, "ERROR: os_spawn not supported for VxWorks.\n");
- return (OS_BAD_PID);
-#elif defined(HAVE_QNX)
- /*
- * For QNX, we cannot fork if we've ever used threads. So
- * we'll use their spawn function. We use 'spawnl' which
- * is NOT a POSIX function.
- *
- * The return value of spawnl is just what we want depending
- * on the value of the 'wait' arg.
- */
- return (spawnv(P_NOWAIT, path, argv));
-#elif defined(DB_WIN32)
- return (os_pid_t)(_spawnv(P_NOWAIT, path, argv));
-#else
- if ((pid = fork()) != 0) {
- if (pid == -1)
- return (OS_BAD_PID);
- return (pid);
- } else {
- execv(path, argv);
- exit(EXIT_FAILURE);
- }
-#endif
-}