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.