00001
00002
00003
00004
00005
00006 #include "db_config.h"
00007
00008 #ifndef NO_SYSTEM_INCLUDES
00009 #include <sys/types.h>
00010 #include <sys/wait.h>
00011
00012 #include <errno.h>
00013 #include <signal.h>
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <time.h>
00018
00019 #if defined(MUTEX_THREAD_TEST)
00020 #include <pthread.h>
00021 #endif
00022 #endif
00023
00024 #include "db_int.h"
00025
00026 #ifdef DB_WIN32
00027 extern int getopt(int, char * const *, const char *);
00028
00029 typedef HANDLE os_pid_t;
00030 typedef HANDLE os_thread_t;
00031
00032 #define os_thread_create(thrp, attr, func, arg) \
00033 (((*(thrp) = CreateThread(NULL, 0, \
00034 (LPTHREAD_START_ROUTINE)(func), (arg), 0, NULL)) == NULL) ? -1 : 0)
00035 #define os_thread_join(thr, statusp) \
00036 ((WaitForSingleObject((thr), INFINITE) == WAIT_OBJECT_0) && \
00037 GetExitCodeThread((thr), (LPDWORD)(statusp)) ? 0 : -1)
00038 #define os_thread_self() GetCurrentThreadId()
00039
00040 #else
00041
00042 typedef pid_t os_pid_t;
00043
00044 #ifdef MUTEX_THREAD_TEST
00045 typedef pthread_t os_thread_t;
00046 #endif
00047
00048 #define os_thread_create(thrp, attr, func, arg) \
00049 pthread_create((thrp), (attr), (func), (arg))
00050 #define os_thread_join(thr, statusp) pthread_join((thr), (statusp))
00051 #define os_thread_self() pthread_self()
00052 #endif
00053
00054 #define OS_BAD_PID (os_pid_t)-1
00055
00056 #define TESTDIR "TESTDIR"
00057 #define MT_FILE "TESTDIR/mutex.file"
00058 #define MT_FILE_QUIT "TESTDIR/mutex.file.quit"
00059
00060
00061
00062
00063
00064
00065
00066 typedef struct {
00067 db_mutex_t mutex;
00068 u_long id;
00069 u_int wakeme;
00070 } TM;
00071
00072 DB_ENV *dbenv;
00073 size_t len;
00074
00075 u_int8_t *gm_addr;
00076 u_int8_t *lm_addr;
00077 u_int8_t *tm_addr;
00078
00079 #ifdef MUTEX_THREAD_TEST
00080 os_thread_t *kidsp;
00081 os_thread_t wakep;
00082 #endif
00083
00084 int maxlocks = 20;
00085 int nlocks = 10000;
00086 int nprocs = 20;
00087 int nthreads = 1;
00088 int verbose;
00089
00090 int locker_start(u_long);
00091 int locker_wait(void);
00092 void map_file(u_int8_t **, u_int8_t **, u_int8_t **, DB_FH **);
00093 os_pid_t os_spawn(const char *, char *const[]);
00094 int os_wait(os_pid_t *, int);
00095 void *run_lthread(void *);
00096 void *run_wthread(void *);
00097 os_pid_t spawn_proc(u_long, char *, char *);
00098 void tm_env_close(void);
00099 int tm_env_init(void);
00100 void tm_file_init(void);
00101 void tm_mutex_destroy(void);
00102 void tm_mutex_init(void);
00103 void tm_mutex_stats(void);
00104 void unmap_file(u_int8_t *, DB_FH *);
00105 int usage(void);
00106 int wakeup_start(u_long);
00107 int wakeup_wait(void);
00108
00109 int
00110 main(argc, argv)
00111 int argc;
00112 char *argv[];
00113 {
00114 enum {LOCKER, WAKEUP, PARENT} rtype;
00115 extern int optind;
00116 extern char *optarg;
00117 os_pid_t wakeup_pid, *pids;
00118 u_long id;
00119 DB_FH *fhp, *map_fhp;
00120 int ch, err, i;
00121 char *p, *tmpath, cmd[1024];
00122
00123 rtype = PARENT;
00124 id = 0;
00125 tmpath = argv[0];
00126 while ((ch = getopt(argc, argv, "l:n:p:T:t:v")) != EOF)
00127 switch (ch) {
00128 case 'l':
00129 maxlocks = atoi(optarg);
00130 break;
00131 case 'n':
00132 nlocks = atoi(optarg);
00133 break;
00134 case 'p':
00135 nprocs = atoi(optarg);
00136 break;
00137 case 't':
00138 if ((nthreads = atoi(optarg)) == 0)
00139 nthreads = 1;
00140 #if !defined(MUTEX_THREAD_TEST)
00141 if (nthreads != 1) {
00142 (void)fprintf(stderr,
00143 "tm: thread support not available or not compiled for this platform.\n");
00144 return (EXIT_FAILURE);
00145 }
00146 #endif
00147 break;
00148 case 'T':
00149 if (!memcmp(optarg, "locker", sizeof("locker") - 1))
00150 rtype = LOCKER;
00151 else if (
00152 !memcmp(optarg, "wakeup", sizeof("wakeup") - 1))
00153 rtype = WAKEUP;
00154 else
00155 return (usage());
00156 if ((p = strchr(optarg, '=')) == NULL)
00157 return (usage());
00158 id = atoi(p + 1);
00159 break;
00160 case 'v':
00161 verbose = 1;
00162 break;
00163 case '?':
00164 default:
00165 return (usage());
00166 }
00167 argc -= optind;
00168 argv += optind;
00169
00170
00171
00172
00173
00174 if (nprocs == 1 && nthreads == 1) {
00175 fprintf(stderr,
00176 "tm: running in a single process requires multiple threads\n");
00177 return (EXIT_FAILURE);
00178 }
00179
00180 len = sizeof(TM) * (1 + nthreads * nprocs + maxlocks);
00181
00182
00183
00184
00185
00186
00187 if (rtype == LOCKER || rtype == WAKEUP) {
00188 __os_sleep(dbenv, 3, 0);
00189
00190 srand((u_int)time(NULL) % getpid());
00191
00192 if (tm_env_init() != 0)
00193 exit(EXIT_FAILURE);
00194
00195 map_file(&gm_addr, &tm_addr, &lm_addr, &map_fhp);
00196 if (verbose)
00197 printf(
00198 "Backing file: global (%#lx), threads (%#lx), locks (%#lx)\n",
00199 (u_long)gm_addr, (u_long)tm_addr, (u_long)lm_addr);
00200
00201 if ((rtype == LOCKER ?
00202 locker_start(id) : wakeup_start(id)) != 0)
00203 exit(EXIT_FAILURE);
00204 if ((rtype == LOCKER ? locker_wait() : wakeup_wait()) != 0)
00205 exit(EXIT_FAILURE);
00206
00207 unmap_file(gm_addr, map_fhp);
00208
00209 tm_env_close();
00210
00211 exit(EXIT_SUCCESS);
00212 }
00213
00214
00215
00216
00217
00218
00219 snprintf(cmd, sizeof(cmd), "rm -rf %s", TESTDIR);
00220 (void)system(cmd);
00221 snprintf(cmd, sizeof(cmd), "mkdir %s", TESTDIR);
00222 (void)system(cmd);
00223
00224 printf(
00225 "tm: %d processes, %d threads/process, %d lock requests from %d locks\n",
00226 nprocs, nthreads, nlocks, maxlocks);
00227 printf("tm: backing file %lu bytes\n", (u_long)len);
00228
00229 if (tm_env_init() != 0)
00230 exit(EXIT_FAILURE);
00231
00232 tm_file_init();
00233
00234
00235 map_file(&gm_addr, &tm_addr, &lm_addr, &map_fhp);
00236 if (verbose)
00237 printf(
00238 "backing file: global (%#lx), threads (%#lx), locks (%#lx)\n",
00239 (u_long)gm_addr, (u_long)tm_addr, (u_long)lm_addr);
00240
00241 tm_mutex_init();
00242
00243 if (nprocs > 1) {
00244
00245 if ((pids = calloc(nprocs, sizeof(os_pid_t))) == NULL) {
00246 fprintf(stderr, "tm: %s\n", strerror(errno));
00247 goto fail;
00248 }
00249
00250
00251 for (i = 0; i < nprocs; ++i) {
00252 if ((pids[i] =
00253 spawn_proc(id, tmpath, "locker")) == OS_BAD_PID) {
00254 fprintf(stderr,
00255 "tm: failed to spawn a locker\n");
00256 goto fail;
00257 }
00258 id += nthreads;
00259 }
00260
00261
00262 if ((wakeup_pid =
00263 spawn_proc(id, tmpath, "wakeup")) == OS_BAD_PID) {
00264 fprintf(stderr, "tm: failed to spawn waker\n");
00265 goto fail;
00266 }
00267 ++id;
00268
00269
00270 if ((err = os_wait(pids, nprocs)) != 0) {
00271 fprintf(stderr, "locker wait failed with %d\n", err);
00272 goto fail;
00273 }
00274
00275
00276 if ((err = __os_open(
00277 dbenv, MT_FILE_QUIT, DB_OSO_CREATE, 0664, &fhp)) != 0) {
00278 fprintf(stderr, "tm: open %s\n", db_strerror(err));
00279 goto fail;
00280 }
00281 (void)__os_closehandle(dbenv, fhp);
00282
00283
00284 if ((err = os_wait(&wakeup_pid, 1)) != 0) {
00285 fprintf(stderr,
00286 "%lu: exited %d\n", (u_long)wakeup_pid, err);
00287 goto fail;
00288 }
00289 } else {
00290
00291 if (locker_start(0) != 0)
00292 goto fail;
00293
00294
00295 if (wakeup_start(nthreads) != 0)
00296 goto fail;
00297
00298
00299 if (locker_wait() != 0)
00300 goto fail;
00301
00302
00303 if ((err = __os_open(
00304 dbenv, MT_FILE_QUIT, DB_OSO_CREATE, 0664, &fhp)) != 0) {
00305 fprintf(stderr, "tm: open %s\n", db_strerror(err));
00306 goto fail;
00307 }
00308 (void)__os_closehandle(dbenv, fhp);
00309
00310
00311 if (wakeup_wait() != 0)
00312 goto fail;
00313 }
00314
00315 tm_mutex_stats();
00316 tm_mutex_destroy();
00317
00318 unmap_file(gm_addr, map_fhp);
00319
00320 tm_env_close();
00321
00322 printf("tm: test succeeded\n");
00323 return (EXIT_SUCCESS);
00324
00325 fail: printf("tm: FAILED!\n");
00326 return (EXIT_FAILURE);
00327 }
00328
00329 int
00330 locker_start(id)
00331 u_long id;
00332 {
00333 #if defined(MUTEX_THREAD_TEST)
00334 int err, i;
00335
00336
00337
00338
00339
00340 if ((kidsp =
00341 (os_thread_t *)calloc(sizeof(os_thread_t), nthreads)) == NULL) {
00342 fprintf(stderr, "tm: %s\n", strerror(errno));
00343 return (1);
00344 }
00345 for (i = 0; i < nthreads; i++)
00346 if ((err = os_thread_create(
00347 &kidsp[i], NULL, run_lthread, (void *)(id + i))) != 0) {
00348 fprintf(stderr, "tm: failed spawning thread: %s\n",
00349 db_strerror(err));
00350 return (1);
00351 }
00352 return (0);
00353 #else
00354 return (run_lthread((void *)id) == NULL ? 0 : 1);
00355 #endif
00356 }
00357
00358 int
00359 locker_wait()
00360 {
00361 #if defined(MUTEX_THREAD_TEST)
00362 int i;
00363 void *retp;
00364
00365
00366 for (i = 0; i < nthreads; i++) {
00367 os_thread_join(kidsp[i], &retp);
00368 if (retp != NULL) {
00369 fprintf(stderr, "tm: thread exited with error\n");
00370 return (1);
00371 }
00372 }
00373 free(kidsp);
00374 #endif
00375 return (0);
00376 }
00377
00378 void *
00379 run_lthread(arg)
00380 void *arg;
00381 {
00382 TM *gp, *mp, *tp;
00383 u_long id, tid;
00384 int err, i, lock, nl;
00385
00386 id = (uintptr_t)arg;
00387 #if defined(MUTEX_THREAD_TEST)
00388 tid = (u_long)os_thread_self();
00389 #else
00390 tid = 0;
00391 #endif
00392 printf("Locker: ID %03lu (PID: %lu; TID: %lx)\n",
00393 id, (u_long)getpid(), tid);
00394
00395 gp = (TM *)gm_addr;
00396 tp = (TM *)(tm_addr + id * sizeof(TM));
00397
00398 for (nl = nlocks; nl > 0;) {
00399
00400 lock = rand() % maxlocks;
00401 mp = (TM *)(lm_addr + lock * sizeof(TM));
00402 if (verbose)
00403 printf("%03lu: lock %d (mtx: %lu)\n",
00404 id, lock, (u_long)mp->mutex);
00405
00406 if ((err = dbenv->mutex_lock(dbenv, mp->mutex)) != 0) {
00407 fprintf(stderr, "%03lu: never got lock %d: %s\n",
00408 id, lock, db_strerror(err));
00409 return ((void *)1);
00410 }
00411 if (mp->id != 0) {
00412 fprintf(stderr,
00413 "RACE! (%03lu granted lock %d held by %03lu)\n",
00414 id, lock, mp->id);
00415 return ((void *)1);
00416 }
00417 mp->id = id;
00418
00419
00420
00421
00422
00423 for (i = 0; i < 3; ++i) {
00424 __os_sleep(dbenv, 0, rand() % 3);
00425 if (mp->id != id) {
00426 fprintf(stderr,
00427 "RACE! (%03lu stole lock %d from %03lu)\n",
00428 mp->id, lock, id);
00429 return ((void *)1);
00430 }
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443 if ((err = dbenv->mutex_lock(dbenv, gp->mutex)) != 0) {
00444 fprintf(stderr,
00445 "%03lu: global lock: %s\n", id, db_strerror(err));
00446 return ((void *)1);
00447 }
00448 if (tp->id != 0 && tp->id != id) {
00449 fprintf(stderr,
00450 "%03lu: per-thread mutex isn't mine, owned by %03lu\n",
00451 id, tp->id);
00452 return ((void *)1);
00453 }
00454 tp->id = id;
00455 if (verbose)
00456 printf("%03lu: self-blocking (mtx: %lu)\n",
00457 id, (u_long)tp->mutex);
00458 if (tp->wakeme) {
00459 fprintf(stderr,
00460 "%03lu: wakeup flag incorrectly set\n", id);
00461 return ((void *)1);
00462 }
00463 tp->wakeme = 1;
00464 if ((err = dbenv->mutex_unlock(dbenv, gp->mutex)) != 0) {
00465 fprintf(stderr,
00466 "%03lu: global unlock: %s\n", id, db_strerror(err));
00467 return ((void *)1);
00468 }
00469 if ((err = dbenv->mutex_lock(dbenv, tp->mutex)) != 0) {
00470 fprintf(stderr, "%03lu: per-thread lock: %s\n",
00471 id, db_strerror(err));
00472 return ((void *)1);
00473 }
00474
00475 if (tp->wakeme) {
00476 fprintf(stderr, "%03lu: wakeup flag not cleared\n", id);
00477 return ((void *)1);
00478 }
00479
00480 if (verbose)
00481 printf("%03lu: release %d (mtx: %lu)\n",
00482 id, lock, (u_long)mp->mutex);
00483
00484
00485 mp->id = 0;
00486 if ((err = dbenv->mutex_unlock(dbenv, mp->mutex)) != 0) {
00487 fprintf(stderr,
00488 "%03lu: lock release: %s\n", id, db_strerror(err));
00489 return ((void *)1);
00490 }
00491
00492 if (--nl % 100 == 0) {
00493 fprintf(stderr, "%03lu: %d\n", id, nl);
00494
00495
00496
00497
00498 fflush(stderr);
00499 }
00500 }
00501
00502 return (NULL);
00503 }
00504
00505 int
00506 wakeup_start(id)
00507 u_long id;
00508 {
00509 #if defined(MUTEX_THREAD_TEST)
00510 int err;
00511
00512
00513
00514
00515 if ((err = os_thread_create(
00516 &wakep, NULL, run_wthread, (void *)id)) != 0) {
00517 fprintf(stderr, "tm: failed spawning wakeup thread: %s\n",
00518 db_strerror(err));
00519 return (1);
00520 }
00521 return (0);
00522 #else
00523 return (run_wthread((void *)id) == NULL ? 0 : 1);
00524 #endif
00525 }
00526
00527 int
00528 wakeup_wait()
00529 {
00530 #if defined(MUTEX_THREAD_TEST)
00531 void *retp;
00532
00533
00534
00535
00536 os_thread_join(wakep, &retp);
00537 if (retp != NULL) {
00538 fprintf(stderr, "tm: wakeup thread exited with error\n");
00539 return (1);
00540 }
00541 #endif
00542 return (0);
00543 }
00544
00545
00546
00547
00548
00549 void *
00550 run_wthread(arg)
00551 void *arg;
00552 {
00553 TM *gp, *tp;
00554 u_long id, tid;
00555 int check_id, err;
00556
00557 id = (uintptr_t)arg;
00558 #if defined(MUTEX_THREAD_TEST)
00559 tid = (u_long)os_thread_self();
00560 #else
00561 tid = 0;
00562 #endif
00563 printf("Wakeup: ID %03lu (PID: %lu; TID: %lx)\n",
00564 id, (u_long)getpid(), tid);
00565
00566 gp = (TM *)gm_addr;
00567
00568
00569 for (check_id = 0;; ++check_id) {
00570
00571 if (__os_exists(MT_FILE_QUIT, NULL) == 0)
00572 break;
00573
00574
00575 if (check_id == nthreads * nprocs)
00576 check_id = 0;
00577
00578
00579 tp = (TM *)(tm_addr + check_id * sizeof(TM));
00580 if (!tp->wakeme)
00581 continue;
00582
00583 if (verbose) {
00584 printf("%03lu: wakeup thread %03lu (mtx: %lu)\n",
00585 id, tp->id, (u_long)tp->mutex);
00586 fflush(stdout);
00587 }
00588
00589
00590 if ((err = dbenv->mutex_lock(dbenv, gp->mutex)) != 0) {
00591 fprintf(stderr,
00592 "wakeup: global lock: %s\n", db_strerror(err));
00593 return ((void *)1);
00594 }
00595
00596 tp->wakeme = 0;
00597 if ((err = dbenv->mutex_unlock(dbenv, tp->mutex)) != 0) {
00598 fprintf(stderr,
00599 "wakeup: unlock: %s\n", db_strerror(err));
00600 return ((void *)1);
00601 }
00602
00603 if ((err = dbenv->mutex_unlock(dbenv, gp->mutex))) {
00604 fprintf(stderr,
00605 "wakeup: global unlock: %s\n", db_strerror(err));
00606 return ((void *)1);
00607 }
00608
00609 __os_sleep(dbenv, 0, rand() % 3);
00610 }
00611 return (NULL);
00612 }
00613
00614
00615
00616
00617
00618 int
00619 tm_env_init()
00620 {
00621 u_int32_t flags;
00622 int ret;
00623 char *home;
00624
00625
00626
00627
00628
00629 if ((ret = db_env_create(&dbenv, 0)) != 0) {
00630 fprintf(stderr, "tm: %s\n", db_strerror(ret));
00631 return (1);
00632 }
00633 dbenv->set_errfile(dbenv, stderr);
00634 dbenv->set_errpfx(dbenv, "tm");
00635
00636
00637 if ((ret = dbenv->mutex_set_increment(dbenv,
00638 1 + nthreads * nprocs + maxlocks)) != 0) {
00639 dbenv->err(dbenv, ret, "dbenv->mutex_set_increment");
00640 return (1);
00641 }
00642
00643 flags = DB_CREATE;
00644 if (nprocs == 1) {
00645 home = NULL;
00646 flags |= DB_PRIVATE;
00647 } else
00648 home = TESTDIR;
00649 if (nthreads != 1)
00650 flags |= DB_THREAD;
00651 if ((ret = dbenv->open(dbenv, home, flags, 0)) != 0) {
00652 dbenv->err(dbenv, ret, "environment open: %s", home);
00653 return (1);
00654 }
00655
00656 return (0);
00657 }
00658
00659
00660
00661
00662
00663 void
00664 tm_env_close()
00665 {
00666 (void)dbenv->close(dbenv, 0);
00667 }
00668
00669
00670
00671
00672
00673 void
00674 tm_file_init()
00675 {
00676 DB_FH *fhp;
00677 int err;
00678 size_t nwrite;
00679
00680
00681 if (verbose)
00682 printf("Create the backing file.\n");
00683
00684 (void)unlink(MT_FILE);
00685
00686 if ((err = __os_open(dbenv, MT_FILE,
00687 DB_OSO_CREATE | DB_OSO_TRUNC, 0666, &fhp)) == -1) {
00688 (void)fprintf(stderr,
00689 "%s: open: %s\n", MT_FILE, db_strerror(err));
00690 exit(EXIT_FAILURE);
00691 }
00692
00693 if ((err = __os_seek(dbenv, fhp,
00694 0, 0, len, 0, DB_OS_SEEK_SET)) != 0 ||
00695 (err = __os_write(dbenv, fhp, &err, 1, &nwrite)) != 0 ||
00696 nwrite != 1) {
00697 (void)fprintf(stderr,
00698 "%s: seek/write: %s\n", MT_FILE, db_strerror(err));
00699 exit(EXIT_FAILURE);
00700 }
00701 (void)__os_closehandle(dbenv, fhp);
00702 }
00703
00704
00705
00706
00707
00708 void
00709 tm_mutex_init()
00710 {
00711 TM *mp;
00712 int err, i;
00713
00714 if (verbose)
00715 printf("Allocate the global mutex: ");
00716 mp = (TM *)gm_addr;
00717 if ((err = dbenv->mutex_alloc(dbenv, 0, &mp->mutex)) != 0) {
00718 fprintf(stderr,
00719 "DB_ENV->mutex_alloc (global): %s\n", db_strerror(err));
00720 exit(EXIT_FAILURE);
00721 }
00722 if (verbose)
00723 printf("%lu\n", (u_long)mp->mutex);
00724
00725 if (verbose)
00726 printf(
00727 "Allocate %d per-thread, self-blocking mutexes: ",
00728 nthreads * nprocs);
00729 for (i = 0; i < nthreads * nprocs; ++i) {
00730 mp = (TM *)(tm_addr + i * sizeof(TM));
00731 if ((err = dbenv->mutex_alloc(
00732 dbenv, DB_MUTEX_SELF_BLOCK, &mp->mutex)) != 0) {
00733 fprintf(stderr,
00734 "DB_ENV->mutex_alloc (per-thread %d): %s\n",
00735 i, db_strerror(err));
00736 exit(EXIT_FAILURE);
00737 }
00738 if ((err = dbenv->mutex_lock(dbenv, mp->mutex)) != 0) {
00739 fprintf(stderr,
00740 "DB_ENV->mutex_lock (per-thread %d): %s\n",
00741 i, db_strerror(err));
00742 exit(EXIT_FAILURE);
00743 }
00744 if (verbose)
00745 printf("%lu ", (u_long)mp->mutex);
00746 }
00747 if (verbose)
00748 printf("\n");
00749
00750 if (verbose)
00751 printf("Allocate %d per-lock mutexes: ", maxlocks);
00752 for (i = 0; i < maxlocks; ++i) {
00753 mp = (TM *)(lm_addr + i * sizeof(TM));
00754 if ((err = dbenv->mutex_alloc(dbenv, 0, &mp->mutex)) != 0) {
00755 fprintf(stderr,
00756 "DB_ENV->mutex_alloc (per-lock: %d): %s\n",
00757 i, db_strerror(err));
00758 exit(EXIT_FAILURE);
00759 }
00760 if (verbose)
00761 printf("%lu ", (u_long)mp->mutex);
00762 }
00763 if (verbose)
00764 printf("\n");
00765 }
00766
00767
00768
00769
00770
00771 void
00772 tm_mutex_destroy()
00773 {
00774 TM *gp, *mp;
00775 int err, i;
00776
00777 if (verbose)
00778 printf("Destroy the global mutex.\n");
00779 gp = (TM *)gm_addr;
00780 if ((err = dbenv->mutex_free(dbenv, gp->mutex)) != 0) {
00781 fprintf(stderr,
00782 "DB_ENV->mutex_free (global): %s\n", db_strerror(err));
00783 exit(EXIT_FAILURE);
00784 }
00785
00786 if (verbose)
00787 printf("Destroy the per-thread mutexes.\n");
00788 for (i = 0; i < nthreads * nprocs; ++i) {
00789 mp = (TM *)(tm_addr + i * sizeof(TM));
00790 if ((err = dbenv->mutex_free(dbenv, mp->mutex)) != 0) {
00791 fprintf(stderr,
00792 "DB_ENV->mutex_free (per-thread %d): %s\n",
00793 i, db_strerror(err));
00794 exit(EXIT_FAILURE);
00795 }
00796 }
00797
00798 if (verbose)
00799 printf("Destroy the per-lock mutexes.\n");
00800 for (i = 0; i < maxlocks; ++i) {
00801 mp = (TM *)(lm_addr + i * sizeof(TM));
00802 if ((err = dbenv->mutex_free(dbenv, mp->mutex)) != 0) {
00803 fprintf(stderr,
00804 "DB_ENV->mutex_free (per-lock: %d): %s\n",
00805 i, db_strerror(err));
00806 exit(EXIT_FAILURE);
00807 }
00808 }
00809
00810 (void)unlink(MT_FILE);
00811 }
00812
00813
00814
00815
00816
00817 void
00818 tm_mutex_stats()
00819 {
00820 #ifdef HAVE_STATISTICS
00821 TM *mp;
00822 int i;
00823 u_int32_t set_wait, set_nowait;
00824
00825 printf("Per-lock mutex statistics.\n");
00826 for (i = 0; i < maxlocks; ++i) {
00827 mp = (TM *)(lm_addr + i * sizeof(TM));
00828 __mutex_set_wait_info(dbenv, mp->mutex, &set_wait, &set_nowait);
00829 printf("mutex %2d: wait: %lu; no wait %lu\n", i,
00830 (u_long)set_wait, (u_long)set_nowait);
00831 }
00832 #endif
00833 }
00834
00835
00836
00837
00838
00839 void
00840 map_file(gm_addrp, tm_addrp, lm_addrp, fhpp)
00841 u_int8_t **gm_addrp, **tm_addrp, **lm_addrp;
00842 DB_FH **fhpp;
00843 {
00844 void *addr;
00845 DB_FH *fhp;
00846 int err;
00847
00848 #ifndef MAP_FAILED
00849 #define MAP_FAILED (void *)-1
00850 #endif
00851 #ifndef MAP_FILE
00852 #define MAP_FILE 0
00853 #endif
00854 if ((err = __os_open(dbenv, MT_FILE, 0, 0, &fhp)) != 0) {
00855 fprintf(stderr, "%s: open %s\n", MT_FILE, db_strerror(err));
00856 exit(EXIT_FAILURE);
00857 }
00858
00859 if ((err = __os_mapfile(dbenv, MT_FILE, fhp, len, 0, &addr)) != 0) {
00860 fprintf(stderr, "%s: mmap: %s\n", MT_FILE, db_strerror(err));
00861 exit(EXIT_FAILURE);
00862 }
00863
00864 *gm_addrp = (u_int8_t *)addr;
00865 addr = (u_int8_t *)addr + sizeof(TM);
00866 *tm_addrp = (u_int8_t *)addr;
00867 addr = (u_int8_t *)addr + sizeof(TM) * (nthreads * nprocs);
00868 *lm_addrp = (u_int8_t *)addr;
00869
00870 if (fhpp != NULL)
00871 *fhpp = fhp;
00872 }
00873
00874
00875
00876
00877
00878 void
00879 unmap_file(addr, fhp)
00880 u_int8_t *addr;
00881 DB_FH *fhp;
00882 {
00883 int err;
00884
00885 if ((err = __os_unmapfile(dbenv, addr, len)) != 0) {
00886 fprintf(stderr, "munmap: %s\n", db_strerror(err));
00887 exit(EXIT_FAILURE);
00888 }
00889 if ((err = __os_closehandle(dbenv, fhp)) != 0) {
00890 fprintf(stderr, "close: %s\n", db_strerror(err));
00891 exit(EXIT_FAILURE);
00892 }
00893 }
00894
00895
00896
00897
00898
00899 int
00900 usage()
00901 {
00902 (void)fprintf(stderr, "%s\n\t%s\n",
00903 "usage: tm [-v] [-l maxlocks]",
00904 "[-n locks] [-p procs] [-T locker=ID|wakeup=ID] [-t threads]");
00905 return (EXIT_FAILURE);
00906 }
00907
00908
00909
00910
00911
00912 int
00913 os_wait(procs, nprocs)
00914 os_pid_t *procs;
00915 int nprocs;
00916 {
00917 int i, status;
00918 #if defined(DB_WIN32)
00919 DWORD ret;
00920 #endif
00921
00922 status = 0;
00923
00924 #if defined(DB_WIN32)
00925 do {
00926 ret = WaitForMultipleObjects(nprocs, procs, FALSE, INFINITE);
00927 i = ret - WAIT_OBJECT_0;
00928 if (i < 0 || i >= nprocs)
00929 return (__os_get_errno());
00930
00931 if ((GetExitCodeProcess(procs[i], &ret) == 0) || (ret != 0))
00932 return (ret);
00933
00934
00935 while (++i < nprocs)
00936 procs[i - 1] = procs[i];
00937 } while (--nprocs);
00938 #elif !defined(HAVE_VXWORKS)
00939 do {
00940 if ((i = wait(&status)) == -1)
00941 return (__os_get_errno());
00942
00943 if (WIFEXITED(status) == 0 || WEXITSTATUS(status) != 0) {
00944 for (i = 0; i < nprocs; i++)
00945 kill(procs[i], SIGKILL);
00946 return (WEXITSTATUS(status));
00947 }
00948 } while (--nprocs);
00949 #endif
00950
00951 return (0);
00952 }
00953
00954 os_pid_t
00955 spawn_proc(id, tmpath, typearg)
00956 u_long id;
00957 char *tmpath, *typearg;
00958 {
00959 char lbuf[16], nbuf[16], pbuf[16], tbuf[16], Tbuf[256];
00960 char *const vbuf = verbose ? "-v" : NULL;
00961 char *args[] = { NULL ,
00962 "-l", NULL , "-n", NULL ,
00963 "-p", NULL , "-t", NULL ,
00964 "-T", NULL , NULL ,
00965 NULL
00966 };
00967
00968 args[0] = tmpath;
00969 snprintf(lbuf, sizeof(lbuf), "%d", maxlocks);
00970 args[2] = lbuf;
00971 snprintf(nbuf, sizeof(nbuf), "%d", nlocks);
00972 args[4] = nbuf;
00973 snprintf(pbuf, sizeof(pbuf), "%d", nprocs);
00974 args[6] = pbuf;
00975 snprintf(tbuf, sizeof(tbuf), "%d", nthreads);
00976 args[8] = tbuf;
00977 snprintf(Tbuf, sizeof(Tbuf), "%s=%lu", typearg, id);
00978 args[10] = Tbuf;
00979 args[11] = vbuf;
00980
00981 return (os_spawn(tmpath, args));
00982 }
00983
00984 os_pid_t
00985 os_spawn(path, argv)
00986 const char *path;
00987 char *const argv[];
00988 {
00989 os_pid_t pid;
00990 int status;
00991
00992 COMPQUIET(pid, 0);
00993 COMPQUIET(status, 0);
00994
00995 #ifdef HAVE_VXWORKS
00996 fprintf(stderr, "ERROR: os_spawn not supported for VxWorks.\n");
00997 return (OS_BAD_PID);
00998 #elif defined(HAVE_QNX)
00999
01000
01001
01002
01003
01004
01005
01006
01007 return (spawnv(P_NOWAIT, path, argv));
01008 #elif defined(DB_WIN32)
01009 return (os_pid_t)(_spawnv(P_NOWAIT, path, argv));
01010 #else
01011 if ((pid = fork()) != 0) {
01012 if (pid == -1)
01013 return (OS_BAD_PID);
01014 return (pid);
01015 } else {
01016 execv(path, argv);
01017 exit(EXIT_FAILURE);
01018 }
01019 #endif
01020 }