brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.9 KiB · e12070c Raw
168 lines · cpp
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-exception6//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 value56void 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 changing63    uint32_t changed_bits = m_bits ^ bits;64    // Set the new bit values65    m_bits = bits;66    // If any new bits are set, then broadcast67    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 set73// 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 set79  if (mask) {80    std::lock_guard<std::mutex> guard(m_mutex);81    // Save the old event bit state so we can tell if things change82    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 bits92void 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>(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          ToDuration(ts))};115}116 117// Wait until 'timeout_abstime' for any events that are set in118// 'mask'. If 'timeout_abstime' is NULL, then wait forever.119uint32_t120PThreadEvent::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 get129    // a timeout we will drop out of the loop on the next iteration and we130    // will recompute the mask in case of a race between the condition and the131    // 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 we139  // encountered an unrecoverable error (EINVAL, EPERM). Regardless of how we140  // got here, recompute and return the mask indicating which bits (if any) are141  // set.142  return GetBitsMasked(mask);143}144 145uint32_t146PThreadEvent::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_t159PThreadEvent::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 & m_reset_ack_mask, timeout_abstime);165  }166  return 0;167}168