tm.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:14k
- /*
- * 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 bytesn",
- 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 %dn", (u_long)pid, WEXITSTATUS(status));
- if (WEXITSTATUS(status) != 0)
- eval = EXIT_FAILURE;
- }
- tm_mutex_stats();
- tm_mutex_destroy();
- printf("tm: exit status: %sn",
- 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: %sn", 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: %sn", 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: %sn",
- 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: %sn",
- 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 errorn", 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 errorn");
- 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: %dn", 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: %03dn", gid1, gid2, lock);
- if (__db_mutex_lock(&dbenv, mp)) {
- fprintf(stderr,
- "%lu/%lx: never got lockn", 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 lockn", 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 failedn", gid1, gid2);
- return ((void *)EXIT_FAILURE);
- }
- if (__db_mutex_lock(&dbenv, mp)) {
- fprintf(stderr,
- "%lu/%lx: per-thread lockn", gid1, gid2);
- return ((void *)EXIT_FAILURE);
- }
- /* Time passes... */
- if (F_ISSET(mp, MUTEX_WAKEME)) {
- fprintf(stderr, "%lu/%lx: %03d wakeup flag still setn",
- 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 failedn", gid1, gid2);
- return ((void *)EXIT_FAILURE);
- }
- if (--nl % 100 == 0)
- fprintf(stderr, "%lu/%lx: %dn", 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 failedn");
- 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 failedn");
- return ((void *)EXIT_FAILURE);
- }
- }
- if (++id < nthreads && id % 3 != 0)
- goto next;
- if (__db_mutex_unlock(&dbenv, gm_addr)) {
- fprintf(stderr, "wt: global unlock failedn");
- 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: %sn", 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: %sn", 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): %sn", 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): %sn",
- i, strerror(errno));
- exit(EXIT_FAILURE);
- }
- if (__db_mutex_lock(&dbenv, mp)) {
- fprintf(stderr,
- "__db_mutex_init (per-thread %d) lock: %sn",
- 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): %sn",
- 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): %sn", 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): %sn",
- 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): %sn",
- 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 %lun", 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 %sn", 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: %sn", 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: %sn", strerror(errno));
- exit(EXIT_FAILURE);
- }
- if (close(fd) != 0) {
- fprintf(stderr, "close: %sn", strerror(errno));
- exit(EXIT_FAILURE);
- }
- }