tlbie_test.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright 2019, Nick Piggin, Gautham R. Shenoy, Aneesh Kumar K.V, IBM Corp.
  4. */
  5. /*
  6. *
  7. * Test tlbie/mtpidr race. We have 4 threads doing flush/load/compare/store
  8. * sequence in a loop. The same threads also rung a context switch task
  9. * that does sched_yield() in loop.
  10. *
  11. * The snapshot thread mark the mmap area PROT_READ in between, make a copy
  12. * and copy it back to the original area. This helps us to detect if any
  13. * store continued to happen after we marked the memory PROT_READ.
  14. */
  15. #define _GNU_SOURCE
  16. #include <stdio.h>
  17. #include <sys/mman.h>
  18. #include <sys/types.h>
  19. #include <sys/wait.h>
  20. #include <sys/ipc.h>
  21. #include <sys/shm.h>
  22. #include <sys/stat.h>
  23. #include <sys/time.h>
  24. #include <linux/futex.h>
  25. #include <unistd.h>
  26. #include <asm/unistd.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <fcntl.h>
  30. #include <sched.h>
  31. #include <time.h>
  32. #include <stdarg.h>
  33. #include <sched.h>
  34. #include <pthread.h>
  35. #include <signal.h>
  36. #include <sys/prctl.h>
  37. static inline void dcbf(volatile unsigned int *addr)
  38. {
  39. __asm__ __volatile__ ("dcbf %y0; sync" : : "Z"(*(unsigned char *)addr) : "memory");
  40. }
  41. static void err_msg(char *msg)
  42. {
  43. time_t now;
  44. time(&now);
  45. printf("=================================\n");
  46. printf(" Error: %s\n", msg);
  47. printf(" %s", ctime(&now));
  48. printf("=================================\n");
  49. exit(1);
  50. }
  51. static char *map1;
  52. static char *map2;
  53. static pid_t rim_process_pid;
  54. /*
  55. * A "rim-sequence" is defined to be the sequence of the following
  56. * operations performed on a memory word:
  57. * 1) FLUSH the contents of that word.
  58. * 2) LOAD the contents of that word.
  59. * 3) COMPARE the contents of that word with the content that was
  60. * previously stored at that word
  61. * 4) STORE new content into that word.
  62. *
  63. * The threads in this test that perform the rim-sequence are termed
  64. * as rim_threads.
  65. */
  66. /*
  67. * A "corruption" is defined to be the failed COMPARE operation in a
  68. * rim-sequence.
  69. *
  70. * A rim_thread that detects a corruption informs about it to all the
  71. * other rim_threads, and the mem_snapshot thread.
  72. */
  73. static volatile unsigned int corruption_found;
  74. /*
  75. * This defines the maximum number of rim_threads in this test.
  76. *
  77. * The THREAD_ID_BITS denote the number of bits required
  78. * to represent the thread_ids [0..MAX_THREADS - 1].
  79. * We are being a bit paranoid here and set it to 8 bits,
  80. * though 6 bits suffice.
  81. *
  82. */
  83. #define MAX_THREADS 64
  84. #define THREAD_ID_BITS 8
  85. #define THREAD_ID_MASK ((1 << THREAD_ID_BITS) - 1)
  86. static unsigned int rim_thread_ids[MAX_THREADS];
  87. static pthread_t rim_threads[MAX_THREADS];
  88. /*
  89. * Each rim_thread works on an exclusive "chunk" of size
  90. * RIM_CHUNK_SIZE.
  91. *
  92. * The ith rim_thread works on the ith chunk.
  93. *
  94. * The ith chunk begins at
  95. * map1 + (i * RIM_CHUNK_SIZE)
  96. */
  97. #define RIM_CHUNK_SIZE 1024
  98. #define BITS_PER_BYTE 8
  99. #define WORD_SIZE (sizeof(unsigned int))
  100. #define WORD_BITS (WORD_SIZE * BITS_PER_BYTE)
  101. #define WORDS_PER_CHUNK (RIM_CHUNK_SIZE/WORD_SIZE)
  102. static inline char *compute_chunk_start_addr(unsigned int thread_id)
  103. {
  104. char *chunk_start;
  105. chunk_start = (char *)((unsigned long)map1 +
  106. (thread_id * RIM_CHUNK_SIZE));
  107. return chunk_start;
  108. }
  109. /*
  110. * The "word-offset" of a word-aligned address inside a chunk, is
  111. * defined to be the number of words that precede the address in that
  112. * chunk.
  113. *
  114. * WORD_OFFSET_BITS denote the number of bits required to represent
  115. * the word-offsets of all the word-aligned addresses of a chunk.
  116. */
  117. #define WORD_OFFSET_BITS (__builtin_ctz(WORDS_PER_CHUNK))
  118. #define WORD_OFFSET_MASK ((1 << WORD_OFFSET_BITS) - 1)
  119. static inline unsigned int compute_word_offset(char *start, unsigned int *addr)
  120. {
  121. unsigned int delta_bytes, ret;
  122. delta_bytes = (unsigned long)addr - (unsigned long)start;
  123. ret = delta_bytes/WORD_SIZE;
  124. return ret;
  125. }
  126. /*
  127. * A "sweep" is defined to be the sequential execution of the
  128. * rim-sequence by a rim_thread on its chunk one word at a time,
  129. * starting from the first word of its chunk and ending with the last
  130. * word of its chunk.
  131. *
  132. * Each sweep of a rim_thread is uniquely identified by a sweep_id.
  133. * SWEEP_ID_BITS denote the number of bits required to represent
  134. * the sweep_ids of rim_threads.
  135. *
  136. * As to why SWEEP_ID_BITS are computed as a function of THREAD_ID_BITS,
  137. * WORD_OFFSET_BITS, and WORD_BITS, see the "store-pattern" below.
  138. */
  139. #define SWEEP_ID_BITS (WORD_BITS - (THREAD_ID_BITS + WORD_OFFSET_BITS))
  140. #define SWEEP_ID_MASK ((1 << SWEEP_ID_BITS) - 1)
  141. /*
  142. * A "store-pattern" is the word-pattern that is stored into a word
  143. * location in the 4)STORE step of the rim-sequence.
  144. *
  145. * In the store-pattern, we shall encode:
  146. *
  147. * - The thread-id of the rim_thread performing the store
  148. * (The most significant THREAD_ID_BITS)
  149. *
  150. * - The word-offset of the address into which the store is being
  151. * performed (The next WORD_OFFSET_BITS)
  152. *
  153. * - The sweep_id of the current sweep in which the store is
  154. * being performed. (The lower SWEEP_ID_BITS)
  155. *
  156. * Store Pattern: 32 bits
  157. * |------------------|--------------------|---------------------------------|
  158. * | Thread id | Word offset | sweep_id |
  159. * |------------------|--------------------|---------------------------------|
  160. * THREAD_ID_BITS WORD_OFFSET_BITS SWEEP_ID_BITS
  161. *
  162. * In the store pattern, the (Thread-id + Word-offset) uniquely identify the
  163. * address to which the store is being performed i.e,
  164. * address == map1 +
  165. * (Thread-id * RIM_CHUNK_SIZE) + (Word-offset * WORD_SIZE)
  166. *
  167. * And the sweep_id in the store pattern identifies the time when the
  168. * store was performed by the rim_thread.
  169. *
  170. * We shall use this property in the 3)COMPARE step of the
  171. * rim-sequence.
  172. */
  173. #define SWEEP_ID_SHIFT 0
  174. #define WORD_OFFSET_SHIFT (SWEEP_ID_BITS)
  175. #define THREAD_ID_SHIFT (WORD_OFFSET_BITS + SWEEP_ID_BITS)
  176. /*
  177. * Compute the store pattern for a given thread with id @tid, at
  178. * location @addr in the sweep identified by @sweep_id
  179. */
  180. static inline unsigned int compute_store_pattern(unsigned int tid,
  181. unsigned int *addr,
  182. unsigned int sweep_id)
  183. {
  184. unsigned int ret = 0;
  185. char *start = compute_chunk_start_addr(tid);
  186. unsigned int word_offset = compute_word_offset(start, addr);
  187. ret += (tid & THREAD_ID_MASK) << THREAD_ID_SHIFT;
  188. ret += (word_offset & WORD_OFFSET_MASK) << WORD_OFFSET_SHIFT;
  189. ret += (sweep_id & SWEEP_ID_MASK) << SWEEP_ID_SHIFT;
  190. return ret;
  191. }
  192. /* Extract the thread-id from the given store-pattern */
  193. static inline unsigned int extract_tid(unsigned int pattern)
  194. {
  195. unsigned int ret;
  196. ret = (pattern >> THREAD_ID_SHIFT) & THREAD_ID_MASK;
  197. return ret;
  198. }
  199. /* Extract the word-offset from the given store-pattern */
  200. static inline unsigned int extract_word_offset(unsigned int pattern)
  201. {
  202. unsigned int ret;
  203. ret = (pattern >> WORD_OFFSET_SHIFT) & WORD_OFFSET_MASK;
  204. return ret;
  205. }
  206. /* Extract the sweep-id from the given store-pattern */
  207. static inline unsigned int extract_sweep_id(unsigned int pattern)
  208. {
  209. unsigned int ret;
  210. ret = (pattern >> SWEEP_ID_SHIFT) & SWEEP_ID_MASK;
  211. return ret;
  212. }
  213. /************************************************************
  214. * *
  215. * Logging the output of the verification *
  216. * *
  217. ************************************************************/
  218. #define LOGDIR_NAME_SIZE 100
  219. static char logdir[LOGDIR_NAME_SIZE];
  220. static FILE *fp[MAX_THREADS];
  221. static const char logfilename[] ="Thread-%02d-Chunk";
  222. static inline void start_verification_log(unsigned int tid,
  223. unsigned int *addr,
  224. unsigned int cur_sweep_id,
  225. unsigned int prev_sweep_id)
  226. {
  227. FILE *f;
  228. char logfile[30];
  229. char path[LOGDIR_NAME_SIZE + 30];
  230. char separator[2] = "/";
  231. char *chunk_start = compute_chunk_start_addr(tid);
  232. unsigned int size = RIM_CHUNK_SIZE;
  233. sprintf(logfile, logfilename, tid);
  234. strcpy(path, logdir);
  235. strcat(path, separator);
  236. strcat(path, logfile);
  237. f = fopen(path, "w");
  238. if (!f) {
  239. err_msg("Unable to create logfile\n");
  240. }
  241. fp[tid] = f;
  242. fprintf(f, "----------------------------------------------------------\n");
  243. fprintf(f, "PID = %d\n", rim_process_pid);
  244. fprintf(f, "Thread id = %02d\n", tid);
  245. fprintf(f, "Chunk Start Addr = 0x%016lx\n", (unsigned long)chunk_start);
  246. fprintf(f, "Chunk Size = %d\n", size);
  247. fprintf(f, "Next Store Addr = 0x%016lx\n", (unsigned long)addr);
  248. fprintf(f, "Current sweep-id = 0x%08x\n", cur_sweep_id);
  249. fprintf(f, "Previous sweep-id = 0x%08x\n", prev_sweep_id);
  250. fprintf(f, "----------------------------------------------------------\n");
  251. }
  252. static inline void log_anamoly(unsigned int tid, unsigned int *addr,
  253. unsigned int expected, unsigned int observed)
  254. {
  255. FILE *f = fp[tid];
  256. fprintf(f, "Thread %02d: Addr 0x%lx: Expected 0x%x, Observed 0x%x\n",
  257. tid, (unsigned long)addr, expected, observed);
  258. fprintf(f, "Thread %02d: Expected Thread id = %02d\n", tid, extract_tid(expected));
  259. fprintf(f, "Thread %02d: Observed Thread id = %02d\n", tid, extract_tid(observed));
  260. fprintf(f, "Thread %02d: Expected Word offset = %03d\n", tid, extract_word_offset(expected));
  261. fprintf(f, "Thread %02d: Observed Word offset = %03d\n", tid, extract_word_offset(observed));
  262. fprintf(f, "Thread %02d: Expected sweep-id = 0x%x\n", tid, extract_sweep_id(expected));
  263. fprintf(f, "Thread %02d: Observed sweep-id = 0x%x\n", tid, extract_sweep_id(observed));
  264. fprintf(f, "----------------------------------------------------------\n");
  265. }
  266. static inline void end_verification_log(unsigned int tid, unsigned nr_anamolies)
  267. {
  268. FILE *f = fp[tid];
  269. char logfile[30];
  270. char path[LOGDIR_NAME_SIZE + 30];
  271. char separator[] = "/";
  272. fclose(f);
  273. if (nr_anamolies == 0) {
  274. remove(path);
  275. return;
  276. }
  277. sprintf(logfile, logfilename, tid);
  278. strcpy(path, logdir);
  279. strcat(path, separator);
  280. strcat(path, logfile);
  281. printf("Thread %02d chunk has %d corrupted words. For details check %s\n",
  282. tid, nr_anamolies, path);
  283. }
  284. /*
  285. * When a COMPARE step of a rim-sequence fails, the rim_thread informs
  286. * everyone else via the shared_memory pointed to by
  287. * corruption_found variable. On seeing this, every thread verifies the
  288. * content of its chunk as follows.
  289. *
  290. * Suppose a thread identified with @tid was about to store (but not
  291. * yet stored) to @next_store_addr in its current sweep identified
  292. * @cur_sweep_id. Let @prev_sweep_id indicate the previous sweep_id.
  293. *
  294. * This implies that for all the addresses @addr < @next_store_addr,
  295. * Thread @tid has already performed a store as part of its current
  296. * sweep. Hence we expect the content of such @addr to be:
  297. * |-------------------------------------------------|
  298. * | tid | word_offset(addr) | cur_sweep_id |
  299. * |-------------------------------------------------|
  300. *
  301. * Since Thread @tid is yet to perform stores on address
  302. * @next_store_addr and above, we expect the content of such an
  303. * address @addr to be:
  304. * |-------------------------------------------------|
  305. * | tid | word_offset(addr) | prev_sweep_id |
  306. * |-------------------------------------------------|
  307. *
  308. * The verifier function @verify_chunk does this verification and logs
  309. * any anamolies that it finds.
  310. */
  311. static void verify_chunk(unsigned int tid, unsigned int *next_store_addr,
  312. unsigned int cur_sweep_id,
  313. unsigned int prev_sweep_id)
  314. {
  315. unsigned int *iter_ptr;
  316. unsigned int size = RIM_CHUNK_SIZE;
  317. unsigned int expected;
  318. unsigned int observed;
  319. char *chunk_start = compute_chunk_start_addr(tid);
  320. int nr_anamolies = 0;
  321. start_verification_log(tid, next_store_addr,
  322. cur_sweep_id, prev_sweep_id);
  323. for (iter_ptr = (unsigned int *)chunk_start;
  324. (unsigned long)iter_ptr < (unsigned long)chunk_start + size;
  325. iter_ptr++) {
  326. unsigned int expected_sweep_id;
  327. if (iter_ptr < next_store_addr) {
  328. expected_sweep_id = cur_sweep_id;
  329. } else {
  330. expected_sweep_id = prev_sweep_id;
  331. }
  332. expected = compute_store_pattern(tid, iter_ptr, expected_sweep_id);
  333. dcbf((volatile unsigned int*)iter_ptr); //Flush before reading
  334. observed = *iter_ptr;
  335. if (observed != expected) {
  336. nr_anamolies++;
  337. log_anamoly(tid, iter_ptr, expected, observed);
  338. }
  339. }
  340. end_verification_log(tid, nr_anamolies);
  341. }
  342. static void set_pthread_cpu(pthread_t th, int cpu)
  343. {
  344. cpu_set_t run_cpu_mask;
  345. struct sched_param param;
  346. CPU_ZERO(&run_cpu_mask);
  347. CPU_SET(cpu, &run_cpu_mask);
  348. pthread_setaffinity_np(th, sizeof(cpu_set_t), &run_cpu_mask);
  349. param.sched_priority = 1;
  350. if (0 && sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
  351. /* haven't reproduced with this setting, it kills random preemption which may be a factor */
  352. fprintf(stderr, "could not set SCHED_FIFO, run as root?\n");
  353. }
  354. }
  355. static void set_mycpu(int cpu)
  356. {
  357. cpu_set_t run_cpu_mask;
  358. struct sched_param param;
  359. CPU_ZERO(&run_cpu_mask);
  360. CPU_SET(cpu, &run_cpu_mask);
  361. sched_setaffinity(0, sizeof(cpu_set_t), &run_cpu_mask);
  362. param.sched_priority = 1;
  363. if (0 && sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
  364. fprintf(stderr, "could not set SCHED_FIFO, run as root?\n");
  365. }
  366. }
  367. static volatile int segv_wait;
  368. static void segv_handler(int signo, siginfo_t *info, void *extra)
  369. {
  370. while (segv_wait) {
  371. sched_yield();
  372. }
  373. }
  374. static void set_segv_handler(void)
  375. {
  376. struct sigaction sa;
  377. sa.sa_flags = SA_SIGINFO;
  378. sa.sa_sigaction = segv_handler;
  379. if (sigaction(SIGSEGV, &sa, NULL) == -1) {
  380. perror("sigaction");
  381. exit(EXIT_FAILURE);
  382. }
  383. }
  384. int timeout = 0;
  385. /*
  386. * This function is executed by every rim_thread.
  387. *
  388. * This function performs sweeps over the exclusive chunks of the
  389. * rim_threads executing the rim-sequence one word at a time.
  390. */
  391. static void *rim_fn(void *arg)
  392. {
  393. unsigned int tid = *((unsigned int *)arg);
  394. int size = RIM_CHUNK_SIZE;
  395. char *chunk_start = compute_chunk_start_addr(tid);
  396. unsigned int prev_sweep_id;
  397. unsigned int cur_sweep_id = 0;
  398. /* word access */
  399. unsigned int pattern = cur_sweep_id;
  400. unsigned int *pattern_ptr = &pattern;
  401. unsigned int *w_ptr, read_data;
  402. set_segv_handler();
  403. /*
  404. * Let us initialize the chunk:
  405. *
  406. * Each word-aligned address addr in the chunk,
  407. * is initialized to :
  408. * |-------------------------------------------------|
  409. * | tid | word_offset(addr) | 0 |
  410. * |-------------------------------------------------|
  411. */
  412. for (w_ptr = (unsigned int *)chunk_start;
  413. (unsigned long)w_ptr < (unsigned long)(chunk_start) + size;
  414. w_ptr++) {
  415. *pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id);
  416. *w_ptr = *pattern_ptr;
  417. }
  418. while (!corruption_found && !timeout) {
  419. prev_sweep_id = cur_sweep_id;
  420. cur_sweep_id = cur_sweep_id + 1;
  421. for (w_ptr = (unsigned int *)chunk_start;
  422. (unsigned long)w_ptr < (unsigned long)(chunk_start) + size;
  423. w_ptr++) {
  424. unsigned int old_pattern;
  425. /*
  426. * Compute the pattern that we would have
  427. * stored at this location in the previous
  428. * sweep.
  429. */
  430. old_pattern = compute_store_pattern(tid, w_ptr, prev_sweep_id);
  431. /*
  432. * FLUSH:Ensure that we flush the contents of
  433. * the cache before loading
  434. */
  435. dcbf((volatile unsigned int*)w_ptr); //Flush
  436. /* LOAD: Read the value */
  437. read_data = *w_ptr; //Load
  438. /*
  439. * COMPARE: Is it the same as what we had stored
  440. * in the previous sweep ? It better be!
  441. */
  442. if (read_data != old_pattern) {
  443. /* No it isn't! Tell everyone */
  444. corruption_found = 1;
  445. }
  446. /*
  447. * Before performing a store, let us check if
  448. * any rim_thread has found a corruption.
  449. */
  450. if (corruption_found || timeout) {
  451. /*
  452. * Yes. Someone (including us!) has found
  453. * a corruption :(
  454. *
  455. * Let us verify that our chunk is
  456. * correct.
  457. */
  458. /* But first, let us allow the dust to settle down! */
  459. verify_chunk(tid, w_ptr, cur_sweep_id, prev_sweep_id);
  460. return 0;
  461. }
  462. /*
  463. * Compute the new pattern that we are going
  464. * to write to this location
  465. */
  466. *pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id);
  467. /*
  468. * STORE: Now let us write this pattern into
  469. * the location
  470. */
  471. *w_ptr = *pattern_ptr;
  472. }
  473. }
  474. return NULL;
  475. }
  476. static unsigned long start_cpu = 0;
  477. static unsigned long nrthreads = 4;
  478. static pthread_t mem_snapshot_thread;
  479. static void *mem_snapshot_fn(void *arg)
  480. {
  481. int page_size = getpagesize();
  482. size_t size = page_size;
  483. void *tmp = malloc(size);
  484. while (!corruption_found && !timeout) {
  485. /* Stop memory migration once corruption is found */
  486. segv_wait = 1;
  487. mprotect(map1, size, PROT_READ);
  488. /*
  489. * Load from the working alias (map1). Loading from map2
  490. * also fails.
  491. */
  492. memcpy(tmp, map1, size);
  493. /*
  494. * Stores must go via map2 which has write permissions, but
  495. * the corrupted data tends to be seen in the snapshot buffer,
  496. * so corruption does not appear to be introduced at the
  497. * copy-back via map2 alias here.
  498. */
  499. memcpy(map2, tmp, size);
  500. /*
  501. * Before releasing other threads, must ensure the copy
  502. * back to
  503. */
  504. asm volatile("sync" ::: "memory");
  505. mprotect(map1, size, PROT_READ|PROT_WRITE);
  506. asm volatile("sync" ::: "memory");
  507. segv_wait = 0;
  508. usleep(1); /* This value makes a big difference */
  509. }
  510. return 0;
  511. }
  512. void alrm_sighandler(int sig)
  513. {
  514. timeout = 1;
  515. }
  516. int main(int argc, char *argv[])
  517. {
  518. int c;
  519. int page_size = getpagesize();
  520. time_t now;
  521. int i, dir_error;
  522. pthread_attr_t attr;
  523. key_t shm_key = (key_t) getpid();
  524. int shmid, run_time = 20 * 60;
  525. struct sigaction sa_alrm;
  526. snprintf(logdir, LOGDIR_NAME_SIZE,
  527. "/tmp/logdir-%u", (unsigned int)getpid());
  528. while ((c = getopt(argc, argv, "r:hn:l:t:")) != -1) {
  529. switch(c) {
  530. case 'r':
  531. start_cpu = strtoul(optarg, NULL, 10);
  532. break;
  533. case 'h':
  534. printf("%s [-r <start_cpu>] [-n <nrthreads>] [-l <logdir>] [-t <timeout>]\n", argv[0]);
  535. exit(0);
  536. break;
  537. case 'n':
  538. nrthreads = strtoul(optarg, NULL, 10);
  539. break;
  540. case 'l':
  541. strncpy(logdir, optarg, LOGDIR_NAME_SIZE - 1);
  542. break;
  543. case 't':
  544. run_time = strtoul(optarg, NULL, 10);
  545. break;
  546. default:
  547. printf("invalid option\n");
  548. exit(0);
  549. break;
  550. }
  551. }
  552. if (nrthreads > MAX_THREADS)
  553. nrthreads = MAX_THREADS;
  554. shmid = shmget(shm_key, page_size, IPC_CREAT|0666);
  555. if (shmid < 0) {
  556. err_msg("Failed shmget\n");
  557. }
  558. map1 = shmat(shmid, NULL, 0);
  559. if (map1 == (void *) -1) {
  560. err_msg("Failed shmat");
  561. }
  562. map2 = shmat(shmid, NULL, 0);
  563. if (map2 == (void *) -1) {
  564. err_msg("Failed shmat");
  565. }
  566. dir_error = mkdir(logdir, 0755);
  567. if (dir_error) {
  568. err_msg("Failed mkdir");
  569. }
  570. printf("start_cpu list:%lu\n", start_cpu);
  571. printf("number of worker threads:%lu + 1 snapshot thread\n", nrthreads);
  572. printf("Allocated address:0x%016lx + secondary map:0x%016lx\n", (unsigned long)map1, (unsigned long)map2);
  573. printf("logdir at : %s\n", logdir);
  574. printf("Timeout: %d seconds\n", run_time);
  575. time(&now);
  576. printf("=================================\n");
  577. printf(" Starting Test\n");
  578. printf(" %s", ctime(&now));
  579. printf("=================================\n");
  580. for (i = 0; i < nrthreads; i++) {
  581. if (1 && !fork()) {
  582. prctl(PR_SET_PDEATHSIG, SIGKILL);
  583. set_mycpu(start_cpu + i);
  584. for (;;)
  585. sched_yield();
  586. exit(0);
  587. }
  588. }
  589. sa_alrm.sa_handler = &alrm_sighandler;
  590. sigemptyset(&sa_alrm.sa_mask);
  591. sa_alrm.sa_flags = 0;
  592. if (sigaction(SIGALRM, &sa_alrm, 0) == -1) {
  593. err_msg("Failed signal handler registration\n");
  594. }
  595. alarm(run_time);
  596. pthread_attr_init(&attr);
  597. for (i = 0; i < nrthreads; i++) {
  598. rim_thread_ids[i] = i;
  599. pthread_create(&rim_threads[i], &attr, rim_fn, &rim_thread_ids[i]);
  600. set_pthread_cpu(rim_threads[i], start_cpu + i);
  601. }
  602. pthread_create(&mem_snapshot_thread, &attr, mem_snapshot_fn, map1);
  603. set_pthread_cpu(mem_snapshot_thread, start_cpu + i);
  604. pthread_join(mem_snapshot_thread, NULL);
  605. for (i = 0; i < nrthreads; i++) {
  606. pthread_join(rim_threads[i], NULL);
  607. }
  608. if (!timeout) {
  609. time(&now);
  610. printf("=================================\n");
  611. printf(" Data Corruption Detected\n");
  612. printf(" %s", ctime(&now));
  613. printf(" See logfiles in %s\n", logdir);
  614. printf("=================================\n");
  615. return 1;
  616. }
  617. return 0;
  618. }