Mark Wielaard 0e37cf
commit 9abfed23c0d430aafb85de6397d171316c982792
Mark Wielaard 0e37cf
Author: Paul Floyd <pjfloyd@wanadoo.fr>
Mark Wielaard 0e37cf
Date:   Fri Nov 19 08:34:53 2021 +0100
Mark Wielaard 0e37cf
Mark Wielaard 0e37cf
    Bug 445504 Using C++ condition_variable results in bogus "mutex is locked simultaneously by two threads" warning(edit)
Mark Wielaard 0e37cf
    
Mark Wielaard 0e37cf
    Add intercepts for pthread_cond_clockwait to DRD and Helgrind
Mark Wielaard 0e37cf
    Also testcase from bugzilla done by Bart, with configure check
Mark Wielaard 0e37cf
Mark Wielaard 0e37cf
diff --git a/configure.ac b/configure.ac
Mark Wielaard 0e37cf
index e7381f205..cb836dbff 100755
Mark Wielaard 0e37cf
--- a/configure.ac
Mark Wielaard 0e37cf
+++ b/configure.ac
Mark Wielaard 0e37cf
@@ -1989,6 +1989,27 @@ AC_LANG(C)
Mark Wielaard 0e37cf
 
Mark Wielaard 0e37cf
 AM_CONDITIONAL(CXX_CAN_INCLUDE_THREAD_HEADER, test x$ac_cxx_can_include_thread_header = xyes)
Mark Wielaard 0e37cf
 
Mark Wielaard 0e37cf
+# Check whether compiler can process #include <condition_variable> without errors
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+AC_MSG_CHECKING([that C++ compiler can include <condition_variable> header file])
Mark Wielaard 0e37cf
+AC_LANG(C++)
Mark Wielaard 0e37cf
+safe_CXXFLAGS=$CXXFLAGS
Mark Wielaard 0e37cf
+CXXFLAGS=-std=c++0x
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+AC_COMPILE_IFELSE([AC_LANG_SOURCE([
Mark Wielaard 0e37cf
+#include <condition_variable> 
Mark Wielaard 0e37cf
+])],
Mark Wielaard 0e37cf
+[
Mark Wielaard 0e37cf
+ac_cxx_can_include_condition_variable_header=yes
Mark Wielaard 0e37cf
+AC_MSG_RESULT([yes])
Mark Wielaard 0e37cf
+], [
Mark Wielaard 0e37cf
+ac_cxx_can_include_condition_variable_header=no
Mark Wielaard 0e37cf
+AC_MSG_RESULT([no])
Mark Wielaard 0e37cf
+])
Mark Wielaard 0e37cf
+CXXFLAGS=$safe_CXXFLAGS
Mark Wielaard 0e37cf
+AC_LANG(C)
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+AM_CONDITIONAL(CXX_CAN_INCLUDE_CONDITION_VARIABLE_HEADER, test x$ac_cxx_can_include_condition_variable_header = xyes)
Mark Wielaard 0e37cf
 
Mark Wielaard 0e37cf
 # On aarch64 before glibc 2.20 we would get the kernel user_pt_regs instead
Mark Wielaard 0e37cf
 # of the user_regs_struct from sys/user.h. They are structurally the same
Mark Wielaard 0e37cf
diff --git a/drd/drd_pthread_intercepts.c b/drd/drd_pthread_intercepts.c
Mark Wielaard 0e37cf
index 8b4454364..95127b42c 100644
Mark Wielaard 0e37cf
--- a/drd/drd_pthread_intercepts.c
Mark Wielaard 0e37cf
+++ b/drd/drd_pthread_intercepts.c
Mark Wielaard 0e37cf
@@ -1175,6 +1175,30 @@ PTH_FUNCS(int, condZureltimedwait, pthread_cond_timedwait_intercept,
Mark Wielaard 0e37cf
           (cond, mutex, timeout));
Mark Wielaard 0e37cf
 #endif /* VGO_solaris */
