tm.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:14k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*
  2.  * Standalone mutex tester for Berkeley DB mutexes.
  3.  */
  4. #include "db_config.h"
  5. #include <sys/types.h>
  6. #include <sys/mman.h>
  7. #include <sys/stat.h>
  8. #include <sys/wait.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <unistd.h>
  15. #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
  16. #include <pthread.h>
  17. #endif
  18. #include "db_int.h"
  19. void  exec_proc();
  20. void  tm_file_init();
  21. void  map_file();
  22. void  run_proc();
  23. void *run_thread();
  24. void *run_thread_wake();
  25. void  tm_mutex_destroy();
  26. void  tm_mutex_init();
  27. void  tm_mutex_stats();
  28. void  unmap_file();
  29. #define MUTEX_WAKEME 0x80 /* Wake-me flag. */
  30. DB_ENV  dbenv; /* Fake out DB. */
  31. size_t  len; /* Backing file size. */
  32. int  align; /* Mutex alignment in file. */
  33. int  quit; /* End-of-test flag. */
  34. char *file = "mutex.file"; /* Backing file. */
  35. int  maxlocks = 20; /* -l: Backing locks. */
  36. int  nlocks = 10000; /* -n: Locks per processes. */
  37. int  nprocs = 20; /* -p: Processes. */
  38. int  child; /* -s: Slave. */
  39. int  nthreads = 1; /* -t: Threads. */
  40. int  verbose; /* -v: Verbosity. */
  41. int
  42. main(argc, argv)
  43. int argc;
  44. char *argv[];
  45. {
  46. extern int optind;
  47. extern char *optarg;
  48. pid_t pid;
  49. int ch, eval, i, status;
  50. char *tmpath;
  51. tmpath = argv[0];
  52. while ((ch = getopt(argc, argv, "l:n:p:st:v")) != EOF)
  53. switch(ch) {
  54. case 'l':
  55. maxlocks = atoi(optarg);
  56. break;
  57. case 'n':
  58. nlocks = atoi(optarg);
  59. break;
  60. case 'p':
  61. nprocs = atoi(optarg);
  62. break;
  63. case 's':
  64. child = 1;
  65. break;
  66. case 't':
  67. nthreads = atoi(optarg);
  68. #if !defined(HAVE_MUTEX_PTHREADS) && !defined(BUILD_PTHREADS_ANYWAY)
  69. if (nthreads != 1) {
  70. (void)fprintf(stderr,
  71. "tm: pthreads not available or not compiled for this platform.n");
  72. return (EXIT_FAILURE);
  73. }
  74. #endif
  75. break;
  76. case 'v':
  77. verbose = 1;
  78. break;
  79. case '?':
  80. default:
  81. (void)fprintf(stderr,
  82.     "usage: tm [-v] [-l maxlocks] [-n locks] [-p procs] [-t threads]n");
  83. return (EXIT_FAILURE);
  84. }
  85. argc -= optind;
  86. argv += optind;
  87. /*
  88.  * The file layout:
  89.  * DB_MUTEX[1] per-thread mutex array lock
  90.  * DB_MUTEX[nthreads] per-thread mutex array
  91.  * DB_MUTEX[maxlocks] per-lock mutex array
  92.  * u_long[maxlocks][2] per-lock ID array
  93.  */
  94. align = ALIGN(sizeof(DB_MUTEX) * 2, MUTEX_ALIGN);
  95. len =
  96.     align * (1 + nthreads +  maxlocks) + sizeof(u_long) * maxlocks * 2;
  97. printf(
  98.     "mutex alignment %d, structure alignment %d, backing file %lu bytesn",
  99.     MUTEX_ALIGN, align, (u_long)len);
  100. if (child) {
  101. run_proc();
  102. return (EXIT_SUCCESS);
  103. }
  104. tm_file_init();
  105. tm_mutex_init();
  106. printf(
  107.     "%d proc, %d threads/proc, %d lock requests from %d locks:n",
  108.     nprocs, nthreads, nlocks, maxlocks);
  109. for (i = 0; i < nprocs; ++i)
  110. switch (fork()) {
  111. case -1:
  112. perror("fork");
  113. return (EXIT_FAILURE);
  114. case 0:
  115. exec_proc(tmpath);
  116. break;
  117. default:
  118. break;
  119. }
  120. eval = EXIT_SUCCESS;
  121. while ((pid = wait(&status)) != (pid_t)-1) {
  122. fprintf(stderr,
  123.     "%lu: exited %dn", (u_long)pid, WEXITSTATUS(status));
  124. if (WEXITSTATUS(status) != 0)
  125. eval = EXIT_FAILURE;
  126. }
  127. tm_mutex_stats();
  128. tm_mutex_destroy();
  129. printf("tm: exit status: %sn",
  130.     eval == EXIT_SUCCESS ? "success" : "failed!");
  131. return (eval);
  132. }
  133. void
  134. exec_proc(tmpath)
  135. char *tmpath;
  136. {
  137. char *argv[10], **ap, b_l[10], b_n[10], b_t[10];
  138. ap = &argv[0];
  139. *ap++ = "tm";
  140. sprintf(b_l, "-l%d", maxlocks);
  141. *ap++ = b_l;
  142. sprintf(b_n, "-n%d", nlocks);
  143. *ap++ = b_n;
  144. *ap++ = "-s";
  145. sprintf(b_t, "-t%d", nthreads);
  146. *ap++ = b_t;
  147. if (verbose)
  148. *ap++ = "-v";
  149. *ap = NULL;
  150. execvp(tmpath, argv);
  151. fprintf(stderr, "%s: %sn", tmpath, strerror(errno));
  152. exit(EXIT_FAILURE);
  153. }
  154. void
  155. run_proc()
  156. {
  157. #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
  158. pthread_t *kidsp, wakep;
  159. int i, status;
  160. void *retp;
  161. #endif
  162. __os_sleep(&dbenv, 3, 0); /* Let everyone catch up. */
  163. srand((u_int)time(NULL) / getpid()); /* Initialize random numbers. */
  164. if (nthreads == 1) /* Simple case. */
  165. exit((int)run_thread((void *)0));
  166. #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
  167. /*
  168.  * Spawn off threads.  We have nthreads all locking and going to
  169.  * sleep, and one other thread cycling through and waking them up.
  170.  */
  171. if ((kidsp =
  172.     (pthread_t *)calloc(sizeof(pthread_t), nthreads)) == NULL) {
  173. fprintf(stderr, "tm: %sn", strerror(errno));
  174. exit(EXIT_FAILURE);
  175. }
  176. for (i = 0; i < nthreads; i++)
  177. if ((errno = pthread_create(
  178.     &kidsp[i], NULL, run_thread, (void *)i)) != 0) {
  179. fprintf(stderr, "tm: failed spawning thread %d: %sn",
  180.     i, strerror(errno));
  181. exit(EXIT_FAILURE);
  182. }
  183. if ((errno = pthread_create(
  184.     &wakep, NULL, run_thread_wake, (void *)0)) != 0) {
  185. fprintf(stderr, "tm: failed spawning wakeup thread: %sn",
  186.     strerror(errno));
  187. exit(EXIT_FAILURE);
  188. }
  189. /* Wait for the threads to exit. */
  190. status = 0;
  191. for (i = 0; i < nthreads; i++) {
  192. pthread_join(kidsp[i], &retp);
  193. if (retp != NULL) {
  194. fprintf(stderr,
  195.     "tm: thread %d exited with errorn", i);
  196. status = EXIT_FAILURE;
  197. }
  198. }
  199. free(kidsp);
  200. /* Signal wakeup thread to stop. */
  201. quit = 1;
  202. pthread_join(wakep, &retp);
  203. if (retp != NULL) {
  204. fprintf(stderr, "tm: wakeup thread exited with errorn");
  205. status = EXIT_FAILURE;
  206. }
  207. exit(status);
  208. #endif
  209. }
  210. void *
  211. run_thread(arg)
  212. void *arg;
  213. {
  214. DB_MUTEX *gm_addr, *lm_addr, *tm_addr, *mp;
  215. u_long gid1, gid2, *id_addr;
  216. int fd, i, lock, id, nl, remap;
  217. /* Set local and global per-thread ID. */
  218. id = (int)arg;
  219. gid1 = (u_long)getpid();
  220. #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
  221. gid2 = (u_long)pthread_self();
  222. #else
  223. gid2 = 0;
  224. #endif
  225. printf("tPID: %lu; TID: %lx; ID: %dn", gid1, gid2, id);
  226. nl = nlocks;
  227. for (gm_addr = NULL, remap = 0;;) {
  228. /* Map in the file as necessary. */
  229. if (gm_addr == NULL) {
  230. map_file(&gm_addr, &tm_addr, &lm_addr, &id_addr, &fd);
  231. remap = (rand() % 100) + 35;
  232. }
  233. /* Select and acquire a data lock. */
  234. lock = rand() % maxlocks;
  235. mp = (DB_MUTEX *)((u_int8_t *)lm_addr + lock * align);
  236. if (verbose)
  237. printf("%lu/%lx: %03dn", gid1, gid2, lock);
  238. if (__db_mutex_lock(&dbenv, mp)) {
  239. fprintf(stderr,
  240.     "%lu/%lx: never got lockn", gid1, gid2);
  241. return ((void *)EXIT_FAILURE);
  242. }
  243. if (id_addr[lock * 2] != 0) {
  244. fprintf(stderr,
  245.     "RACE! (%lu/%lx granted lock %d held by %lu/%lx)n",
  246.     gid1, gid2,
  247.     lock, id_addr[lock * 2], id_addr[lock * 2 + 1]);
  248. return ((void *)EXIT_FAILURE);
  249. }
  250. id_addr[lock * 2] = gid1;
  251. id_addr[lock * 2 + 1] = gid2;
  252. /*
  253.  * Pretend to do some work, periodically checking to see if
  254.  * we still hold the mutex.
  255.  */
  256. for (i = 0; i < 3; ++i) {
  257. __os_sleep(&dbenv, 0, rand() % 3);
  258. if (id_addr[lock * 2] != gid1 ||
  259.     id_addr[lock * 2 + 1] != gid2) {
  260. fprintf(stderr,
  261.     "RACE! (%lu/%lx stole lock %d from %lu/%lx)n",
  262.     id_addr[lock * 2],
  263.     id_addr[lock * 2 + 1], lock, gid1, gid2);
  264. return ((void *)EXIT_FAILURE);
  265. }
  266. }
  267. #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
  268. /*
  269.  * Test self-blocking and unlocking by other threads/processes:
  270.  *
  271.  * acquire the global lock
  272.  * set our wakeup flag
  273.  * release the global lock
  274.  * acquire our per-thread lock
  275.  *
  276.  * The wakeup thread will wake us up.
  277.  */
  278. if (__db_mutex_lock(&dbenv, gm_addr)) {
  279. fprintf(stderr, "%lu/%lx: global lockn", gid1, gid2);
  280. return ((void *)EXIT_FAILURE);
  281. }
  282. mp = (DB_MUTEX *)((u_int8_t *)tm_addr + id * align);
  283. F_SET(mp, MUTEX_WAKEME);
  284. if (__db_mutex_unlock(&dbenv, gm_addr)) {
  285. fprintf(stderr,
  286.     "%lu/%lx: per-thread wakeup failedn", gid1, gid2);
  287. return ((void *)EXIT_FAILURE);
  288. }
  289. if (__db_mutex_lock(&dbenv, mp)) {
  290. fprintf(stderr,
  291.     "%lu/%lx: per-thread lockn", gid1, gid2);
  292. return ((void *)EXIT_FAILURE);
  293. }
  294. /* Time passes... */
  295. if (F_ISSET(mp, MUTEX_WAKEME)) {
  296. fprintf(stderr, "%lu/%lx: %03d wakeup flag still setn",
  297.     gid1, gid2, id);
  298. return ((void *)EXIT_FAILURE);
  299. }
  300. #endif
  301. /* Release the data lock. */
  302. id_addr[lock * 2] = id_addr[lock * 2 + 1] = 0;
  303. mp = (DB_MUTEX *)((u_int8_t *)lm_addr + lock * align);
  304. if (__db_mutex_unlock(&dbenv, mp)) {
  305. fprintf(stderr, "%lu/%lx: wakeup failedn", gid1, gid2);
  306. return ((void *)EXIT_FAILURE);
  307. }
  308. if (--nl % 100 == 0)
  309. fprintf(stderr, "%lu/%lx: %dn", gid1, gid2, nl);
  310. if (nl == 0 || --remap == 0) {
  311. unmap_file((void *)gm_addr, fd);
  312. gm_addr = NULL;
  313. if (nl == 0)
  314. break;
  315. __os_sleep(&dbenv, rand() % 3, 0);
  316. }
  317. }
  318. return (NULL);
  319. }
  320. #if defined(HAVE_MUTEX_PTHREADS) || defined(BUILD_PTHREADS_ANYWAY)
  321. /*
  322.  * run_thread_wake --
  323.  * Thread to wake up other threads that are sleeping.
  324.  */
  325. void *
  326. run_thread_wake(arg)
  327. void *arg;
  328. {
  329. DB_MUTEX *gm_addr, *tm_addr, *mp;
  330. int fd, id;
  331. arg = NULL;
  332. map_file(&gm_addr, &tm_addr, NULL, NULL, &fd);
  333. /* Loop, waking up sleepers and periodically sleeping ourselves. */
  334. while (!quit) {
  335. id = 0;
  336. /* Acquire the global lock. */
  337. retry: if (__db_mutex_lock(&dbenv, gm_addr)) {
  338. fprintf(stderr, "wt: global lock failedn");
  339. return ((void *)EXIT_FAILURE);
  340. }
  341. next: mp = (DB_MUTEX *)((u_int8_t *)tm_addr + id * align);
  342. if (F_ISSET(mp, MUTEX_WAKEME)) {
  343. F_CLR(mp, MUTEX_WAKEME);
  344. if (__db_mutex_unlock(&dbenv, mp)) {
  345. fprintf(stderr, "wt: wakeup failedn");
  346. return ((void *)EXIT_FAILURE);
  347. }
  348. }
  349. if (++id < nthreads && id % 3 != 0)
  350. goto next;
  351. if (__db_mutex_unlock(&dbenv, gm_addr)) {
  352. fprintf(stderr, "wt: global unlock failedn");
  353. return ((void *)EXIT_FAILURE);
  354. }
  355. __os_sleep(&dbenv, 0, 500);
  356. if (id < nthreads)
  357. goto retry;
  358. }
  359. return (NULL);
  360. }
  361. #endif
  362. /*
  363.  * tm_file_init --
  364.  * Initialize the backing file.
  365.  */
  366. void
  367. tm_file_init()
  368. {
  369. int fd;
  370. /* Initialize the backing file. */
  371. printf("Create the backing file...n");
  372. #ifdef HAVE_QNX
  373. (void)shm_unlink(file);
  374. if ((fd = shm_open(file, O_CREAT | O_RDWR | O_TRUNC,
  375. #else
  376. (void)remove(file);
  377. if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC,
  378. #endif
  379.     S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) == -1) {
  380. (void)fprintf(stderr, "%s: open: %sn", file, strerror(errno));
  381. exit(EXIT_FAILURE);
  382. }
  383. if (lseek(fd, (off_t)len, SEEK_SET) != len || write(fd, &fd, 1) != 1) {
  384. (void)fprintf(stderr,
  385.     "%s: seek/write: %sn", file, strerror(errno));
  386. exit(EXIT_FAILURE);
  387. }
  388. (void)close(fd);
  389. }
  390. /*
  391.  * tm_mutex_init --
  392.  * Initialize the mutexes.
  393.  */
  394. void
  395. tm_mutex_init()
  396. {
  397. DB_MUTEX *gm_addr, *lm_addr, *mp, *tm_addr;
  398. int fd, i;
  399. map_file(&gm_addr, &tm_addr, &lm_addr, NULL, &fd);
  400. printf("Initialize the global mutex...n");
  401. if (__db_mutex_init_int(&dbenv, gm_addr, 0, 0)) {
  402. fprintf(stderr,
  403.     "__db_mutex_init (global): %sn", strerror(errno));
  404. exit(EXIT_FAILURE);
  405. }
  406. printf("Initialize the per-thread mutexes...n");
  407. for (i = 1, mp = tm_addr;
  408.     i <= nthreads; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align)) {
  409. if (__db_mutex_init_int(&dbenv, mp, 0, MUTEX_SELF_BLOCK)) {
  410. fprintf(stderr, "__db_mutex_init (per-thread %d): %sn",
  411.     i, strerror(errno));
  412. exit(EXIT_FAILURE);
  413. }
  414. if (__db_mutex_lock(&dbenv, mp)) {
  415. fprintf(stderr,
  416.     "__db_mutex_init (per-thread %d) lock: %sn",
  417.     i, strerror(errno));
  418. exit(EXIT_FAILURE);
  419. }
  420. }
  421. printf("Initialize the per-lock mutexes...n");
  422. for (i = 1, mp = lm_addr;
  423.     i <= maxlocks; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align))
  424. if (__db_mutex_init_int(&dbenv, mp, 0, 0)) {
  425. fprintf(stderr, "__db_mutex_init (per-lock: %d): %sn",
  426.     i, strerror(errno));
  427. exit(EXIT_FAILURE);
  428. }
  429. unmap_file((void *)gm_addr, fd);
  430. }
  431. /*
  432.  * tm_mutex_destroy --
  433.  * Destroy the mutexes.
  434.  */
  435. void
  436. tm_mutex_destroy()
  437. {
  438. DB_MUTEX *gm_addr, *lm_addr, *mp, *tm_addr;
  439. int fd, i;
  440. map_file(&gm_addr, &tm_addr, &lm_addr, NULL, &fd);
  441. printf("Destroy the global mutex...n");
  442. if (__db_mutex_destroy(gm_addr)) {
  443. fprintf(stderr,
  444.     "__db_mutex_destroy (global): %sn", strerror(errno));
  445. exit(EXIT_FAILURE);
  446. }
  447. printf("Destroy the per-thread mutexes...n");
  448. for (i = 1, mp = tm_addr;
  449.     i <= nthreads; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align)) {
  450. if (__db_mutex_destroy(mp)) {
  451. fprintf(stderr,
  452.     "__db_mutex_destroy (per-thread %d): %sn",
  453.     i, strerror(errno));
  454. exit(EXIT_FAILURE);
  455. }
  456. }
  457. printf("Destroy the per-lock mutexes...n");
  458. for (i = 1, mp = lm_addr;
  459.     i <= maxlocks; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align))
  460. if (__db_mutex_destroy(mp)) {
  461. fprintf(stderr,
  462.     "__db_mutex_destroy (per-lock: %d): %sn",
  463.     i, strerror(errno));
  464. exit(EXIT_FAILURE);
  465. }
  466. unmap_file((void *)gm_addr, fd);
  467. #ifdef HAVE_QNX
  468. (void)shm_unlink(file);
  469. #endif
  470. }
  471. /*
  472.  * tm_mutex_stats --
  473.  * Display mutex statistics.
  474.  */
  475. void
  476. tm_mutex_stats()
  477. {
  478. DB_MUTEX *gm_addr, *lm_addr, *mp;
  479. int fd, i;
  480. map_file(&gm_addr, NULL, &lm_addr, NULL, &fd);
  481. printf("Per-lock mutex statistics...n");
  482. for (i = 1, mp = lm_addr;
  483.     i <= maxlocks; ++i, mp = (DB_MUTEX *)((u_int8_t *)mp + align))
  484. printf("mutex %2d: wait: %lu; no wait %lun", i,
  485.     (u_long)mp->mutex_set_wait, (u_long)mp->mutex_set_nowait);
  486. unmap_file((void *)gm_addr, fd);
  487. }
  488. /*
  489.  * map_file --
  490.  * Map in the backing file.
  491.  */
  492. void
  493. map_file(gm_addrp, tm_addrp, lm_addrp, id_addrp, fdp)
  494. DB_MUTEX **gm_addrp, **tm_addrp, **lm_addrp;
  495. u_long **id_addrp;
  496. int *fdp;
  497. {
  498. void *maddr;
  499. int fd;
  500. #ifndef MAP_FAILED
  501. #define MAP_FAILED (void *)-1
  502. #endif
  503. #ifndef MAP_FILE
  504. #define MAP_FILE 0
  505. #endif
  506. #ifdef HAVE_QNX
  507. if ((fd = shm_open(file, O_RDWR, 0)) == -1) {
  508. #else
  509. if ((fd = open(file, O_RDWR, 0)) == -1) {
  510. #endif
  511. fprintf(stderr, "%s: open %sn", file, strerror(errno));
  512. exit(EXIT_FAILURE);
  513. }
  514. maddr = mmap(NULL, len,
  515.     PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, (off_t)0);
  516. if (maddr == MAP_FAILED) {
  517. fprintf(stderr, "%s: mmap: %sn", file, strerror(errno));
  518. exit(EXIT_FAILURE);
  519. }
  520. if (gm_addrp != NULL)
  521. *gm_addrp = (DB_MUTEX *)maddr;
  522. maddr = (u_int8_t *)maddr + align;
  523. if (tm_addrp != NULL)
  524. *tm_addrp = (DB_MUTEX *)maddr;
  525. maddr = (u_int8_t *)maddr + align * nthreads;
  526. if (lm_addrp != NULL)
  527. *lm_addrp = (DB_MUTEX *)maddr;
  528. maddr = (u_int8_t *)maddr + align * maxlocks;
  529. if (id_addrp != NULL)
  530. *id_addrp = (u_long *)maddr;
  531. if (fdp != NULL)
  532. *fdp = fd;
  533. }
  534. /*
  535.  * unmap_file --
  536.  * Discard backing file map.
  537.  */
  538. void
  539. unmap_file(maddr, fd)
  540. void *maddr;
  541. int fd;
  542. {
  543. if (munmap(maddr, len) != 0) {
  544. fprintf(stderr, "munmap: %sn", strerror(errno));
  545. exit(EXIT_FAILURE);
  546. }
  547. if (close(fd) != 0) {
  548. fprintf(stderr, "close: %sn", strerror(errno));
  549. exit(EXIT_FAILURE);
  550. }
  551. }