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