Mark Wielaard 0e37cf
 
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+static __always_inline
Mark Wielaard 0e37cf
+int pthread_cond_clockwait_intercept(pthread_cond_t *cond,
Mark Wielaard 0e37cf
+                                     pthread_mutex_t *mutex,
Mark Wielaard 0e37cf
+                                     clockid_t clockid,
Mark Wielaard 0e37cf
+                                     const struct timespec* abstime)
Mark Wielaard 0e37cf
+{
Mark Wielaard 0e37cf
+   int   ret;
Mark Wielaard 0e37cf
+   OrigFn fn;
Mark Wielaard 0e37cf
+   VALGRIND_GET_ORIG_FN(fn);
Mark Wielaard 0e37cf
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__PRE_COND_WAIT,
Mark Wielaard 0e37cf
+                                   cond, mutex, DRD_(mutex_type)(mutex), 0, 0);
Mark Wielaard 0e37cf
+   CALL_FN_W_WWWW(ret, fn, cond, mutex, clockid, abstime);
Mark Wielaard 0e37cf
+   VALGRIND_DO_CLIENT_REQUEST_STMT(VG_USERREQ__POST_COND_WAIT,
Mark Wielaard 0e37cf
+                                   cond, mutex, 1, 0, 0);
Mark Wielaard 0e37cf
+   return ret;
Mark Wielaard 0e37cf
+}
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+PTH_FUNCS(int, pthreadZucondZuclockwait, pthread_cond_clockwait_intercept,
Mark Wielaard 0e37cf
+          (pthread_cond_t *cond, pthread_mutex_t *mutex,
Mark Wielaard 0e37cf
+            clockid_t clockid, const struct timespec* abstime),
Mark Wielaard 0e37cf
+          (cond, mutex, clockid, abstime));
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
 // NOTE: be careful to intercept only pthread_cond_signal() and not Darwin's
Mark Wielaard 0e37cf
 // pthread_cond_signal_thread_np(). The former accepts one argument; the latter
Mark Wielaard 0e37cf
 // two. Intercepting all pthread_cond_signal* functions will cause only one
Mark Wielaard 0e37cf
diff --git a/drd/tests/Makefile.am b/drd/tests/Makefile.am
Mark Wielaard 0e37cf
index 4cb2f7f84..c804391e8 100755
Mark Wielaard 0e37cf
--- a/drd/tests/Makefile.am
Mark Wielaard 0e37cf
+++ b/drd/tests/Makefile.am
Mark Wielaard 0e37cf
@@ -105,6 +105,8 @@ EXTRA_DIST =                                        \
Mark Wielaard 0e37cf
 	circular_buffer.vgtest			    \
Mark Wielaard 0e37cf
 	concurrent_close.stderr.exp		    \
Mark Wielaard 0e37cf
 	concurrent_close.vgtest			    \
Mark Wielaard 0e37cf
+	condvar.stderr.exp			    \
Mark Wielaard 0e37cf
+	condvar.vgtest				    \
Mark Wielaard 0e37cf
 	custom_alloc.stderr.exp			    \
Mark Wielaard 0e37cf
 	custom_alloc.vgtest			    \
Mark Wielaard 0e37cf
 	custom_alloc_fiw.stderr.exp		    \
Mark Wielaard 0e37cf
@@ -458,6 +460,11 @@ check_PROGRAMS += \
Mark Wielaard 0e37cf
 endif
Mark Wielaard 0e37cf
 endif
Mark Wielaard 0e37cf
 
Mark Wielaard 0e37cf
+if CXX_CAN_INCLUDE_CONDITION_VARIABLE_HEADER
Mark Wielaard 0e37cf
+check_PROGRAMS += \
Mark Wielaard 0e37cf
+    condvar
Mark Wielaard 0e37cf
+endif
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
 if HAVE_OPENMP
Mark Wielaard 0e37cf
 check_PROGRAMS += omp_matinv omp_prime omp_printf
Mark Wielaard 0e37cf
 endif
Mark Wielaard 0e37cf
@@ -502,6 +509,8 @@ LDADD = -lpthread
Mark Wielaard 0e37cf
 
