1//===-- PThreadEvent.cpp ----------------------------------------*- C++ -*-===//
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//
9// Created by Greg Clayton on 6/16/07.
10//
11//===----------------------------------------------------------------------===//
12
13#include "PThreadEvent.h"
14#include "DNBLog.h"
15#include <cerrno>
16
17PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits)
18 : m_mutex(), m_set_condition(), m_bits(bits), m_validBits(validBits),
19 m_reset_ack_mask(0) {
20 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)",
21 // this, __FUNCTION__, bits, validBits);
22}
23
24PThreadEvent::~PThreadEvent() {
25 // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
26}
27
28uint32_t PThreadEvent::NewEventBit() {
29 // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
30 std::lock_guard<std::mutex> guard(m_mutex);
31 uint32_t mask = 1;
32 while (mask & m_validBits)
33 mask <<= 1;
34 m_validBits |= mask;
35 return mask;
36}
37
38void PThreadEvent::FreeEventBits(const uint32_t mask) {
39 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
40 // __FUNCTION__, mask);
41 if (mask) {
42 std::lock_guard<std::mutex> guard(m_mutex);
43 m_bits &= ~mask;
44 m_validBits &= ~mask;
45 }
46}
47
48uint32_t PThreadEvent::GetEventBits() const {
49 // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION);
50 std::lock_guard<std::mutex> guard(m_mutex);
51 uint32_t bits = m_bits;
52 return bits;
53}
54
55// Replace the event bits with a new bitmask value
56void PThreadEvent::ReplaceEventBits(const uint32_t bits) {
57 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
58 // __FUNCTION__, bits);
59 std::lock_guard<std::mutex> guard(m_mutex);
60 // Make sure we have some bits and that they aren't already set...
61 if (m_bits != bits) {
62 // Figure out which bits are changing
63 uint32_t changed_bits = m_bits ^ bits;
64 // Set the new bit values
65 m_bits = bits;
66 // If any new bits are set, then broadcast
67 if (changed_bits & m_bits)
68 m_set_condition.notify_all();
69 }
70}
71
72// Set one or more event bits and broadcast if any new event bits get set
73// that weren't already set.
74
75void PThreadEvent::SetEvents(const uint32_t mask) {
76 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
77 // __FUNCTION__, mask);
78 // Make sure we have some bits to set
79 if (mask) {
80 std::lock_guard<std::mutex> guard(m_mutex);
81 // Save the old event bit state so we can tell if things change
82 uint32_t old = m_bits;
83 // Set the all event bits that are set in 'mask'
84 m_bits |= mask;
85 // Broadcast only if any extra bits got set.
86 if (old != m_bits)
87 m_set_condition.notify_all();
88 }
89}
90
91// Reset one or more event bits
92void PThreadEvent::ResetEvents(const uint32_t mask) {
93 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this,
94 // __FUNCTION__, mask);
95 if (mask) {
96 std::lock_guard<std::mutex> guard(m_mutex);
97 // Clear the all event bits that are set in 'mask'
98 m_bits &= ~mask;
99 }
100}
101
102static std::chrono::nanoseconds ToDuration(timespec ts) {
103 auto duration =
104 std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec};
105 return std::chrono::duration_cast<std::chrono::nanoseconds>(d: duration);
106}
107
108static std::chrono::time_point<std::chrono::system_clock,
109 std::chrono::nanoseconds>
110ToTimePoint(timespec ts) {
111 return std::chrono::time_point<std::chrono::system_clock,
112 std::chrono::nanoseconds>{
113 std::chrono::duration_cast<std::chrono::system_clock::duration>(
114 d: ToDuration(ts))};
115}
116
117// Wait until 'timeout_abstime' for any events that are set in
118// 'mask'. If 'timeout_abstime' is NULL, then wait forever.
119uint32_t
120PThreadEvent::WaitForEventsImpl(const uint32_t mask,
121 const struct timespec *timeout_abstime,
122 std::function<bool()> predicate) const {
123 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
124 // __FUNCTION__, mask, timeout_abstime);
125 std::unique_lock<std::mutex> lock(m_mutex);
126
127 if (timeout_abstime) {
128 // Wait for condition to get broadcast, or for a timeout. If we get
129 // a timeout we will drop out of the loop on the next iteration and we
130 // will recompute the mask in case of a race between the condition and the
131 // timeout.
132 m_set_condition.wait_until(lock, ToTimePoint(*timeout_abstime), predicate);
133 } else {
134 // Wait for condition to get broadcast.
135 m_set_condition.wait(lock, predicate);
136 }
137
138 // Either the predicate passed, we hit the specified timeout (ETIMEDOUT) or we
139 // encountered an unrecoverable error (EINVAL, EPERM). Regardless of how we
140 // got here, recompute and return the mask indicating which bits (if any) are
141 // set.
142 return GetBitsMasked(mask);
143}
144
145uint32_t
146PThreadEvent::WaitForSetEvents(const uint32_t mask,
147 const struct timespec *timeout_abstime) const {
148 auto predicate = [&]() -> uint32_t { return GetBitsMasked(mask) != 0; };
149 return WaitForEventsImpl(mask, timeout_abstime, predicate);
150}
151
152uint32_t PThreadEvent::WaitForEventsToReset(
153 const uint32_t mask, const struct timespec *timeout_abstime) const {
154 auto predicate = [&]() -> uint32_t { return GetBitsMasked(mask) == 0; };
155 return WaitForEventsImpl(mask, timeout_abstime, predicate);
156}
157
158uint32_t
159PThreadEvent::WaitForResetAck(const uint32_t mask,
160 const struct timespec *timeout_abstime) const {
161 if (mask & m_reset_ack_mask) {
162 // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this,
163 // __FUNCTION__, mask, timeout_abstime);
164 return WaitForEventsToReset(mask: mask & m_reset_ack_mask, timeout_abstime);
165 }
166 return 0;
167}
168

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/tools/debugserver/source/PThreadEvent.cpp