tfork: TFORK_ANNOTATE_BENIGN_RACE
authorRalph Boehme <slow@samba.org>
Mon, 19 Nov 2018 22:07:55 +0000 (23:07 +0100)
committerRalph Boehme <slow@samba.org>
Wed, 28 Nov 2018 11:59:27 +0000 (12:59 +0100)
Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
lib/util/tfork.c

index 8ed5811..4a5c08f 100644 (file)
  *   +----------+
  */
 
+#ifdef HAVE_VALGRIND_HELGRIND_H
+#include <valgrind/helgrind.h>
+#endif
+#ifndef ANNOTATE_BENIGN_RACE_SIZED
+#define ANNOTATE_BENIGN_RACE_SIZED(obj, size, description)
+#endif
+
+#define TFORK_ANNOTATE_BENIGN_RACE(obj)                                        \
+       ANNOTATE_BENIGN_RACE_SIZED(                                     \
+               (obj), sizeof(*(obj)),                                  \
+               "no race, serialized by tfork_[un]install_sigchld_handler");
+
 /*
  * The resulting (private) state per tfork_create() call, returned as a opaque
  * handle to the caller.
@@ -221,6 +233,14 @@ static void tfork_atfork_child(void)
        ret = pthread_key_create(&tfork_global_key, tfork_global_destructor);
        assert(ret == 0);
 
+       /*
+        * There's no data race on the cond variable from the signal state, we
+        * are writing here, but there are no readers yet. Some data race
+        * detection tools report a race, but the readers are in the parent
+        * process.
+        */
+       TFORK_ANNOTATE_BENIGN_RACE(&signal_state.cond);
+
        /*
         * There's no way to destroy a condition variable if there are waiters,
         * pthread_cond_destroy() will return EBUSY. Just zero out memory and
@@ -266,6 +286,13 @@ static void tfork_global_initialize(void)
 
        ret = pthread_cond_init(&signal_state.cond, NULL);
        assert(ret == 0);
+
+       /*
+        * In a threaded process there's no data race on t->waiter_pid as
+        * we're serializing globally via tfork_acquire_sighandling() and
+        * tfork_release_sighandling().
+        */
+       TFORK_ANNOTATE_BENIGN_RACE(&signal_state.pid);
 #endif
 
        signal_state.available = true;
@@ -496,6 +523,13 @@ static pid_t tfork_start_waiter_and_worker(struct tfork_state *state,
        if (pid != 0) {
                /* The caller */
 
+               /*
+                * In a threaded process there's no data race on
+                * state->waiter_pid as we're serializing globally via
+                * tfork_acquire_sighandling() and tfork_release_sighandling().
+                */
+               TFORK_ANNOTATE_BENIGN_RACE(&state->waiter_pid);
+
                state->waiter_pid = pid;
 
                close(status_sp_waiter_fd);
@@ -757,6 +791,13 @@ struct tfork *tfork_create(void)
                return t;
        }
 
+       /*
+        * In a threaded process there's no data race on t->waiter_pid as
+        * we're serializing globally via tfork_acquire_sighandling() and
+        * tfork_release_sighandling().
+        */
+       TFORK_ANNOTATE_BENIGN_RACE(&t->waiter_pid);
+
        t->waiter_pid = pid;
        t->worker_pid = state->worker_pid;