LLDB mainline
common/ProcessRunLock.cpp
Go to the documentation of this file.
1//===-- ProcessRunLock.cpp ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10
11#include "llvm/Support/ErrorHandling.h"
12#include "llvm/Support/Threading.h"
13
14#include <cassert>
15#include <cstdint>
16
17namespace lldb_private {
18
19#ifndef _WIN32
20
22 int err = ::pthread_rwlock_init(&m_rwlock, nullptr);
23 (void)err;
24}
25
27 int err = ::pthread_rwlock_destroy(&m_rwlock);
28 (void)err;
29}
30
32 ::pthread_rwlock_rdlock(&m_rwlock);
33 if (!m_running) {
34 // coverity[missing_unlock]
35 return true;
36 }
37 ::pthread_rwlock_unlock(&m_rwlock);
38 return false;
39}
40
42 return ::pthread_rwlock_unlock(&m_rwlock) == 0;
43}
44
46 ::pthread_rwlock_wrlock(&m_rwlock);
47 bool was_stopped = !m_running;
48 m_running = true;
49 ::pthread_rwlock_unlock(&m_rwlock);
50 return was_stopped;
51}
52
54 ::pthread_rwlock_wrlock(&m_rwlock);
55 bool was_running = m_running;
56 m_running = false;
57 ::pthread_rwlock_unlock(&m_rwlock);
58 return was_running;
59}
60
61#endif // !_WIN32
62
64 if (other.m_lock && other.m_thread != llvm::get_threadid())
65 llvm::report_fatal_error(
66 "ProcessRunLocker moved across threads while held");
67 assert(!m_lock && "move-construct into a held ProcessRunLocker");
68 m_lock = other.m_lock;
69 m_thread = other.m_thread;
70 other.m_lock = nullptr;
71}
72
75 if (this != &other) {
76 if (other.m_lock && other.m_thread != llvm::get_threadid())
77 llvm::report_fatal_error(
78 "ProcessRunLocker move-assigned across threads while held");
79 Unlock();
80 m_lock = other.m_lock;
81 m_thread = other.m_thread;
82 other.m_lock = nullptr;
83 }
84 return *this;
85}
86
88 if (m_lock) {
89 if (m_lock == lock)
90 return true;
91 Unlock();
92 }
93 if (!lock)
94 return false;
95
96 const uint64_t this_thread = llvm::get_threadid();
97
98 // Fast path: already holding as a reader on this thread, bump the count.
99 {
100 std::lock_guard<std::mutex> guard(lock->m_recursion_mutex);
101 auto it = lock->m_recursion.find(this_thread);
102 if (it != lock->m_recursion.end()) {
103 ++it->second;
104 m_lock = lock;
105 m_thread = this_thread;
106 return true;
107 }
108 }
109
110 // Acquire the rwlock with m_recursion_mutex released: ReadTryLock can
111 // block waiting for a writer, and holding the recursion mutex through
112 // that wait would stall fast-path bumps that only need the map.
113 if (!lock->ReadTryLock())
114 return false;
115
116 std::lock_guard<std::mutex> guard(lock->m_recursion_mutex);
117 lock->m_recursion[this_thread] = 1;
118 m_lock = lock;
119 m_thread = this_thread;
120 return true;
121}
122
124 if (!m_lock)
125 return;
126
127 const uint64_t this_thread = llvm::get_threadid();
128 if (m_thread != this_thread)
129 // pthread_rwlock_unlock from a different thread than the one that
130 // called pthread_rwlock_rdlock is UB. The move ctor / operator= are
131 // the only way a held locker can change object identity, and both
132 // fatal on cross-thread transfer; this is the last-line check on
133 // the destructor path in case a held locker escaped that trap.
134 llvm::report_fatal_error(
135 "ProcessRunLocker destroyed on a different thread while held");
136
137 bool release_rwlock = false;
138 {
139 std::lock_guard<std::mutex> guard(m_lock->m_recursion_mutex);
140 auto it = m_lock->m_recursion.find(this_thread);
141 assert(
142 it != m_lock->m_recursion.end() &&
143 "ProcessRunLocker released without a matching TryLock on this thread");
144 if (it == m_lock->m_recursion.end()) {
145 m_lock = nullptr;
146 return;
147 }
148 if (--it->second == 0) {
149 m_lock->m_recursion.erase(it);
150 release_rwlock = true;
151 }
152 }
153
154 if (release_rwlock)
155 m_lock->ReadUnlock();
156 m_lock = nullptr;
157}
158
159} // namespace lldb_private
RAII helper around the read-lock side of ProcessRunLock.
ProcessRunLocker & operator=(ProcessRunLocker &&other)
bool TryLock(ProcessRunLock *lock)
Try to acquire the read lock.
bool SetStopped()
Set the process to stopped.
bool SetRunning()
Set the process to running.
llvm::DenseMap< uint64_t, uint32_t > m_recursion
A class that represents a running process on the host machine.