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(x: 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(x: stream_sp);
34 if (stream_2_sp)
35 m_streams.push_back(x: 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(l1&: m_streams_mutex, l2&: 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(x: 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(new_size: 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(src: s, src_len: 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

source code of lldb/include/lldb/Utility/StreamTee.h