]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Added a regression test called monitor_example.
authorBart Van Assche <bvanassche@acm.org>
Sun, 5 Oct 2008 17:37:06 +0000 (17:37 +0000)
committerBart Van Assche <bvanassche@acm.org>
Sun, 5 Oct 2008 17:37:06 +0000 (17:37 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@8646

drd/tests/Makefile.am
drd/tests/monitor_example.cpp [new file with mode: 0644]
drd/tests/monitor_example.stderr.exp [new file with mode: 0644]
drd/tests/monitor_example.vgtest [new file with mode: 0644]

index bf98e10cc7ea704be3c0690af8f9cfc66f52ae62..2757fc921540b857a7a2a05de8fa55d093edb1d1 100644 (file)
@@ -54,6 +54,8 @@ EXTRA_DIST =                                        \
        matinv.vgtest                               \
        memory_allocation.stderr.exp                \
        memory_allocation.vgtest                    \
+       monitor_example.stderr.exp                  \
+       monitor_example.vgtest                      \
        new_delete.stderr.exp                       \
        new_delete.vgtest                           \
        omp_matinv.stderr.exp                       \
@@ -201,6 +203,7 @@ check_PROGRAMS =      \
   linuxthreads_det    \
   matinv              \
   memory_allocation   \
+  monitor_example     \
   new_delete          \
   pth_barrier         \
   pth_barrier_reinit  \
@@ -291,6 +294,9 @@ matinv_LDADD                = -lpthread -lm
 
 memory_allocation_SOURCES   = memory_allocation.c
 
+monitor_example_SOURCES     = monitor_example.cpp
+monitor_example_LDADD       = -lpthread
+
 new_delete_SOURCES          = new_delete.cpp
 
 pth_barrier_SOURCES         = pth_barrier.c
diff --git a/drd/tests/monitor_example.cpp b/drd/tests/monitor_example.cpp
new file mode 100644 (file)
index 0000000..3984266
--- /dev/null
@@ -0,0 +1,175 @@
+// An example that shows how to implement the monitor synchronization concept.
+// See also http://en.wikipedia.org/wiki/Monitor_(synchronization).
+//
+// Copyright (C) 2008 Bart Van Assche <bart.vanassche@gmail.com>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the Apache License version 2.0
+// (see also http://www.apache.org/licenses/LICENSE-2.0.txt).
+
+
+#define _GNU_SOURCE 1
+
+
+#include <cassert>
+#include <iostream>
+#include <pthread.h>
+
+
+class Monitor
+{
+public:
+  Monitor()
+    : m_mutex()
+    , m_cond()
+    , m_owner()
+    , m_recursion_count()
+  {
+    pthread_mutexattr_t mutexattr;
+    pthread_mutexattr_init(&mutexattr);
+    pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&m_mutex, &mutexattr);
+    pthread_mutexattr_destroy(&mutexattr);
+    pthread_condattr_t condattr;
+    pthread_condattr_init(&condattr);
+    pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
+    pthread_cond_init(&m_cond, 0);
+    pthread_condattr_destroy(&condattr);
+  }
+  ~Monitor()
+  {
+    assert(m_recursion_count == 0);
+    pthread_cond_destroy(&m_cond);
+    pthread_mutex_destroy(&m_mutex);
+  }
+  void lock()
+  {
+    pthread_mutex_lock(&m_mutex);
+    assert(m_recursion_count >= 0);
+    if (++m_recursion_count == 1)
+    {
+      m_owner = pthread_self();
+    }
+  }
+  void unlock()
+  {
+    m_recursion_count--;
+    assert(m_recursion_count >= 0);
+    pthread_mutex_unlock(&m_mutex);
+  }
+  void wait()
+  {
+    assert(m_recursion_count == 1);
+    assert(m_owner == pthread_self());
+    m_recursion_count--;
+    pthread_cond_wait(&m_cond, &m_mutex);
+    m_recursion_count++;
+    m_owner = pthread_self();
+  }
+  void signal()
+  {
+    assert(m_recursion_count > 0);
+    pthread_cond_signal(&m_cond);
+  }
+  void broadcast_signal()
+  {
+    assert(m_recursion_count > 0);
+    pthread_cond_broadcast(&m_cond);
+  }
+  bool is_locked_by_self()
+  {
+    bool result;
+    pthread_mutex_lock(&m_mutex);
+    result = m_recursion_count > 0 && m_owner == pthread_self();
+    pthread_mutex_unlock(&m_mutex);
+    return result;
+  }
+
+private:
+  Monitor(const Monitor&);
+  Monitor& operator=(const Monitor&);
+
+  pthread_mutex_t m_mutex;
+  pthread_cond_t  m_cond;
+  pthread_t       m_owner;
+  int             m_recursion_count;
+};
+
+
+class ScopedLock
+{
+public:
+  ScopedLock(Monitor& m)
+    : m_monitor(m)
+    , m_locked(false)
+  { lock(); }
+  ~ScopedLock()
+  { if (m_locked) unlock(); }
+  void lock()
+  { assert(! m_locked); m_monitor.lock(); m_locked = true; }
+  void unlock()
+  { assert(m_locked); m_locked = false; m_monitor.unlock(); }
+
+private:
+  ScopedLock(const ScopedLock&);
+  ScopedLock& operator=(const ScopedLock&);
+
+  Monitor& m_monitor;
+  bool     m_locked;
+};
+
+
+class StateVariable
+{
+public:
+  StateVariable()
+    : m_state()
+  { }
+  int get()
+  {
+    ScopedLock sl(m_monitor);
+    return m_state;
+  }
+  void set(const int state)
+  {
+    ScopedLock sl(m_monitor);
+    m_state = state;
+    m_monitor.signal();
+  }
+  void wait(const int state)
+  {
+    ScopedLock sl(m_monitor);
+    while (m_state != state)
+      m_monitor.wait();
+  }
+
+private:
+  Monitor m_monitor;
+  int     m_state;
+};
+
+
+static StateVariable s_sv;
+
+
+static void* thread_func(void*)
+{
+  s_sv.wait(1);
+  s_sv.set(2);
+  s_sv.wait(3);
+  s_sv.set(4);
+  return 0;
+}
+
+int main(int, char**)
+{
+  pthread_t tid;
+  pthread_create(&tid, 0, thread_func, 0);
+  s_sv.set(1);
+  s_sv.wait(2);
+  s_sv.set(3);
+  s_sv.wait(4);
+  pthread_join(tid, 0);
+  std::cerr << "Finished successfully.\n";
+  return 0;
+}
diff --git a/drd/tests/monitor_example.stderr.exp b/drd/tests/monitor_example.stderr.exp
new file mode 100644 (file)
index 0000000..a4e94d2
--- /dev/null
@@ -0,0 +1,4 @@
+
+Finished successfully.
+
+ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
diff --git a/drd/tests/monitor_example.vgtest b/drd/tests/monitor_example.vgtest
new file mode 100644 (file)
index 0000000..27264aa
--- /dev/null
@@ -0,0 +1,2 @@
+prereq: ./supported_libpthread
+prog: monitor_example