193cad5f7SAneesh Kumar K.V // SPDX-License-Identifier: GPL-2.0
293cad5f7SAneesh Kumar K.V
393cad5f7SAneesh Kumar K.V /*
493cad5f7SAneesh Kumar K.V * Copyright 2019, Nick Piggin, Gautham R. Shenoy, Aneesh Kumar K.V, IBM Corp.
593cad5f7SAneesh Kumar K.V */
693cad5f7SAneesh Kumar K.V
793cad5f7SAneesh Kumar K.V /*
893cad5f7SAneesh Kumar K.V *
993cad5f7SAneesh Kumar K.V * Test tlbie/mtpidr race. We have 4 threads doing flush/load/compare/store
1093cad5f7SAneesh Kumar K.V * sequence in a loop. The same threads also rung a context switch task
1193cad5f7SAneesh Kumar K.V * that does sched_yield() in loop.
1293cad5f7SAneesh Kumar K.V *
1393cad5f7SAneesh Kumar K.V * The snapshot thread mark the mmap area PROT_READ in between, make a copy
1493cad5f7SAneesh Kumar K.V * and copy it back to the original area. This helps us to detect if any
1593cad5f7SAneesh Kumar K.V * store continued to happen after we marked the memory PROT_READ.
1693cad5f7SAneesh Kumar K.V */
1793cad5f7SAneesh Kumar K.V
1893cad5f7SAneesh Kumar K.V #define _GNU_SOURCE
1993cad5f7SAneesh Kumar K.V #include <stdio.h>
2093cad5f7SAneesh Kumar K.V #include <sys/mman.h>
2193cad5f7SAneesh Kumar K.V #include <sys/types.h>
2293cad5f7SAneesh Kumar K.V #include <sys/wait.h>
2393cad5f7SAneesh Kumar K.V #include <sys/ipc.h>
2493cad5f7SAneesh Kumar K.V #include <sys/shm.h>
2593cad5f7SAneesh Kumar K.V #include <sys/stat.h>
2693cad5f7SAneesh Kumar K.V #include <sys/time.h>
2793cad5f7SAneesh Kumar K.V #include <linux/futex.h>
2893cad5f7SAneesh Kumar K.V #include <unistd.h>
2993cad5f7SAneesh Kumar K.V #include <asm/unistd.h>
3093cad5f7SAneesh Kumar K.V #include <string.h>
3193cad5f7SAneesh Kumar K.V #include <stdlib.h>
3293cad5f7SAneesh Kumar K.V #include <fcntl.h>
3393cad5f7SAneesh Kumar K.V #include <sched.h>
3493cad5f7SAneesh Kumar K.V #include <time.h>
3593cad5f7SAneesh Kumar K.V #include <stdarg.h>
3693cad5f7SAneesh Kumar K.V #include <pthread.h>
3793cad5f7SAneesh Kumar K.V #include <signal.h>
3893cad5f7SAneesh Kumar K.V #include <sys/prctl.h>
3993cad5f7SAneesh Kumar K.V
dcbf(volatile unsigned int * addr)4093cad5f7SAneesh Kumar K.V static inline void dcbf(volatile unsigned int *addr)
4193cad5f7SAneesh Kumar K.V {
4293cad5f7SAneesh Kumar K.V __asm__ __volatile__ ("dcbf %y0; sync" : : "Z"(*(unsigned char *)addr) : "memory");
4393cad5f7SAneesh Kumar K.V }
4493cad5f7SAneesh Kumar K.V
err_msg(char * msg)4593cad5f7SAneesh Kumar K.V static void err_msg(char *msg)
4693cad5f7SAneesh Kumar K.V {
4793cad5f7SAneesh Kumar K.V
4893cad5f7SAneesh Kumar K.V time_t now;
4993cad5f7SAneesh Kumar K.V time(&now);
5093cad5f7SAneesh Kumar K.V printf("=================================\n");
5193cad5f7SAneesh Kumar K.V printf(" Error: %s\n", msg);
5293cad5f7SAneesh Kumar K.V printf(" %s", ctime(&now));
5393cad5f7SAneesh Kumar K.V printf("=================================\n");
5493cad5f7SAneesh Kumar K.V exit(1);
5593cad5f7SAneesh Kumar K.V }
5693cad5f7SAneesh Kumar K.V
5793cad5f7SAneesh Kumar K.V static char *map1;
5893cad5f7SAneesh Kumar K.V static char *map2;
5993cad5f7SAneesh Kumar K.V static pid_t rim_process_pid;
6093cad5f7SAneesh Kumar K.V
6193cad5f7SAneesh Kumar K.V /*
6293cad5f7SAneesh Kumar K.V * A "rim-sequence" is defined to be the sequence of the following
6393cad5f7SAneesh Kumar K.V * operations performed on a memory word:
6493cad5f7SAneesh Kumar K.V * 1) FLUSH the contents of that word.
6593cad5f7SAneesh Kumar K.V * 2) LOAD the contents of that word.
6693cad5f7SAneesh Kumar K.V * 3) COMPARE the contents of that word with the content that was
6793cad5f7SAneesh Kumar K.V * previously stored at that word
6893cad5f7SAneesh Kumar K.V * 4) STORE new content into that word.
6993cad5f7SAneesh Kumar K.V *
7093cad5f7SAneesh Kumar K.V * The threads in this test that perform the rim-sequence are termed
7193cad5f7SAneesh Kumar K.V * as rim_threads.
7293cad5f7SAneesh Kumar K.V */
7393cad5f7SAneesh Kumar K.V
7493cad5f7SAneesh Kumar K.V /*
7593cad5f7SAneesh Kumar K.V * A "corruption" is defined to be the failed COMPARE operation in a
7693cad5f7SAneesh Kumar K.V * rim-sequence.
7793cad5f7SAneesh Kumar K.V *
7893cad5f7SAneesh Kumar K.V * A rim_thread that detects a corruption informs about it to all the
7993cad5f7SAneesh Kumar K.V * other rim_threads, and the mem_snapshot thread.
8093cad5f7SAneesh Kumar K.V */
8193cad5f7SAneesh Kumar K.V static volatile unsigned int corruption_found;
8293cad5f7SAneesh Kumar K.V
8393cad5f7SAneesh Kumar K.V /*
8493cad5f7SAneesh Kumar K.V * This defines the maximum number of rim_threads in this test.
8593cad5f7SAneesh Kumar K.V *
8693cad5f7SAneesh Kumar K.V * The THREAD_ID_BITS denote the number of bits required
8793cad5f7SAneesh Kumar K.V * to represent the thread_ids [0..MAX_THREADS - 1].
8893cad5f7SAneesh Kumar K.V * We are being a bit paranoid here and set it to 8 bits,
8993cad5f7SAneesh Kumar K.V * though 6 bits suffice.
9093cad5f7SAneesh Kumar K.V *
9193cad5f7SAneesh Kumar K.V */
9293cad5f7SAneesh Kumar K.V #define MAX_THREADS 64
9393cad5f7SAneesh Kumar K.V #define THREAD_ID_BITS 8
9493cad5f7SAneesh Kumar K.V #define THREAD_ID_MASK ((1 << THREAD_ID_BITS) - 1)
9593cad5f7SAneesh Kumar K.V static unsigned int rim_thread_ids[MAX_THREADS];
9693cad5f7SAneesh Kumar K.V static pthread_t rim_threads[MAX_THREADS];
9793cad5f7SAneesh Kumar K.V
9893cad5f7SAneesh Kumar K.V
9993cad5f7SAneesh Kumar K.V /*
10093cad5f7SAneesh Kumar K.V * Each rim_thread works on an exclusive "chunk" of size
10193cad5f7SAneesh Kumar K.V * RIM_CHUNK_SIZE.
10293cad5f7SAneesh Kumar K.V *
10393cad5f7SAneesh Kumar K.V * The ith rim_thread works on the ith chunk.
10493cad5f7SAneesh Kumar K.V *
10593cad5f7SAneesh Kumar K.V * The ith chunk begins at
10693cad5f7SAneesh Kumar K.V * map1 + (i * RIM_CHUNK_SIZE)
10793cad5f7SAneesh Kumar K.V */
10893cad5f7SAneesh Kumar K.V #define RIM_CHUNK_SIZE 1024
10993cad5f7SAneesh Kumar K.V #define BITS_PER_BYTE 8
11093cad5f7SAneesh Kumar K.V #define WORD_SIZE (sizeof(unsigned int))
11193cad5f7SAneesh Kumar K.V #define WORD_BITS (WORD_SIZE * BITS_PER_BYTE)
11293cad5f7SAneesh Kumar K.V #define WORDS_PER_CHUNK (RIM_CHUNK_SIZE/WORD_SIZE)
11393cad5f7SAneesh Kumar K.V
compute_chunk_start_addr(unsigned int thread_id)11493cad5f7SAneesh Kumar K.V static inline char *compute_chunk_start_addr(unsigned int thread_id)
11593cad5f7SAneesh Kumar K.V {
11693cad5f7SAneesh Kumar K.V char *chunk_start;
11793cad5f7SAneesh Kumar K.V
11893cad5f7SAneesh Kumar K.V chunk_start = (char *)((unsigned long)map1 +
11993cad5f7SAneesh Kumar K.V (thread_id * RIM_CHUNK_SIZE));
12093cad5f7SAneesh Kumar K.V
12193cad5f7SAneesh Kumar K.V return chunk_start;
12293cad5f7SAneesh Kumar K.V }
12393cad5f7SAneesh Kumar K.V
12493cad5f7SAneesh Kumar K.V /*
12593cad5f7SAneesh Kumar K.V * The "word-offset" of a word-aligned address inside a chunk, is
12693cad5f7SAneesh Kumar K.V * defined to be the number of words that precede the address in that
12793cad5f7SAneesh Kumar K.V * chunk.
12893cad5f7SAneesh Kumar K.V *
12993cad5f7SAneesh Kumar K.V * WORD_OFFSET_BITS denote the number of bits required to represent
13093cad5f7SAneesh Kumar K.V * the word-offsets of all the word-aligned addresses of a chunk.
13193cad5f7SAneesh Kumar K.V */
13293cad5f7SAneesh Kumar K.V #define WORD_OFFSET_BITS (__builtin_ctz(WORDS_PER_CHUNK))
13393cad5f7SAneesh Kumar K.V #define WORD_OFFSET_MASK ((1 << WORD_OFFSET_BITS) - 1)
13493cad5f7SAneesh Kumar K.V
compute_word_offset(char * start,unsigned int * addr)13593cad5f7SAneesh Kumar K.V static inline unsigned int compute_word_offset(char *start, unsigned int *addr)
13693cad5f7SAneesh Kumar K.V {
13793cad5f7SAneesh Kumar K.V unsigned int delta_bytes, ret;
13893cad5f7SAneesh Kumar K.V delta_bytes = (unsigned long)addr - (unsigned long)start;
13993cad5f7SAneesh Kumar K.V
14093cad5f7SAneesh Kumar K.V ret = delta_bytes/WORD_SIZE;
14193cad5f7SAneesh Kumar K.V
14293cad5f7SAneesh Kumar K.V return ret;
14393cad5f7SAneesh Kumar K.V }
14493cad5f7SAneesh Kumar K.V
14593cad5f7SAneesh Kumar K.V /*
14693cad5f7SAneesh Kumar K.V * A "sweep" is defined to be the sequential execution of the
14793cad5f7SAneesh Kumar K.V * rim-sequence by a rim_thread on its chunk one word at a time,
14893cad5f7SAneesh Kumar K.V * starting from the first word of its chunk and ending with the last
14993cad5f7SAneesh Kumar K.V * word of its chunk.
15093cad5f7SAneesh Kumar K.V *
15193cad5f7SAneesh Kumar K.V * Each sweep of a rim_thread is uniquely identified by a sweep_id.
15293cad5f7SAneesh Kumar K.V * SWEEP_ID_BITS denote the number of bits required to represent
15393cad5f7SAneesh Kumar K.V * the sweep_ids of rim_threads.
15493cad5f7SAneesh Kumar K.V *
15593cad5f7SAneesh Kumar K.V * As to why SWEEP_ID_BITS are computed as a function of THREAD_ID_BITS,
15693cad5f7SAneesh Kumar K.V * WORD_OFFSET_BITS, and WORD_BITS, see the "store-pattern" below.
15793cad5f7SAneesh Kumar K.V */
15893cad5f7SAneesh Kumar K.V #define SWEEP_ID_BITS (WORD_BITS - (THREAD_ID_BITS + WORD_OFFSET_BITS))
15993cad5f7SAneesh Kumar K.V #define SWEEP_ID_MASK ((1 << SWEEP_ID_BITS) - 1)
16093cad5f7SAneesh Kumar K.V
16193cad5f7SAneesh Kumar K.V /*
16293cad5f7SAneesh Kumar K.V * A "store-pattern" is the word-pattern that is stored into a word
16393cad5f7SAneesh Kumar K.V * location in the 4)STORE step of the rim-sequence.
16493cad5f7SAneesh Kumar K.V *
16593cad5f7SAneesh Kumar K.V * In the store-pattern, we shall encode:
16693cad5f7SAneesh Kumar K.V *
16793cad5f7SAneesh Kumar K.V * - The thread-id of the rim_thread performing the store
16893cad5f7SAneesh Kumar K.V * (The most significant THREAD_ID_BITS)
16993cad5f7SAneesh Kumar K.V *
17093cad5f7SAneesh Kumar K.V * - The word-offset of the address into which the store is being
17193cad5f7SAneesh Kumar K.V * performed (The next WORD_OFFSET_BITS)
17293cad5f7SAneesh Kumar K.V *
17393cad5f7SAneesh Kumar K.V * - The sweep_id of the current sweep in which the store is
17493cad5f7SAneesh Kumar K.V * being performed. (The lower SWEEP_ID_BITS)
17593cad5f7SAneesh Kumar K.V *
17693cad5f7SAneesh Kumar K.V * Store Pattern: 32 bits
17793cad5f7SAneesh Kumar K.V * |------------------|--------------------|---------------------------------|
17893cad5f7SAneesh Kumar K.V * | Thread id | Word offset | sweep_id |
17993cad5f7SAneesh Kumar K.V * |------------------|--------------------|---------------------------------|
18093cad5f7SAneesh Kumar K.V * THREAD_ID_BITS WORD_OFFSET_BITS SWEEP_ID_BITS
18193cad5f7SAneesh Kumar K.V *
18293cad5f7SAneesh Kumar K.V * In the store pattern, the (Thread-id + Word-offset) uniquely identify the
18393cad5f7SAneesh Kumar K.V * address to which the store is being performed i.e,
18493cad5f7SAneesh Kumar K.V * address == map1 +
18593cad5f7SAneesh Kumar K.V * (Thread-id * RIM_CHUNK_SIZE) + (Word-offset * WORD_SIZE)
18693cad5f7SAneesh Kumar K.V *
18793cad5f7SAneesh Kumar K.V * And the sweep_id in the store pattern identifies the time when the
18893cad5f7SAneesh Kumar K.V * store was performed by the rim_thread.
18993cad5f7SAneesh Kumar K.V *
19093cad5f7SAneesh Kumar K.V * We shall use this property in the 3)COMPARE step of the
19193cad5f7SAneesh Kumar K.V * rim-sequence.
19293cad5f7SAneesh Kumar K.V */
19393cad5f7SAneesh Kumar K.V #define SWEEP_ID_SHIFT 0
19493cad5f7SAneesh Kumar K.V #define WORD_OFFSET_SHIFT (SWEEP_ID_BITS)
19593cad5f7SAneesh Kumar K.V #define THREAD_ID_SHIFT (WORD_OFFSET_BITS + SWEEP_ID_BITS)
19693cad5f7SAneesh Kumar K.V
19793cad5f7SAneesh Kumar K.V /*
19893cad5f7SAneesh Kumar K.V * Compute the store pattern for a given thread with id @tid, at
19993cad5f7SAneesh Kumar K.V * location @addr in the sweep identified by @sweep_id
20093cad5f7SAneesh Kumar K.V */
compute_store_pattern(unsigned int tid,unsigned int * addr,unsigned int sweep_id)20193cad5f7SAneesh Kumar K.V static inline unsigned int compute_store_pattern(unsigned int tid,
20293cad5f7SAneesh Kumar K.V unsigned int *addr,
20393cad5f7SAneesh Kumar K.V unsigned int sweep_id)
20493cad5f7SAneesh Kumar K.V {
20593cad5f7SAneesh Kumar K.V unsigned int ret = 0;
20693cad5f7SAneesh Kumar K.V char *start = compute_chunk_start_addr(tid);
20793cad5f7SAneesh Kumar K.V unsigned int word_offset = compute_word_offset(start, addr);
20893cad5f7SAneesh Kumar K.V
20993cad5f7SAneesh Kumar K.V ret += (tid & THREAD_ID_MASK) << THREAD_ID_SHIFT;
21093cad5f7SAneesh Kumar K.V ret += (word_offset & WORD_OFFSET_MASK) << WORD_OFFSET_SHIFT;
21193cad5f7SAneesh Kumar K.V ret += (sweep_id & SWEEP_ID_MASK) << SWEEP_ID_SHIFT;
21293cad5f7SAneesh Kumar K.V return ret;
21393cad5f7SAneesh Kumar K.V }
21493cad5f7SAneesh Kumar K.V
21593cad5f7SAneesh Kumar K.V /* Extract the thread-id from the given store-pattern */
extract_tid(unsigned int pattern)21693cad5f7SAneesh Kumar K.V static inline unsigned int extract_tid(unsigned int pattern)
21793cad5f7SAneesh Kumar K.V {
21893cad5f7SAneesh Kumar K.V unsigned int ret;
21993cad5f7SAneesh Kumar K.V
22093cad5f7SAneesh Kumar K.V ret = (pattern >> THREAD_ID_SHIFT) & THREAD_ID_MASK;
22193cad5f7SAneesh Kumar K.V return ret;
22293cad5f7SAneesh Kumar K.V }
22393cad5f7SAneesh Kumar K.V
22493cad5f7SAneesh Kumar K.V /* Extract the word-offset from the given store-pattern */
extract_word_offset(unsigned int pattern)22593cad5f7SAneesh Kumar K.V static inline unsigned int extract_word_offset(unsigned int pattern)
22693cad5f7SAneesh Kumar K.V {
22793cad5f7SAneesh Kumar K.V unsigned int ret;
22893cad5f7SAneesh Kumar K.V
22993cad5f7SAneesh Kumar K.V ret = (pattern >> WORD_OFFSET_SHIFT) & WORD_OFFSET_MASK;
23093cad5f7SAneesh Kumar K.V
23193cad5f7SAneesh Kumar K.V return ret;
23293cad5f7SAneesh Kumar K.V }
23393cad5f7SAneesh Kumar K.V
23493cad5f7SAneesh Kumar K.V /* Extract the sweep-id from the given store-pattern */
extract_sweep_id(unsigned int pattern)23593cad5f7SAneesh Kumar K.V static inline unsigned int extract_sweep_id(unsigned int pattern)
23693cad5f7SAneesh Kumar K.V
23793cad5f7SAneesh Kumar K.V {
23893cad5f7SAneesh Kumar K.V unsigned int ret;
23993cad5f7SAneesh Kumar K.V
24093cad5f7SAneesh Kumar K.V ret = (pattern >> SWEEP_ID_SHIFT) & SWEEP_ID_MASK;
24193cad5f7SAneesh Kumar K.V
24293cad5f7SAneesh Kumar K.V return ret;
24393cad5f7SAneesh Kumar K.V }
24493cad5f7SAneesh Kumar K.V
24593cad5f7SAneesh Kumar K.V /************************************************************
24693cad5f7SAneesh Kumar K.V * *
24793cad5f7SAneesh Kumar K.V * Logging the output of the verification *
24893cad5f7SAneesh Kumar K.V * *
24993cad5f7SAneesh Kumar K.V ************************************************************/
25093cad5f7SAneesh Kumar K.V #define LOGDIR_NAME_SIZE 100
25193cad5f7SAneesh Kumar K.V static char logdir[LOGDIR_NAME_SIZE];
25293cad5f7SAneesh Kumar K.V
25393cad5f7SAneesh Kumar K.V static FILE *fp[MAX_THREADS];
25493cad5f7SAneesh Kumar K.V static const char logfilename[] ="Thread-%02d-Chunk";
25593cad5f7SAneesh Kumar K.V
start_verification_log(unsigned int tid,unsigned int * addr,unsigned int cur_sweep_id,unsigned int prev_sweep_id)25693cad5f7SAneesh Kumar K.V static inline void start_verification_log(unsigned int tid,
25793cad5f7SAneesh Kumar K.V unsigned int *addr,
25893cad5f7SAneesh Kumar K.V unsigned int cur_sweep_id,
25993cad5f7SAneesh Kumar K.V unsigned int prev_sweep_id)
26093cad5f7SAneesh Kumar K.V {
26193cad5f7SAneesh Kumar K.V FILE *f;
26293cad5f7SAneesh Kumar K.V char logfile[30];
26393cad5f7SAneesh Kumar K.V char path[LOGDIR_NAME_SIZE + 30];
26493cad5f7SAneesh Kumar K.V char separator[2] = "/";
26593cad5f7SAneesh Kumar K.V char *chunk_start = compute_chunk_start_addr(tid);
26693cad5f7SAneesh Kumar K.V unsigned int size = RIM_CHUNK_SIZE;
26793cad5f7SAneesh Kumar K.V
26893cad5f7SAneesh Kumar K.V sprintf(logfile, logfilename, tid);
26993cad5f7SAneesh Kumar K.V strcpy(path, logdir);
27093cad5f7SAneesh Kumar K.V strcat(path, separator);
27193cad5f7SAneesh Kumar K.V strcat(path, logfile);
27293cad5f7SAneesh Kumar K.V f = fopen(path, "w");
27393cad5f7SAneesh Kumar K.V
27493cad5f7SAneesh Kumar K.V if (!f) {
27593cad5f7SAneesh Kumar K.V err_msg("Unable to create logfile\n");
27693cad5f7SAneesh Kumar K.V }
27793cad5f7SAneesh Kumar K.V
27893cad5f7SAneesh Kumar K.V fp[tid] = f;
27993cad5f7SAneesh Kumar K.V
28093cad5f7SAneesh Kumar K.V fprintf(f, "----------------------------------------------------------\n");
28193cad5f7SAneesh Kumar K.V fprintf(f, "PID = %d\n", rim_process_pid);
28293cad5f7SAneesh Kumar K.V fprintf(f, "Thread id = %02d\n", tid);
28393cad5f7SAneesh Kumar K.V fprintf(f, "Chunk Start Addr = 0x%016lx\n", (unsigned long)chunk_start);
28493cad5f7SAneesh Kumar K.V fprintf(f, "Chunk Size = %d\n", size);
28593cad5f7SAneesh Kumar K.V fprintf(f, "Next Store Addr = 0x%016lx\n", (unsigned long)addr);
28693cad5f7SAneesh Kumar K.V fprintf(f, "Current sweep-id = 0x%08x\n", cur_sweep_id);
28793cad5f7SAneesh Kumar K.V fprintf(f, "Previous sweep-id = 0x%08x\n", prev_sweep_id);
28893cad5f7SAneesh Kumar K.V fprintf(f, "----------------------------------------------------------\n");
28993cad5f7SAneesh Kumar K.V }
29093cad5f7SAneesh Kumar K.V
log_anamoly(unsigned int tid,unsigned int * addr,unsigned int expected,unsigned int observed)29193cad5f7SAneesh Kumar K.V static inline void log_anamoly(unsigned int tid, unsigned int *addr,
29293cad5f7SAneesh Kumar K.V unsigned int expected, unsigned int observed)
29393cad5f7SAneesh Kumar K.V {
29493cad5f7SAneesh Kumar K.V FILE *f = fp[tid];
29593cad5f7SAneesh Kumar K.V
29693cad5f7SAneesh Kumar K.V fprintf(f, "Thread %02d: Addr 0x%lx: Expected 0x%x, Observed 0x%x\n",
29793cad5f7SAneesh Kumar K.V tid, (unsigned long)addr, expected, observed);
29893cad5f7SAneesh Kumar K.V fprintf(f, "Thread %02d: Expected Thread id = %02d\n", tid, extract_tid(expected));
29993cad5f7SAneesh Kumar K.V fprintf(f, "Thread %02d: Observed Thread id = %02d\n", tid, extract_tid(observed));
30093cad5f7SAneesh Kumar K.V fprintf(f, "Thread %02d: Expected Word offset = %03d\n", tid, extract_word_offset(expected));
30193cad5f7SAneesh Kumar K.V fprintf(f, "Thread %02d: Observed Word offset = %03d\n", tid, extract_word_offset(observed));
30293cad5f7SAneesh Kumar K.V fprintf(f, "Thread %02d: Expected sweep-id = 0x%x\n", tid, extract_sweep_id(expected));
30393cad5f7SAneesh Kumar K.V fprintf(f, "Thread %02d: Observed sweep-id = 0x%x\n", tid, extract_sweep_id(observed));
30493cad5f7SAneesh Kumar K.V fprintf(f, "----------------------------------------------------------\n");
30593cad5f7SAneesh Kumar K.V }
30693cad5f7SAneesh Kumar K.V
end_verification_log(unsigned int tid,unsigned nr_anamolies)30793cad5f7SAneesh Kumar K.V static inline void end_verification_log(unsigned int tid, unsigned nr_anamolies)
30893cad5f7SAneesh Kumar K.V {
30993cad5f7SAneesh Kumar K.V FILE *f = fp[tid];
31093cad5f7SAneesh Kumar K.V char logfile[30];
31193cad5f7SAneesh Kumar K.V char path[LOGDIR_NAME_SIZE + 30];
31293cad5f7SAneesh Kumar K.V char separator[] = "/";
31393cad5f7SAneesh Kumar K.V
31493cad5f7SAneesh Kumar K.V fclose(f);
31593cad5f7SAneesh Kumar K.V
31693cad5f7SAneesh Kumar K.V if (nr_anamolies == 0) {
31793cad5f7SAneesh Kumar K.V remove(path);
31893cad5f7SAneesh Kumar K.V return;
31993cad5f7SAneesh Kumar K.V }
32093cad5f7SAneesh Kumar K.V
32193cad5f7SAneesh Kumar K.V sprintf(logfile, logfilename, tid);
32293cad5f7SAneesh Kumar K.V strcpy(path, logdir);
32393cad5f7SAneesh Kumar K.V strcat(path, separator);
32493cad5f7SAneesh Kumar K.V strcat(path, logfile);
32593cad5f7SAneesh Kumar K.V
32693cad5f7SAneesh Kumar K.V printf("Thread %02d chunk has %d corrupted words. For details check %s\n",
32793cad5f7SAneesh Kumar K.V tid, nr_anamolies, path);
32893cad5f7SAneesh Kumar K.V }
32993cad5f7SAneesh Kumar K.V
33093cad5f7SAneesh Kumar K.V /*
33193cad5f7SAneesh Kumar K.V * When a COMPARE step of a rim-sequence fails, the rim_thread informs
33293cad5f7SAneesh Kumar K.V * everyone else via the shared_memory pointed to by
33393cad5f7SAneesh Kumar K.V * corruption_found variable. On seeing this, every thread verifies the
33493cad5f7SAneesh Kumar K.V * content of its chunk as follows.
33593cad5f7SAneesh Kumar K.V *
33693cad5f7SAneesh Kumar K.V * Suppose a thread identified with @tid was about to store (but not
33793cad5f7SAneesh Kumar K.V * yet stored) to @next_store_addr in its current sweep identified
33893cad5f7SAneesh Kumar K.V * @cur_sweep_id. Let @prev_sweep_id indicate the previous sweep_id.
33993cad5f7SAneesh Kumar K.V *
34093cad5f7SAneesh Kumar K.V * This implies that for all the addresses @addr < @next_store_addr,
34193cad5f7SAneesh Kumar K.V * Thread @tid has already performed a store as part of its current
34293cad5f7SAneesh Kumar K.V * sweep. Hence we expect the content of such @addr to be:
34393cad5f7SAneesh Kumar K.V * |-------------------------------------------------|
34493cad5f7SAneesh Kumar K.V * | tid | word_offset(addr) | cur_sweep_id |
34593cad5f7SAneesh Kumar K.V * |-------------------------------------------------|
34693cad5f7SAneesh Kumar K.V *
34793cad5f7SAneesh Kumar K.V * Since Thread @tid is yet to perform stores on address
34893cad5f7SAneesh Kumar K.V * @next_store_addr and above, we expect the content of such an
34993cad5f7SAneesh Kumar K.V * address @addr to be:
35093cad5f7SAneesh Kumar K.V * |-------------------------------------------------|
35193cad5f7SAneesh Kumar K.V * | tid | word_offset(addr) | prev_sweep_id |
35293cad5f7SAneesh Kumar K.V * |-------------------------------------------------|
35393cad5f7SAneesh Kumar K.V *
35493cad5f7SAneesh Kumar K.V * The verifier function @verify_chunk does this verification and logs
35593cad5f7SAneesh Kumar K.V * any anamolies that it finds.
35693cad5f7SAneesh Kumar K.V */
verify_chunk(unsigned int tid,unsigned int * next_store_addr,unsigned int cur_sweep_id,unsigned int prev_sweep_id)35793cad5f7SAneesh Kumar K.V static void verify_chunk(unsigned int tid, unsigned int *next_store_addr,
35893cad5f7SAneesh Kumar K.V unsigned int cur_sweep_id,
35993cad5f7SAneesh Kumar K.V unsigned int prev_sweep_id)
36093cad5f7SAneesh Kumar K.V {
36193cad5f7SAneesh Kumar K.V unsigned int *iter_ptr;
36293cad5f7SAneesh Kumar K.V unsigned int size = RIM_CHUNK_SIZE;
36393cad5f7SAneesh Kumar K.V unsigned int expected;
36493cad5f7SAneesh Kumar K.V unsigned int observed;
36593cad5f7SAneesh Kumar K.V char *chunk_start = compute_chunk_start_addr(tid);
36693cad5f7SAneesh Kumar K.V
36793cad5f7SAneesh Kumar K.V int nr_anamolies = 0;
36893cad5f7SAneesh Kumar K.V
36993cad5f7SAneesh Kumar K.V start_verification_log(tid, next_store_addr,
37093cad5f7SAneesh Kumar K.V cur_sweep_id, prev_sweep_id);
37193cad5f7SAneesh Kumar K.V
37293cad5f7SAneesh Kumar K.V for (iter_ptr = (unsigned int *)chunk_start;
37393cad5f7SAneesh Kumar K.V (unsigned long)iter_ptr < (unsigned long)chunk_start + size;
37493cad5f7SAneesh Kumar K.V iter_ptr++) {
37593cad5f7SAneesh Kumar K.V unsigned int expected_sweep_id;
37693cad5f7SAneesh Kumar K.V
37793cad5f7SAneesh Kumar K.V if (iter_ptr < next_store_addr) {
37893cad5f7SAneesh Kumar K.V expected_sweep_id = cur_sweep_id;
37993cad5f7SAneesh Kumar K.V } else {
38093cad5f7SAneesh Kumar K.V expected_sweep_id = prev_sweep_id;
38193cad5f7SAneesh Kumar K.V }
38293cad5f7SAneesh Kumar K.V
38393cad5f7SAneesh Kumar K.V expected = compute_store_pattern(tid, iter_ptr, expected_sweep_id);
38493cad5f7SAneesh Kumar K.V
38593cad5f7SAneesh Kumar K.V dcbf((volatile unsigned int*)iter_ptr); //Flush before reading
38693cad5f7SAneesh Kumar K.V observed = *iter_ptr;
38793cad5f7SAneesh Kumar K.V
38893cad5f7SAneesh Kumar K.V if (observed != expected) {
38993cad5f7SAneesh Kumar K.V nr_anamolies++;
39093cad5f7SAneesh Kumar K.V log_anamoly(tid, iter_ptr, expected, observed);
39193cad5f7SAneesh Kumar K.V }
39293cad5f7SAneesh Kumar K.V }
39393cad5f7SAneesh Kumar K.V
39493cad5f7SAneesh Kumar K.V end_verification_log(tid, nr_anamolies);
39593cad5f7SAneesh Kumar K.V }
39693cad5f7SAneesh Kumar K.V
set_pthread_cpu(pthread_t th,int cpu)39793cad5f7SAneesh Kumar K.V static void set_pthread_cpu(pthread_t th, int cpu)
39893cad5f7SAneesh Kumar K.V {
39993cad5f7SAneesh Kumar K.V cpu_set_t run_cpu_mask;
40093cad5f7SAneesh Kumar K.V struct sched_param param;
40193cad5f7SAneesh Kumar K.V
40293cad5f7SAneesh Kumar K.V CPU_ZERO(&run_cpu_mask);
40393cad5f7SAneesh Kumar K.V CPU_SET(cpu, &run_cpu_mask);
40493cad5f7SAneesh Kumar K.V pthread_setaffinity_np(th, sizeof(cpu_set_t), &run_cpu_mask);
40593cad5f7SAneesh Kumar K.V
40693cad5f7SAneesh Kumar K.V param.sched_priority = 1;
40793cad5f7SAneesh Kumar K.V if (0 && sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
40893cad5f7SAneesh Kumar K.V /* haven't reproduced with this setting, it kills random preemption which may be a factor */
40993cad5f7SAneesh Kumar K.V fprintf(stderr, "could not set SCHED_FIFO, run as root?\n");
41093cad5f7SAneesh Kumar K.V }
41193cad5f7SAneesh Kumar K.V }
41293cad5f7SAneesh Kumar K.V
set_mycpu(int cpu)41393cad5f7SAneesh Kumar K.V static void set_mycpu(int cpu)
41493cad5f7SAneesh Kumar K.V {
41593cad5f7SAneesh Kumar K.V cpu_set_t run_cpu_mask;
41693cad5f7SAneesh Kumar K.V struct sched_param param;
41793cad5f7SAneesh Kumar K.V
41893cad5f7SAneesh Kumar K.V CPU_ZERO(&run_cpu_mask);
41993cad5f7SAneesh Kumar K.V CPU_SET(cpu, &run_cpu_mask);
42093cad5f7SAneesh Kumar K.V sched_setaffinity(0, sizeof(cpu_set_t), &run_cpu_mask);
42193cad5f7SAneesh Kumar K.V
42293cad5f7SAneesh Kumar K.V param.sched_priority = 1;
42393cad5f7SAneesh Kumar K.V if (0 && sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
42493cad5f7SAneesh Kumar K.V fprintf(stderr, "could not set SCHED_FIFO, run as root?\n");
42593cad5f7SAneesh Kumar K.V }
42693cad5f7SAneesh Kumar K.V }
42793cad5f7SAneesh Kumar K.V
42893cad5f7SAneesh Kumar K.V static volatile int segv_wait;
42993cad5f7SAneesh Kumar K.V
segv_handler(int signo,siginfo_t * info,void * extra)43093cad5f7SAneesh Kumar K.V static void segv_handler(int signo, siginfo_t *info, void *extra)
43193cad5f7SAneesh Kumar K.V {
43293cad5f7SAneesh Kumar K.V while (segv_wait) {
43393cad5f7SAneesh Kumar K.V sched_yield();
43493cad5f7SAneesh Kumar K.V }
43593cad5f7SAneesh Kumar K.V
43693cad5f7SAneesh Kumar K.V }
43793cad5f7SAneesh Kumar K.V
set_segv_handler(void)43893cad5f7SAneesh Kumar K.V static void set_segv_handler(void)
43993cad5f7SAneesh Kumar K.V {
44093cad5f7SAneesh Kumar K.V struct sigaction sa;
44193cad5f7SAneesh Kumar K.V
44293cad5f7SAneesh Kumar K.V sa.sa_flags = SA_SIGINFO;
44393cad5f7SAneesh Kumar K.V sa.sa_sigaction = segv_handler;
44493cad5f7SAneesh Kumar K.V
44593cad5f7SAneesh Kumar K.V if (sigaction(SIGSEGV, &sa, NULL) == -1) {
44693cad5f7SAneesh Kumar K.V perror("sigaction");
44793cad5f7SAneesh Kumar K.V exit(EXIT_FAILURE);
44893cad5f7SAneesh Kumar K.V }
44993cad5f7SAneesh Kumar K.V }
45093cad5f7SAneesh Kumar K.V
45193cad5f7SAneesh Kumar K.V int timeout = 0;
45293cad5f7SAneesh Kumar K.V /*
45393cad5f7SAneesh Kumar K.V * This function is executed by every rim_thread.
45493cad5f7SAneesh Kumar K.V *
45593cad5f7SAneesh Kumar K.V * This function performs sweeps over the exclusive chunks of the
45693cad5f7SAneesh Kumar K.V * rim_threads executing the rim-sequence one word at a time.
45793cad5f7SAneesh Kumar K.V */
rim_fn(void * arg)45893cad5f7SAneesh Kumar K.V static void *rim_fn(void *arg)
45993cad5f7SAneesh Kumar K.V {
46093cad5f7SAneesh Kumar K.V unsigned int tid = *((unsigned int *)arg);
46193cad5f7SAneesh Kumar K.V
46293cad5f7SAneesh Kumar K.V int size = RIM_CHUNK_SIZE;
46393cad5f7SAneesh Kumar K.V char *chunk_start = compute_chunk_start_addr(tid);
46493cad5f7SAneesh Kumar K.V
46593cad5f7SAneesh Kumar K.V unsigned int prev_sweep_id;
46693cad5f7SAneesh Kumar K.V unsigned int cur_sweep_id = 0;
46793cad5f7SAneesh Kumar K.V
46893cad5f7SAneesh Kumar K.V /* word access */
46993cad5f7SAneesh Kumar K.V unsigned int pattern = cur_sweep_id;
47093cad5f7SAneesh Kumar K.V unsigned int *pattern_ptr = &pattern;
47193cad5f7SAneesh Kumar K.V unsigned int *w_ptr, read_data;
47293cad5f7SAneesh Kumar K.V
47393cad5f7SAneesh Kumar K.V set_segv_handler();
47493cad5f7SAneesh Kumar K.V
47593cad5f7SAneesh Kumar K.V /*
47693cad5f7SAneesh Kumar K.V * Let us initialize the chunk:
47793cad5f7SAneesh Kumar K.V *
47893cad5f7SAneesh Kumar K.V * Each word-aligned address addr in the chunk,
47993cad5f7SAneesh Kumar K.V * is initialized to :
48093cad5f7SAneesh Kumar K.V * |-------------------------------------------------|
48193cad5f7SAneesh Kumar K.V * | tid | word_offset(addr) | 0 |
48293cad5f7SAneesh Kumar K.V * |-------------------------------------------------|
48393cad5f7SAneesh Kumar K.V */
48493cad5f7SAneesh Kumar K.V for (w_ptr = (unsigned int *)chunk_start;
48593cad5f7SAneesh Kumar K.V (unsigned long)w_ptr < (unsigned long)(chunk_start) + size;
48693cad5f7SAneesh Kumar K.V w_ptr++) {
48793cad5f7SAneesh Kumar K.V
48893cad5f7SAneesh Kumar K.V *pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id);
48993cad5f7SAneesh Kumar K.V *w_ptr = *pattern_ptr;
49093cad5f7SAneesh Kumar K.V }
49193cad5f7SAneesh Kumar K.V
49293cad5f7SAneesh Kumar K.V while (!corruption_found && !timeout) {
49393cad5f7SAneesh Kumar K.V prev_sweep_id = cur_sweep_id;
49493cad5f7SAneesh Kumar K.V cur_sweep_id = cur_sweep_id + 1;
49593cad5f7SAneesh Kumar K.V
49693cad5f7SAneesh Kumar K.V for (w_ptr = (unsigned int *)chunk_start;
49793cad5f7SAneesh Kumar K.V (unsigned long)w_ptr < (unsigned long)(chunk_start) + size;
49893cad5f7SAneesh Kumar K.V w_ptr++) {
49993cad5f7SAneesh Kumar K.V unsigned int old_pattern;
50093cad5f7SAneesh Kumar K.V
50193cad5f7SAneesh Kumar K.V /*
50293cad5f7SAneesh Kumar K.V * Compute the pattern that we would have
50393cad5f7SAneesh Kumar K.V * stored at this location in the previous
50493cad5f7SAneesh Kumar K.V * sweep.
50593cad5f7SAneesh Kumar K.V */
50693cad5f7SAneesh Kumar K.V old_pattern = compute_store_pattern(tid, w_ptr, prev_sweep_id);
50793cad5f7SAneesh Kumar K.V
50893cad5f7SAneesh Kumar K.V /*
50993cad5f7SAneesh Kumar K.V * FLUSH:Ensure that we flush the contents of
51093cad5f7SAneesh Kumar K.V * the cache before loading
51193cad5f7SAneesh Kumar K.V */
51293cad5f7SAneesh Kumar K.V dcbf((volatile unsigned int*)w_ptr); //Flush
51393cad5f7SAneesh Kumar K.V
51493cad5f7SAneesh Kumar K.V /* LOAD: Read the value */
51593cad5f7SAneesh Kumar K.V read_data = *w_ptr; //Load
51693cad5f7SAneesh Kumar K.V
51793cad5f7SAneesh Kumar K.V /*
51893cad5f7SAneesh Kumar K.V * COMPARE: Is it the same as what we had stored
51993cad5f7SAneesh Kumar K.V * in the previous sweep ? It better be!
52093cad5f7SAneesh Kumar K.V */
52193cad5f7SAneesh Kumar K.V if (read_data != old_pattern) {
52293cad5f7SAneesh Kumar K.V /* No it isn't! Tell everyone */
52393cad5f7SAneesh Kumar K.V corruption_found = 1;
52493cad5f7SAneesh Kumar K.V }
52593cad5f7SAneesh Kumar K.V
52693cad5f7SAneesh Kumar K.V /*
52793cad5f7SAneesh Kumar K.V * Before performing a store, let us check if
52893cad5f7SAneesh Kumar K.V * any rim_thread has found a corruption.
52993cad5f7SAneesh Kumar K.V */
53093cad5f7SAneesh Kumar K.V if (corruption_found || timeout) {
53193cad5f7SAneesh Kumar K.V /*
53293cad5f7SAneesh Kumar K.V * Yes. Someone (including us!) has found
53393cad5f7SAneesh Kumar K.V * a corruption :(
53493cad5f7SAneesh Kumar K.V *
53593cad5f7SAneesh Kumar K.V * Let us verify that our chunk is
53693cad5f7SAneesh Kumar K.V * correct.
53793cad5f7SAneesh Kumar K.V */
53893cad5f7SAneesh Kumar K.V /* But first, let us allow the dust to settle down! */
53993cad5f7SAneesh Kumar K.V verify_chunk(tid, w_ptr, cur_sweep_id, prev_sweep_id);
54093cad5f7SAneesh Kumar K.V
54193cad5f7SAneesh Kumar K.V return 0;
54293cad5f7SAneesh Kumar K.V }
54393cad5f7SAneesh Kumar K.V
54493cad5f7SAneesh Kumar K.V /*
54593cad5f7SAneesh Kumar K.V * Compute the new pattern that we are going
54693cad5f7SAneesh Kumar K.V * to write to this location
54793cad5f7SAneesh Kumar K.V */
54893cad5f7SAneesh Kumar K.V *pattern_ptr = compute_store_pattern(tid, w_ptr, cur_sweep_id);
54993cad5f7SAneesh Kumar K.V
55093cad5f7SAneesh Kumar K.V /*
55193cad5f7SAneesh Kumar K.V * STORE: Now let us write this pattern into
55293cad5f7SAneesh Kumar K.V * the location
55393cad5f7SAneesh Kumar K.V */
55493cad5f7SAneesh Kumar K.V *w_ptr = *pattern_ptr;
55593cad5f7SAneesh Kumar K.V }
55693cad5f7SAneesh Kumar K.V }
55793cad5f7SAneesh Kumar K.V
55893cad5f7SAneesh Kumar K.V return NULL;
55993cad5f7SAneesh Kumar K.V }
56093cad5f7SAneesh Kumar K.V
56193cad5f7SAneesh Kumar K.V
56293cad5f7SAneesh Kumar K.V static unsigned long start_cpu = 0;
56393cad5f7SAneesh Kumar K.V static unsigned long nrthreads = 4;
56493cad5f7SAneesh Kumar K.V
56593cad5f7SAneesh Kumar K.V static pthread_t mem_snapshot_thread;
56693cad5f7SAneesh Kumar K.V
mem_snapshot_fn(void * arg)56793cad5f7SAneesh Kumar K.V static void *mem_snapshot_fn(void *arg)
56893cad5f7SAneesh Kumar K.V {
56993cad5f7SAneesh Kumar K.V int page_size = getpagesize();
57093cad5f7SAneesh Kumar K.V size_t size = page_size;
57193cad5f7SAneesh Kumar K.V void *tmp = malloc(size);
57293cad5f7SAneesh Kumar K.V
57393cad5f7SAneesh Kumar K.V while (!corruption_found && !timeout) {
57493cad5f7SAneesh Kumar K.V /* Stop memory migration once corruption is found */
57593cad5f7SAneesh Kumar K.V segv_wait = 1;
57693cad5f7SAneesh Kumar K.V
57793cad5f7SAneesh Kumar K.V mprotect(map1, size, PROT_READ);
57893cad5f7SAneesh Kumar K.V
57993cad5f7SAneesh Kumar K.V /*
58093cad5f7SAneesh Kumar K.V * Load from the working alias (map1). Loading from map2
58193cad5f7SAneesh Kumar K.V * also fails.
58293cad5f7SAneesh Kumar K.V */
58393cad5f7SAneesh Kumar K.V memcpy(tmp, map1, size);
58493cad5f7SAneesh Kumar K.V
58593cad5f7SAneesh Kumar K.V /*
58693cad5f7SAneesh Kumar K.V * Stores must go via map2 which has write permissions, but
58793cad5f7SAneesh Kumar K.V * the corrupted data tends to be seen in the snapshot buffer,
58893cad5f7SAneesh Kumar K.V * so corruption does not appear to be introduced at the
58993cad5f7SAneesh Kumar K.V * copy-back via map2 alias here.
59093cad5f7SAneesh Kumar K.V */
59193cad5f7SAneesh Kumar K.V memcpy(map2, tmp, size);
59293cad5f7SAneesh Kumar K.V /*
59393cad5f7SAneesh Kumar K.V * Before releasing other threads, must ensure the copy
59493cad5f7SAneesh Kumar K.V * back to
59593cad5f7SAneesh Kumar K.V */
59693cad5f7SAneesh Kumar K.V asm volatile("sync" ::: "memory");
59793cad5f7SAneesh Kumar K.V mprotect(map1, size, PROT_READ|PROT_WRITE);
59893cad5f7SAneesh Kumar K.V asm volatile("sync" ::: "memory");
59993cad5f7SAneesh Kumar K.V segv_wait = 0;
60093cad5f7SAneesh Kumar K.V
60193cad5f7SAneesh Kumar K.V usleep(1); /* This value makes a big difference */
60293cad5f7SAneesh Kumar K.V }
60393cad5f7SAneesh Kumar K.V
60493cad5f7SAneesh Kumar K.V return 0;
60593cad5f7SAneesh Kumar K.V }
60693cad5f7SAneesh Kumar K.V
alrm_sighandler(int sig)60793cad5f7SAneesh Kumar K.V void alrm_sighandler(int sig)
60893cad5f7SAneesh Kumar K.V {
60993cad5f7SAneesh Kumar K.V timeout = 1;
61093cad5f7SAneesh Kumar K.V }
61193cad5f7SAneesh Kumar K.V
main(int argc,char * argv[])61293cad5f7SAneesh Kumar K.V int main(int argc, char *argv[])
61393cad5f7SAneesh Kumar K.V {
61493cad5f7SAneesh Kumar K.V int c;
61593cad5f7SAneesh Kumar K.V int page_size = getpagesize();
61693cad5f7SAneesh Kumar K.V time_t now;
61793cad5f7SAneesh Kumar K.V int i, dir_error;
61893cad5f7SAneesh Kumar K.V pthread_attr_t attr;
61993cad5f7SAneesh Kumar K.V key_t shm_key = (key_t) getpid();
62093cad5f7SAneesh Kumar K.V int shmid, run_time = 20 * 60;
62193cad5f7SAneesh Kumar K.V struct sigaction sa_alrm;
62293cad5f7SAneesh Kumar K.V
62393cad5f7SAneesh Kumar K.V snprintf(logdir, LOGDIR_NAME_SIZE,
62493cad5f7SAneesh Kumar K.V "/tmp/logdir-%u", (unsigned int)getpid());
62593cad5f7SAneesh Kumar K.V while ((c = getopt(argc, argv, "r:hn:l:t:")) != -1) {
62693cad5f7SAneesh Kumar K.V switch(c) {
62793cad5f7SAneesh Kumar K.V case 'r':
62893cad5f7SAneesh Kumar K.V start_cpu = strtoul(optarg, NULL, 10);
62993cad5f7SAneesh Kumar K.V break;
63093cad5f7SAneesh Kumar K.V case 'h':
63193cad5f7SAneesh Kumar K.V printf("%s [-r <start_cpu>] [-n <nrthreads>] [-l <logdir>] [-t <timeout>]\n", argv[0]);
63293cad5f7SAneesh Kumar K.V exit(0);
63393cad5f7SAneesh Kumar K.V break;
63493cad5f7SAneesh Kumar K.V case 'n':
63593cad5f7SAneesh Kumar K.V nrthreads = strtoul(optarg, NULL, 10);
63693cad5f7SAneesh Kumar K.V break;
63793cad5f7SAneesh Kumar K.V case 'l':
638*5b216ea1SDesnes A. Nunes do Rosario strncpy(logdir, optarg, LOGDIR_NAME_SIZE - 1);
63993cad5f7SAneesh Kumar K.V break;
64093cad5f7SAneesh Kumar K.V case 't':
64193cad5f7SAneesh Kumar K.V run_time = strtoul(optarg, NULL, 10);
64293cad5f7SAneesh Kumar K.V break;
64393cad5f7SAneesh Kumar K.V default:
64493cad5f7SAneesh Kumar K.V printf("invalid option\n");
64593cad5f7SAneesh Kumar K.V exit(0);
64693cad5f7SAneesh Kumar K.V break;
64793cad5f7SAneesh Kumar K.V }
64893cad5f7SAneesh Kumar K.V }
64993cad5f7SAneesh Kumar K.V
65093cad5f7SAneesh Kumar K.V if (nrthreads > MAX_THREADS)
65193cad5f7SAneesh Kumar K.V nrthreads = MAX_THREADS;
65293cad5f7SAneesh Kumar K.V
65393cad5f7SAneesh Kumar K.V shmid = shmget(shm_key, page_size, IPC_CREAT|0666);
65493cad5f7SAneesh Kumar K.V if (shmid < 0) {
65593cad5f7SAneesh Kumar K.V err_msg("Failed shmget\n");
65693cad5f7SAneesh Kumar K.V }
65793cad5f7SAneesh Kumar K.V
65893cad5f7SAneesh Kumar K.V map1 = shmat(shmid, NULL, 0);
65993cad5f7SAneesh Kumar K.V if (map1 == (void *) -1) {
66093cad5f7SAneesh Kumar K.V err_msg("Failed shmat");
66193cad5f7SAneesh Kumar K.V }
66293cad5f7SAneesh Kumar K.V
66393cad5f7SAneesh Kumar K.V map2 = shmat(shmid, NULL, 0);
66493cad5f7SAneesh Kumar K.V if (map2 == (void *) -1) {
66593cad5f7SAneesh Kumar K.V err_msg("Failed shmat");
66693cad5f7SAneesh Kumar K.V }
66793cad5f7SAneesh Kumar K.V
66893cad5f7SAneesh Kumar K.V dir_error = mkdir(logdir, 0755);
66993cad5f7SAneesh Kumar K.V
67093cad5f7SAneesh Kumar K.V if (dir_error) {
67193cad5f7SAneesh Kumar K.V err_msg("Failed mkdir");
67293cad5f7SAneesh Kumar K.V }
67393cad5f7SAneesh Kumar K.V
67493cad5f7SAneesh Kumar K.V printf("start_cpu list:%lu\n", start_cpu);
67593cad5f7SAneesh Kumar K.V printf("number of worker threads:%lu + 1 snapshot thread\n", nrthreads);
67693cad5f7SAneesh Kumar K.V printf("Allocated address:0x%016lx + secondary map:0x%016lx\n", (unsigned long)map1, (unsigned long)map2);
67793cad5f7SAneesh Kumar K.V printf("logdir at : %s\n", logdir);
67893cad5f7SAneesh Kumar K.V printf("Timeout: %d seconds\n", run_time);
67993cad5f7SAneesh Kumar K.V
68093cad5f7SAneesh Kumar K.V time(&now);
68193cad5f7SAneesh Kumar K.V printf("=================================\n");
68293cad5f7SAneesh Kumar K.V printf(" Starting Test\n");
68393cad5f7SAneesh Kumar K.V printf(" %s", ctime(&now));
68493cad5f7SAneesh Kumar K.V printf("=================================\n");
68593cad5f7SAneesh Kumar K.V
68693cad5f7SAneesh Kumar K.V for (i = 0; i < nrthreads; i++) {
68793cad5f7SAneesh Kumar K.V if (1 && !fork()) {
68893cad5f7SAneesh Kumar K.V prctl(PR_SET_PDEATHSIG, SIGKILL);
68993cad5f7SAneesh Kumar K.V set_mycpu(start_cpu + i);
69093cad5f7SAneesh Kumar K.V for (;;)
69193cad5f7SAneesh Kumar K.V sched_yield();
69293cad5f7SAneesh Kumar K.V exit(0);
69393cad5f7SAneesh Kumar K.V }
69493cad5f7SAneesh Kumar K.V }
69593cad5f7SAneesh Kumar K.V
69693cad5f7SAneesh Kumar K.V
69793cad5f7SAneesh Kumar K.V sa_alrm.sa_handler = &alrm_sighandler;
69893cad5f7SAneesh Kumar K.V sigemptyset(&sa_alrm.sa_mask);
69993cad5f7SAneesh Kumar K.V sa_alrm.sa_flags = 0;
70093cad5f7SAneesh Kumar K.V
70193cad5f7SAneesh Kumar K.V if (sigaction(SIGALRM, &sa_alrm, 0) == -1) {
70293cad5f7SAneesh Kumar K.V err_msg("Failed signal handler registration\n");
70393cad5f7SAneesh Kumar K.V }
70493cad5f7SAneesh Kumar K.V
70593cad5f7SAneesh Kumar K.V alarm(run_time);
70693cad5f7SAneesh Kumar K.V
70793cad5f7SAneesh Kumar K.V pthread_attr_init(&attr);
70893cad5f7SAneesh Kumar K.V for (i = 0; i < nrthreads; i++) {
70993cad5f7SAneesh Kumar K.V rim_thread_ids[i] = i;
71093cad5f7SAneesh Kumar K.V pthread_create(&rim_threads[i], &attr, rim_fn, &rim_thread_ids[i]);
71193cad5f7SAneesh Kumar K.V set_pthread_cpu(rim_threads[i], start_cpu + i);
71293cad5f7SAneesh Kumar K.V }
71393cad5f7SAneesh Kumar K.V
71493cad5f7SAneesh Kumar K.V pthread_create(&mem_snapshot_thread, &attr, mem_snapshot_fn, map1);
71593cad5f7SAneesh Kumar K.V set_pthread_cpu(mem_snapshot_thread, start_cpu + i);
71693cad5f7SAneesh Kumar K.V
71793cad5f7SAneesh Kumar K.V
71893cad5f7SAneesh Kumar K.V pthread_join(mem_snapshot_thread, NULL);
71993cad5f7SAneesh Kumar K.V for (i = 0; i < nrthreads; i++) {
72093cad5f7SAneesh Kumar K.V pthread_join(rim_threads[i], NULL);
72193cad5f7SAneesh Kumar K.V }
72293cad5f7SAneesh Kumar K.V
72393cad5f7SAneesh Kumar K.V if (!timeout) {
72493cad5f7SAneesh Kumar K.V time(&now);
72593cad5f7SAneesh Kumar K.V printf("=================================\n");
72693cad5f7SAneesh Kumar K.V printf(" Data Corruption Detected\n");
72793cad5f7SAneesh Kumar K.V printf(" %s", ctime(&now));
72893cad5f7SAneesh Kumar K.V printf(" See logfiles in %s\n", logdir);
72993cad5f7SAneesh Kumar K.V printf("=================================\n");
73093cad5f7SAneesh Kumar K.V return 1;
73193cad5f7SAneesh Kumar K.V }
73293cad5f7SAneesh Kumar K.V return 0;
73393cad5f7SAneesh Kumar K.V }
734