summaryrefslogtreecommitdiffstats
path: root/comm/third_party/botan/src/lib/utils/thread_utils/rwlock.cpp
blob: 58500a83de731902880d52241aba3e86a64b6778 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/*
* (C) 2019 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/internal/rwlock.h>

namespace Botan {

RWLock::RWLock() : m_state(0) {}

void RWLock::lock()
   {
   std::unique_lock<std::mutex> lock(m_mutex);
   while(m_state & is_writing)
      m_gate1.wait(lock);
   m_state |= is_writing;
   while(m_state & readers_mask)
      m_gate2.wait(lock);
   }

void RWLock::unlock()
   {
   std::unique_lock<std::mutex> lock(m_mutex);
   m_state = 0;
   m_gate1.notify_all();
   }

void RWLock::lock_shared()
   {
   std::unique_lock<std::mutex> lock(m_mutex);
   while((m_state & is_writing) || (m_state & readers_mask) == readers_mask)
      m_gate1.wait(lock);
   const uint32_t num_readers = (m_state & readers_mask) + 1;
   m_state &= ~readers_mask;
   m_state |= num_readers;
   }

void RWLock::unlock_shared()
   {
   std::unique_lock<std::mutex> lock(m_mutex);
   const uint32_t num_readers = (m_state & readers_mask) - 1;
   m_state &= ~readers_mask;
   m_state |= num_readers;
   if(m_state & is_writing)
      {
      if(num_readers == 0)
         m_gate2.notify_one();
      }
   else
      {
      if(num_readers == readers_mask - 1)
         m_gate1.notify_one();
      }
   }

}