1//===-- StreamTee.h ------------------------------------------*- 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#ifndef LLDB_UTILITY_STREAMTEE_H 10#define LLDB_UTILITY_STREAMTEE_H 11 12#include <climits> 13 14#include <mutex> 15 16#include "lldb/Utility/Stream.h" 17 18namespace lldb_private { 19 20class StreamTee : public Stream { 21public: 22 StreamTee(bool colors = false) : Stream(colors) {} 23 24 StreamTee(lldb::StreamSP &stream_sp) { 25 // No need to lock mutex during construction 26 if (stream_sp) 27 m_streams.push_back(stream_sp); 28 } 29 30 StreamTee(lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp) { 31 // No need to lock mutex during construction 32 if (stream_sp) 33 m_streams.push_back(stream_sp); 34 if (stream_2_sp) 35 m_streams.push_back(stream_2_sp); 36 } 37 38 StreamTee(const StreamTee &rhs) : Stream(rhs) { 39 // Don't copy until we lock down "rhs" 40 std::lock_guard<std::recursive_mutex> guard(rhs.m_streams_mutex); 41 m_streams = rhs.m_streams; 42 } 43 44 ~StreamTee() override = default; 45 46 StreamTee &operator=(const StreamTee &rhs) { 47 if (this != &rhs) { 48 Stream::operator=(rhs); 49 std::lock(m_streams_mutex, rhs.m_streams_mutex); 50 std::lock_guard<std::recursive_mutex> lhs_locker(m_streams_mutex, 51 std::adopt_lock); 52 std::lock_guard<std::recursive_mutex> rhs_locker(rhs.m_streams_mutex, 53 std::adopt_lock); 54 m_streams = rhs.m_streams; 55 } 56 return *this; 57 } 58 59 void Flush() override { 60 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 61 collection::iterator pos, end; 62 for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) { 63 // Allow for our collection to contain NULL streams. This allows the 64 // StreamTee to be used with hard coded indexes for clients that might 65 // want N total streams with only a few that are set to valid values. 66 Stream *strm = pos->get(); 67 if (strm) 68 strm->Flush(); 69 } 70 } 71 72 size_t AppendStream(const lldb::StreamSP &stream_sp) { 73 size_t new_idx = m_streams.size(); 74 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 75 m_streams.push_back(stream_sp); 76 return new_idx; 77 } 78 79 size_t GetNumStreams() const { 80 size_t result = 0; 81 { 82 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 83 result = m_streams.size(); 84 } 85 return result; 86 } 87 88 lldb::StreamSP GetStreamAtIndex(uint32_t idx) { 89 lldb::StreamSP stream_sp; 90 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 91 if (idx < m_streams.size()) 92 stream_sp = m_streams[idx]; 93 return stream_sp; 94 } 95 96 void SetStreamAtIndex(uint32_t idx, const lldb::StreamSP &stream_sp) { 97 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 98 // Resize our stream vector as necessary to fit as many streams as needed. 99 // This also allows this class to be used with hard coded indexes that can 100 // be used contain many streams, not all of which are valid. 101 if (idx >= m_streams.size()) 102 m_streams.resize(idx + 1); 103 m_streams[idx] = stream_sp; 104 } 105 106protected: 107 typedef std::vector<lldb::StreamSP> collection; 108 mutable std::recursive_mutex m_streams_mutex; 109 collection m_streams; 110 111 size_t WriteImpl(const void *s, size_t length) override { 112 std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 113 if (m_streams.empty()) 114 return 0; 115 116 size_t min_bytes_written = SIZE_MAX; 117 collection::iterator pos, end; 118 for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) { 119 // Allow for our collection to contain NULL streams. This allows the 120 // StreamTee to be used with hard coded indexes for clients that might 121 // want N total streams with only a few that are set to valid values. 122 Stream *strm = pos->get(); 123 if (strm) { 124 const size_t bytes_written = strm->Write(s, length); 125 if (min_bytes_written > bytes_written) 126 min_bytes_written = bytes_written; 127 } 128 } 129 if (min_bytes_written == SIZE_MAX) 130 return 0; 131 return min_bytes_written; 132 } 133}; 134 135} // namespace lldb_private 136 137#endif // LLDB_UTILITY_STREAMTEE_H 138