Mark Wielaard 0e37cf
 
Mark Wielaard 0e37cf
 bug322621_SOURCES           = bug322621.cpp
Mark Wielaard 0e37cf
+condvar_SOURCES		    = condvar.cpp
Mark Wielaard 0e37cf
+condvar_CXXFLAGS            = $(AM_CXXFLAGS) -std=c++0x
Mark Wielaard 0e37cf
 concurrent_close_SOURCES    = concurrent_close.cpp
Mark Wielaard 0e37cf
 if !VGCONF_OS_IS_FREEBSD
Mark Wielaard 0e37cf
 dlopen_main_LDADD           = -ldl
Mark Wielaard 0e37cf
diff --git a/drd/tests/condvar.cpp b/drd/tests/condvar.cpp
Mark Wielaard 0e37cf
new file mode 100644
Mark Wielaard 0e37cf
index 000000000..18ecb3f8a
Mark Wielaard 0e37cf
--- /dev/null
Mark Wielaard 0e37cf
+++ b/drd/tests/condvar.cpp
Mark Wielaard 0e37cf
@@ -0,0 +1,55 @@
Mark Wielaard 0e37cf
+/* See also https://bugs.kde.org/show_bug.cgi?id=445504 */
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+#include <condition_variable>
Mark Wielaard 0e37cf
+#include <future>
Mark Wielaard 0e37cf
+#include <iostream>
Mark Wielaard 0e37cf
+#include <mutex>
Mark Wielaard 0e37cf
+#include <thread>
Mark Wielaard 0e37cf
+#include <vector>
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+using lock_guard = std::lock_guard<std::mutex>;
Mark Wielaard 0e37cf
+using unique_lock = std::unique_lock<std::mutex>;
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+struct state {
Mark Wielaard 0e37cf
+  std::mutex m;
Mark Wielaard 0e37cf
+  std::vector<int> v;
Mark Wielaard 0e37cf
+  std::condition_variable cv;
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+  state() {
Mark Wielaard 0e37cf
+    // Call pthread_cond_init() explicitly to let DRD know about 'cv'.
Mark Wielaard 0e37cf
+    pthread_cond_init(cv.native_handle(), NULL);
Mark Wielaard 0e37cf
+  }
Mark Wielaard 0e37cf
+};
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+void other_thread(state *sp) {
Mark Wielaard 0e37cf
+  state &s = *sp;
Mark Wielaard 0e37cf
+  std::cerr << "Other thread: waiting for notify\n";
Mark Wielaard 0e37cf
+  unique_lock l{s.m};
Mark Wielaard 0e37cf
+  while (true) {
Mark Wielaard 0e37cf
+    if (s.cv.wait_for(l, std::chrono::seconds(3)) !=
Mark Wielaard 0e37cf
+	std::cv_status::timeout) {
Mark Wielaard 0e37cf
+      std::cerr << "Other thread: notified\n";
Mark Wielaard 0e37cf
+      break;
Mark Wielaard 0e37cf
+    }
Mark Wielaard 0e37cf
+  }
Mark Wielaard 0e37cf
+  return;
Mark Wielaard 0e37cf
+}
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+int main() {
Mark Wielaard 0e37cf
+  state s;
Mark Wielaard 0e37cf
+  auto future = std::async(std::launch::async, other_thread, &s);
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+  if (future.wait_for(std::chrono::seconds(1)) != std::future_status::timeout) {
Mark Wielaard 0e37cf
+    std::cerr << "Main: other thread returned too early!\n";
Mark Wielaard 0e37cf
+    return 2;
Mark Wielaard 0e37cf
+  }
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+  {
Mark Wielaard 0e37cf
+    std::lock_guard<std::mutex> g{s.m};
Mark Wielaard 0e37cf
+    s.v.push_back(1);
Mark Wielaard 0e37cf
+    s.v.push_back(2);
Mark Wielaard 0e37cf
+    s.cv.notify_all();
Mark Wielaard 0e37cf
+  }
Mark Wielaard 0e37cf
+  return 0;
Mark Wielaard 0e37cf
+}
Mark Wielaard 0e37cf
diff --git a/drd/tests/condvar.stderr.exp b/drd/tests/condvar.stderr.exp
Mark Wielaard 0e37cf
new file mode 100644
Mark Wielaard 0e37cf
index 000000000..be1de9f97
Mark Wielaard 0e37cf
--- /dev/null
Mark Wielaard 0e37cf
+++ b/drd/tests/condvar.stderr.exp
Mark Wielaard 0e37cf
@@ -0,0 +1,5 @@
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+Other thread: waiting for notify
Mark Wielaard 0e37cf
+Other thread: notified
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Mark Wielaard 0e37cf
diff --git a/drd/tests/condvar.vgtest b/drd/tests/condvar.vgtest
Mark Wielaard 0e37cf
new file mode 100644
Mark Wielaard 0e37cf
index 000000000..2e7d49f5a
Mark Wielaard 0e37cf
--- /dev/null
Mark Wielaard 0e37cf
+++ b/drd/tests/condvar.vgtest
Mark Wielaard 0e37cf
@@ -0,0 +1,3 @@
Mark Wielaard 0e37cf
+prereq: ./supported_libpthread && [ -e condvar ]
Mark Wielaard 0e37cf
+vgopts: --check-stack-var=yes --read-var-info=yes
Mark Wielaard 0e37cf
+prog: condvar
Mark Wielaard 0e37cf
diff --git a/helgrind/hg_intercepts.c b/helgrind/hg_intercepts.c
Mark Wielaard 0e37cf
index 866efdbaa..49c3ddcd9 100644
Mark Wielaard 0e37cf
--- a/helgrind/hg_intercepts.c
Mark Wielaard 0e37cf
+++ b/helgrind/hg_intercepts.c
Mark Wielaard 0e37cf
@@ -1409,6 +1409,88 @@ static int pthread_cond_timedwait_WRK(pthread_cond_t* cond,
Mark Wielaard 0e37cf
 #  error "Unsupported OS"
Mark Wielaard 0e37cf
 #endif
Mark Wielaard 0e37cf
 
Mark Wielaard 0e37cf
+//-----------------------------------------------------------
Mark Wielaard 0e37cf
+// glibc:   pthread_cond_clockwait
Mark Wielaard 0e37cf
+//
Mark Wielaard 0e37cf
+__attribute__((noinline))
Mark Wielaard 0e37cf
+static int pthread_cond_clockwait_WRK(pthread_cond_t* cond,
Mark Wielaard 0e37cf
+                                      pthread_mutex_t* mutex,
Mark Wielaard 0e37cf
+                                      clockid_t clockid,
Mark Wielaard 0e37cf
+                                      struct timespec* abstime,
Mark Wielaard 0e37cf
+                                      int timeout_error)
Mark Wielaard 0e37cf
+{
Mark Wielaard 0e37cf
+   int ret;
Mark Wielaard 0e37cf
+   OrigFn fn;
Mark Wielaard 0e37cf
+   unsigned long mutex_is_valid;
Mark Wielaard 0e37cf
+   Bool abstime_is_valid;
Mark Wielaard 0e37cf
+   VALGRIND_GET_ORIG_FN(fn);
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   if (TRACE_PTH_FNS) {
Mark Wielaard 0e37cf
+      fprintf(stderr, "<< pthread_cond_clockwait %p %p %p",
Mark Wielaard 0e37cf
+                      cond, mutex, abstime);
Mark Wielaard 0e37cf
+      fflush(stderr);
Mark Wielaard 0e37cf
+   }
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   /* Tell the tool a cond-wait is about to happen, so it can check
Mark Wielaard 0e37cf
+      for bogus argument values.  In return it tells us whether it
Mark Wielaard 0e37cf
+      thinks the mutex is valid or not. */
Mark Wielaard 0e37cf
+   DO_CREQ_W_WW(mutex_is_valid,
Mark Wielaard 0e37cf
+                _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE,
Mark Wielaard 0e37cf
+                pthread_cond_t*,cond, pthread_mutex_t*,mutex);
Mark Wielaard 0e37cf
+   assert(mutex_is_valid == 1 || mutex_is_valid == 0);
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   abstime_is_valid = abstime->tv_nsec >= 0 && abstime->tv_nsec < 1000000000;
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   /* Tell the tool we're about to drop the mutex.  This reflects the
Mark Wielaard 0e37cf
+      fact that in a cond_wait, we show up holding the mutex, and the
Mark Wielaard 0e37cf
+      call atomically drops the mutex and waits for the cv to be
Mark Wielaard 0e37cf
+      signalled. */
Mark Wielaard 0e37cf
+   if (mutex_is_valid && abstime_is_valid) {
Mark Wielaard 0e37cf
+      DO_CREQ_v_W(_VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE,
Mark Wielaard 0e37cf
+                  pthread_mutex_t*,mutex);
Mark Wielaard 0e37cf
+   }
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   CALL_FN_W_WWWW(ret, fn, cond,mutex,clockid,abstime);
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   if (mutex_is_valid && !abstime_is_valid && ret != EINVAL) {
Mark Wielaard 0e37cf
+      DO_PthAPIerror("Bug in libpthread: pthread_cond_clockwait "
Mark Wielaard 0e37cf
+                     "invalid abstime did not cause"
Mark Wielaard 0e37cf
+                     " EINVAL", ret);
Mark Wielaard 0e37cf
+   }
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   if (mutex_is_valid && abstime_is_valid) {
Mark Wielaard 0e37cf
+      /* and now we have the mutex again if (ret == 0 || ret == timeout) */
Mark Wielaard 0e37cf
+      DO_CREQ_v_WW(_VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST,
Mark Wielaard 0e37cf
+                   pthread_mutex_t *, mutex,
Mark Wielaard 0e37cf
+                   long, (ret == 0 || ret == timeout_error) ? True : False);
Mark Wielaard 0e37cf
+   }
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   DO_CREQ_v_WWWW(_VG_USERREQ__HG_PTHREAD_COND_WAIT_POST,
Mark Wielaard 0e37cf
+                  pthread_cond_t*,cond, pthread_mutex_t*,mutex,
Mark Wielaard 0e37cf
+                  long,ret == timeout_error,
Mark Wielaard 0e37cf
+                  long, (ret == 0 || ret == timeout_error) && mutex_is_valid
Mark Wielaard 0e37cf
+                        ? True : False);
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   if (ret != 0 && ret != timeout_error) {
Mark Wielaard 0e37cf
+      DO_PthAPIerror( "pthread_cond_clockwait", ret );
Mark Wielaard 0e37cf
+   }
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   if (TRACE_PTH_FNS) {
Mark Wielaard 0e37cf
+      fprintf(stderr, " cotimedwait -> %d >>\n", ret);
Mark Wielaard 0e37cf
+   }
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+   return ret;
Mark Wielaard 0e37cf
+}
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
+#if defined(VGO_linux)
Mark Wielaard 0e37cf
+   PTH_FUNC(int, pthreadZucondZuclockwait, // pthread_cond_clockwait
Mark Wielaard 0e37cf
+                 pthread_cond_t* cond, pthread_mutex_t* mutex,
Mark Wielaard 0e37cf
+                 clockid_t clockid,
Mark Wielaard 0e37cf
+                 struct timespec* abstime) {
Mark Wielaard 0e37cf
+      return pthread_cond_clockwait_WRK(cond, mutex, clockid, abstime, ETIMEDOUT);
Mark Wielaard 0e37cf
+   }
Mark Wielaard 0e37cf
+#endif
Mark Wielaard 0e37cf
+
Mark Wielaard 0e37cf
 
Mark Wielaard 0e37cf
 //-----------------------------------------------------------
Mark Wielaard 0e37cf
 // glibc:   pthread_cond_signal@GLIBC_2.0