SHARE
TWEET

Chris M Thomasson

a guest Apr 26th, 2009 191 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <relacy/relacy_std.hpp>
  2. #include <cstdio>
  3. #include <cstddef>
  4.  
  5.  
  6.  
  7.  
  8.  
  9. #if ! defined (NDEBUG)
  10. #   define DBG_PRINTF(mp_exp) std::printf mp_exp
  11. #else
  12. #   define DBG_PRINTF(mp_exp) ((void)0)
  13. #endif
  14.  
  15.  
  16.  
  17.  
  18. class eventcount {
  19. public:
  20.   typedef unsigned long key_type;
  21.  
  22.  
  23. private:
  24.   mutable rl::atomic<key_type> m_count;
  25.   rl::mutex m_mutex;
  26.   rl::condition_variable m_cond;
  27.  
  28.  
  29.   void prv_signal(key_type key) {
  30.     if (key & 1) {
  31.       m_mutex.lock($);
  32.       while (! m_count($).compare_exchange_weak(key, (key + 2) & ~1,
  33.         rl::memory_order_seq_cst));
  34.       m_mutex.unlock($);
  35.       m_cond.notify_all($);
  36.     }
  37.   }
  38.  
  39.  
  40. public:
  41.   eventcount() {
  42.     m_count($).store(0, rl::memory_order_relaxed);
  43.   }
  44.  
  45.  
  46. public:
  47.   key_type get() const {
  48.     return m_count($).fetch_or(1, rl::memory_order_acquire);
  49.   }
  50.  
  51.  
  52.   void signal() {
  53.     prv_signal(m_count($).fetch_add(0, rl::memory_order_seq_cst));
  54.   }
  55.  
  56.  
  57.   void signal_relaxed() {
  58.     prv_signal(m_count($).load(rl::memory_order_relaxed));
  59.   }
  60.  
  61.  
  62.   void wait(key_type cmp) {
  63.     m_mutex.lock($);
  64.     if ((m_count($).load(rl::memory_order_seq_cst) & ~1) == (cmp & ~1)) {
  65.       m_cond.wait(m_mutex, $);
  66.     }
  67.     m_mutex.unlock($);
  68.   }
  69. };
  70.  
  71.  
  72.  
  73. class rwmutex {
  74.   enum constant {
  75.     READ_ACCESS = 0x10000,
  76.     WRITE_ACCESS = 1
  77.   };
  78.  
  79.  
  80.   rl::atomic<long> m_next;
  81.   rl::atomic<long> m_current;
  82.   eventcount m_waitset;
  83.  
  84.  
  85. private:
  86.   bool prv_check_read(long ticket) {
  87.     return (ticket == (m_current($).load(rl::memory_order_seq_cst) % READ_ACCESS));
  88.   }
  89.  
  90.  
  91.   bool prv_check_write(long ticket) {
  92.     return (ticket == m_current($).load(rl::memory_order_seq_cst));
  93.   }
  94.  
  95.  
  96. public:
  97.   rwmutex() {
  98.     m_next($).store(0, rl::memory_order_relaxed);
  99.     m_current($).store(0, rl::memory_order_relaxed);
  100.   }
  101.  
  102.  
  103. public:
  104.   void rdlock() {
  105.     long ticket = m_next($).fetch_add(READ_ACCESS, rl::memory_order_seq_cst) % READ_ACCESS;
  106.     while (! prv_check_read(ticket)) {
  107.       eventcount::key_type eckey = m_waitset.get();
  108.       if (prv_check_read(ticket)) return;
  109.       m_waitset.wait(eckey);
  110.     }
  111.   }
  112.  
  113.  
  114.   void rdunlock() {
  115.     m_current($).fetch_add(READ_ACCESS, rl::memory_order_seq_cst);
  116.     //m_waitset.signal_relaxed();
  117.     m_waitset.signal();
  118.   }
  119.  
  120.  
  121. public:
  122.   void wrlock() {
  123.     long ticket = m_next($).fetch_add(WRITE_ACCESS, rl::memory_order_seq_cst);
  124.     while (! prv_check_write(ticket)) {
  125.       eventcount::key_type eckey = m_waitset.get();
  126.       if (prv_check_write(ticket)) return;
  127.       m_waitset.wait(eckey);
  128.     }
  129.   }
  130.  
  131.  
  132.   void wrunlock() {
  133.     m_current($).fetch_add(WRITE_ACCESS, rl::memory_order_seq_cst);
  134.     //m_waitset.signal_relaxed();
  135.     m_waitset.signal();
  136.   }
  137. };
  138.  
  139.  
  140.  
  141.  
  142. #define WRITERS 2
  143. #define READERS 4
  144. #define THREADS (WRITERS + READERS)
  145. #define ITERS 6
  146.  
  147.  
  148.  
  149. struct rwmutex_test : rl::test_suite<rwmutex_test, THREADS> {
  150.  
  151.   rwmutex g_rwmutex;
  152.   rl::var<unsigned> g_state;
  153.   rl::var<unsigned> g_rdtowr;
  154.  
  155.  
  156.   void before() {
  157.     g_state($) = 0;
  158.     g_rdtowr($) = 0;
  159.   }
  160.  
  161.  
  162.   void after() {
  163.     RL_ASSERT(g_state($) + g_rdtowr($) == (WRITERS * ITERS) * 2);
  164.   }  
  165.  
  166.  
  167.   void invariant() {
  168.     RL_ASSERT(g_state($) <= (WRITERS * ITERS) * 2);
  169.     RL_ASSERT(g_rdtowr($) <= (READERS * ITERS) * 2);
  170.   }
  171.  
  172.  
  173.   void thread(unsigned tidx) {
  174.     rl::backoff b;
  175.    
  176.     for (unsigned i = 0; i < ITERS; ++i) {
  177.       if (tidx < WRITERS) {
  178.         g_rwmutex.wrlock();
  179.         ++g_state($);
  180.         b.yield($);
  181.         RL_ASSERT(g_state($) % 2);
  182.         ++g_state($);
  183.         g_rwmutex.wrunlock();
  184.       } else {
  185.         g_rwmutex.rdlock();
  186.         RL_ASSERT(! (g_state($) % 2));
  187.         RL_ASSERT(! (g_rdtowr($) % 2));
  188.         g_rwmutex.rdunlock();
  189.       }
  190.     }
  191.   }
  192. };
  193.  
  194.  
  195.  
  196.  
  197. int main() {
  198.   rl::test_params params;
  199.   params.iteration_count = 9999999;
  200.   rl::simulate<rwmutex_test>(params);
  201.   std::puts("\n\n\n____________________________________\n"
  202.             "DONE!!!!\npress <ENTER> to exit...");
  203.   std::fflush(stdin);
  204.   std::fflush(stdout);
  205.   std::getchar();
  206.   return 0;
  207. }
RAW Paste Data
Top