On Sun, 4 Jan 2015 11:04:34, Mike Stump wrote: > > Ah, even more curious. So, for testing, it would be best if we had a way to > synchronize the threads so that they reliably can show what you want to show, > and reliably pick which thread will run first and which second and so on. The > problem is of course, the synchronization primitives can’t get in the way (be > seen by) of normal tsan functioning. I’m thinking asm() can so obscure > arbitrary things, but I’m not sure I can’t think of a way to do that with > anything less. sleep is close, and, at least portable and simple. What it > isn’t is bullet proof. The tsan test cases would be enhanced if we could find > a way to synchronize the threads invisibly to tsan. I’d like to think that > someone can propose a better scheme than sleep. My thought would be something > like: > > int order = 0; > > void sync(int i) { > while (++order != i) { /* atomic inc */ > --order; /* atomic dec */ > sleep(1); /* or some type of operative yield */ > } > } > > > > thread 1: > asm (“call sync(1)”); > action1; > asm (“call sync(3)”); > action3; > > thread 2: > > asm (“call sync(2)”); > action2; > > where the order executed would be action1, action2, action3. The asm hides > all details of the synchronization from everyone, optimizer, tsan. > > Now, why go to all this work? Simply, determinism in gcc and the test suite, > is, well, nice. I understand that user programs won’t be so nice, and that in > the wild, it won’t be 100%.
Hmm,,,, that could work.... I would need a way to link the test case two helper functions, that are not compiled with -fsanitize=thread like tsan-helper.C void set(int * a , int b) { *a = b; } int get(int *a) { return *a; } uint64_t Global[2]; int z=0; int get(int*); void set(int*,int); void *Thread1(void *x) { /* We have to sleep here, to make it somewhat easier for tsan to detect the race condition. */ while (get(&z) == 0); Global[1]++; return NULL; } void *Thread2(void *x) { char *p1 = reinterpret_cast<char *>(&Global[0]); struct __attribute__((packed, aligned(1))) u_uint64_t { uint64_t val; }; u_uint64_t *p4 = reinterpret_cast<u_uint64_t *>(p1 + 1); (*p4).val++; set(&z,1); return NULL; } I tried, it and it works 10.000 times without one failure. But I have no idea how to do that in our test framework. Bernd.