gem5  v21.1.0.2
uncontended_mutex.hh
Go to the documentation of this file.
1 /*
2  * Copyright 2020 Google, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met: redistributions of source code must retain the above copyright
7  * notice, this list of conditions and the following disclaimer;
8  * redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution;
11  * neither the name of the copyright holders nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #ifndef __BASE_UNCONTENDED_MUTEX_HH__
29 #define __BASE_UNCONTENDED_MUTEX_HH__
30 
31 #include <atomic>
32 #include <condition_variable>
33 #include <mutex>
34 
35 namespace gem5
36 {
37 
38 /*
39  * The std::mutex implementation is slower than expected because of many mode
40  * checking and legacy support.
41  *
42  * The UncontendedMutex uses an atomic flag to check if we really need to
43  * obtain a mutex lock. For most cases without multi-threads event queues,
44  * e.g. non-KVM simulation, this avoid the usage of mutex and speed up the
45  * simulation.
46  */
48 {
49  private:
50  /*
51  * A flag to record the current status:
52  * 0: no one has the lock
53  * 1: exactly one thread has the lock
54  * >1: one or more threads are waiting for the lock
55  */
56  std::atomic<int> flag;
57  std::mutex m;
58  std::condition_variable cv;
59 
60  bool
61  testAndSet(int expected, int desired)
62  {
63  return flag.compare_exchange_strong(expected, desired);
64  }
65 
66  public:
68 
69  void
70  lock()
71  {
72  /*
73  * Here we use 'flag' to check if we are the first thread to get the
74  * lock. If not, we try to obtain the real mutex, and use the condition
75  * variable to wait for the thread who has the lock to release it.
76  *
77  * The flag will be updated to more than 1, so the thread with lock
78  * knows that there is another thread waiting for the lock.
79  */
80  while (!testAndSet(0, 1)) {
81  std::unique_lock<std::mutex> ul(m);
82  /*
83  * It is possible that just before we obtain the mutex lock, the
84  * first thread releases the flag and thus flag becomes zero. In
85  * such case, we shouldn't wait for the condition variable because
86  * there is no the other thread to notify us.
87  */
88  if (flag++ == 0)
89  break;
90  cv.wait(ul);
91  }
92  }
93 
94  void
96  {
97  /* In case there are no other threads waiting, we will just clear the
98  * flag and return.
99  */
100  if (testAndSet(1, 0))
101  return;
102 
103  /*
104  * Otherwise, clear the flag and notify all the waiting threads. We
105  * need to protect the flag by mutex here so that there won't be
106  * another thread waiting but the flag is already set to 0.
107  */
108  {
109  std::lock_guard<std::mutex> g(m);
110  flag = 0;
111  }
112  /*
113  * It's possible to update the algorithm and use notify_one() here.
114  * However, tests show that notify_one() is much slower than
115  * notify_all() in this case. Here we choose to use notify_all().
116  */
117  cv.notify_all();
118  }
119 };
120 
121 } // namespace gem5
122 
123 #endif // __BASE_UNCONTENDED_MUTEX_HH__
gem5::UncontendedMutex
Definition: uncontended_mutex.hh:47
gem5::UncontendedMutex::lock
void lock()
Definition: uncontended_mutex.hh:70
gem5::UncontendedMutex::m
std::mutex m
Definition: uncontended_mutex.hh:57
gem5::UncontendedMutex::flag
std::atomic< int > flag
Definition: uncontended_mutex.hh:56
gem5::MipsISA::g
Bitfield< 4 > g
Definition: dt_constants.hh:86
gem5::UncontendedMutex::cv
std::condition_variable cv
Definition: uncontended_mutex.hh:58
gem5::UncontendedMutex::UncontendedMutex
UncontendedMutex()
Definition: uncontended_mutex.hh:67
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: decoder.cc:40
gem5::UncontendedMutex::testAndSet
bool testAndSet(int expected, int desired)
Definition: uncontended_mutex.hh:61
expected
std::vector< SwitchingFiber * > expected({ &a, &b, &a, &a, &a, &b, &c, &a, &c, &c, &c })
gem5::UncontendedMutex::unlock
void unlock()
Definition: uncontended_mutex.hh:95

Generated on Tue Sep 21 2021 12:25:00 for gem5 by doxygen 1.8.17