|
From: Kirill F. <kir...@de...> - 2016-06-09 13:24:45
|
Hello, All!
How can I annotate source code (see below) to stop valgrind's DRD
tool complain about data race?
I think this source doesn't contain any data race, but DRD thinks
otherwise. This is because common synchronization primitives (like
mutexes) not used in this case. The code relies on possibility of CPU
to swap 's' pointer atomically.
See comments in source code below:
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <valgrind/drd.h>
pthread_t t1, t2;
struct S {
int x;
int y;
};
struct S *volatile s;
void *f1(void *arg)
{
ANNOTATE_BENIGN_RACE(&s, "");
(void)arg;
int n=0;
while (1) {
usleep(100000);
if (__sync_fetch_and_add(&s, 0) != 0) continue;
struct S *p=malloc(sizeof(struct S));
assert(p!=NULL);
p->x = ++n; // Conflicts with this line
p->y = ++n; // Conflicts with this line (see below)
p=__sync_lock_test_and_set(&s, p);
__sync_synchronize();
assert(p==NULL);
}
}
void *f2(void *arg)
{
ANNOTATE_BENIGN_RACE(&s, "");
(void)arg;
while (1) {
usleep(150000);
struct S *p=__sync_fetch_and_add(&s, 0);
if (p==NULL) continue;
volatile int z;
z=p->x; // Conflicting load (DRD complains on this lines)
z+=p->y; // Conflicting load
free(p);
__sync_lock_release(&s);
}
}
int main()
{
ANNOTATE_BENIGN_RACE(&s, "");
pthread_create(&t1, NULL, f1, NULL);
pthread_create(&t2, NULL, f2, NULL);
while (1) {
usleep(75000);
printf("%p\n", __sync_fetch_and_add(&s, 0));
}
return 0;
}
Valgrind output is follows:
...
==20829== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
...
==20829== Thread 3:
==20829== Conflicting load by thread 3 at 0x05c0a290 size 4
==20829== at 0x400AF1: f2 (testdrd.c:51)
==20829== by 0x4C3060B: vgDrd_thread_wrapper
(drd_pthread_intercepts.c:477)
==20829== by 0x4E4F453: start_thread (pthread_create.c:334)
==20829== Address 0x5c0a290 is at offset 0 from 0x5c0a290. Allocation
context:
==20829== at 0x4C2D02F: malloc (vg_replace_malloc.c:299)
==20829== by 0x4009EB: f1 (testdrd.c:29)
==20829== by 0x4C3060B: vgDrd_thread_wrapper
(drd_pthread_intercepts.c:477)
==20829== by 0x4E4F453: start_thread (pthread_create.c:334)
==20829== Other segment start (thread 2)
==20829== at 0x514DEA1: clone (in /lib/x86_64-linux-gnu/libc-2.22.so)
==20829== Other segment end (thread 2)
==20829== at 0x511D82D: ??? (in /lib/x86_64-linux-gnu/libc-2.22.so)
==20829== by 0x51473C3: usleep (in
/lib/x86_64-linux-gnu/libc-2.22.so)
==20829== by 0x4009CC: f1 (testdrd.c:26)
==20829== by 0x4C3060B: vgDrd_thread_wrapper
(drd_pthread_intercepts.c:477)
==20829== by 0x4E4F453: start_thread (pthread_create.c:334)
==20829== ==20829== Conflicting load by thread 3 at 0x05c0a294 size 4
==20829== at 0x400AFA: f2 (testdrd.c:52)
==20829== by 0x4C3060B: vgDrd_thread_wrapper
(drd_pthread_intercepts.c:477)
==20829== by 0x4E4F453: start_thread (pthread_create.c:334)
==20829== Address 0x5c0a294 is at offset 4 from 0x5c0a290. Allocation
context:
==20829== at 0x4C2D02F: malloc (vg_replace_malloc.c:299)
==20829== by 0x4009EB: f1 (testdrd.c:29)
==20829== by 0x4C3060B: vgDrd_thread_wrapper
(drd_pthread_intercepts.c:477)
==20829== by 0x4E4F453: start_thread (pthread_create.c:334)
==20829== Other segment start (thread 2)
==20829== at 0x514DEA1: clone (in /lib/x86_64-linux-gnu/libc-2.22.so)
==20829== Other segment end (thread 2)
==20829== at 0x511D82D: ??? (in /lib/x86_64-linux-gnu/libc-2.22.so)
==20829== by 0x51473C3: usleep (in
/lib/x86_64-linux-gnu/libc-2.22.so)
==20829== by 0x4009CC: f1 (testdrd.c:26)
==20829== by 0x4C3060B: vgDrd_thread_wrapper
(drd_pthread_intercepts.c:477)
==20829== by 0x4E4F453: start_thread (pthread_create.c:334)
--
|
|
From: Ivo R. <iv...@iv...> - 2016-06-10 04:49:26
|
2016-06-09 15:24 GMT+02:00 Kirill Frolov <kir...@de...>: > Hello, All! > > How can I annotate source code (see below) to stop valgrind's DRD > tool complain about data race? > > I think this source doesn't contain any data race, but DRD thinks > otherwise. This is because common synchronization primitives (like > mutexes) not used in this case. The code relies on possibility of CPU > to swap 's' pointer atomically. > > You need to help DRD in such cases because as you said you are not using common synchronization primitives. The question is also why? I was not able to discern your intention but it seems to me you are introducing a barrier or a producer-consumer queue. There are efficient POSIX synchronization primitives for these tasks which DRD supports natively. Otherwise use DRD client requests [1] to annotate your intent. Kind regards, I. [1] http://valgrind.org/docs/manual/drd-manual.html#drd-manual.clientreqs |
|
From: Kirill F. <kir...@de...> - 2016-06-10 13:32:14
|
On Fri, Jun 10, 2016 at 06:49:18AM +0200, Ivo Raisr wrote: >> How can I annotate source code (see below) to stop valgrind's DRD >> tool complain about data race? > You need to help DRD in such cases because as you said you are not using > common synchronization primitives. The question is also why? This is just example, how to reproduce DRD warnings. Actually I have much more complicated code. I am trying to use valgrind to find bugs on relatively large project, and I have no idea how to avoid warnings in this case, so I asking about it in mailing list. > I was not able to discern your intention but it seems to me you are > introducing a barrier or a producer-consumer queue. Loop (while(n!=0)...) exists only in example. In real code where is no loops, and should be no delays. Object exists or not (it may be deleted, but it is protected against this with mutex holding in object itself). Initially object not exists (pointer is NULL) and all operations with it should return error. Later object is created, after that pointer is swapped. Now any other threads may use the object (again, object protected from data races with mutex in object). At some point in time object may be destroyed and pointer will be set to zero. The problem is, that valgrind not understood, that after the moment, when pointer is swapped (from NULL to real value), the thread that creates the object not touches object anymore. Valgrind should split its "segment" in moment, when pointer is swapped. But I don't know how to annotate code for that. > There are efficient POSIX synchronization primitives for these tasks > which DRD supports natively. This code uses lockless algorithm (based on possibility to swap pointers atomically), and I didn't want neither change it, nor use algorithms that involve mutexes, conditional variables, etc (because this leads to blocking, because synchronization primitive should be correctly initialized and this leads to initialization order problem in C++ program, because this is "production quality" code and I don't want to change it at all, and much more...) > Otherwise use DRD client requests [1] to annotate your intent. Yes, but I now understood, how should I annotate it. |