/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Utility/StreamTee.h
Line | Count | Source (jump to first uncovered line) |
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 | | |
18 | | namespace lldb_private { |
19 | | |
20 | | class StreamTee : public Stream { |
21 | | public: |
22 | 187k | 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 | 166 | StreamTee(const StreamTee &rhs) : Stream(rhs) { |
39 | | // Don't copy until we lock down "rhs" |
40 | 166 | std::lock_guard<std::recursive_mutex> guard(rhs.m_streams_mutex); |
41 | 166 | m_streams = rhs.m_streams; |
42 | 166 | } |
43 | | |
44 | 187k | ~StreamTee() override = default; |
45 | | |
46 | 0 | StreamTee &operator=(const StreamTee &rhs) { |
47 | 0 | if (this != &rhs) { |
48 | 0 | Stream::operator=(rhs); |
49 | 0 | std::lock(m_streams_mutex, rhs.m_streams_mutex); |
50 | 0 | std::lock_guard<std::recursive_mutex> lhs_locker(m_streams_mutex, |
51 | 0 | std::adopt_lock); |
52 | 0 | std::lock_guard<std::recursive_mutex> rhs_locker(rhs.m_streams_mutex, |
53 | 0 | std::adopt_lock); |
54 | 0 | m_streams = rhs.m_streams; |
55 | 0 | } |
56 | 0 | return *this; |
57 | 0 | } |
58 | | |
59 | 85 | void Flush() override { |
60 | 85 | std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); |
61 | 85 | collection::iterator pos, end; |
62 | 238 | for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos153 ) { |
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 | 153 | Stream *strm = pos->get(); |
67 | 153 | if (strm) |
68 | 153 | strm->Flush(); |
69 | 153 | } |
70 | 85 | } |
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 | 2.84M | lldb::StreamSP GetStreamAtIndex(uint32_t idx) { |
89 | 2.84M | lldb::StreamSP stream_sp; |
90 | 2.84M | std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); |
91 | 2.84M | if (idx < m_streams.size()) |
92 | 2.60M | stream_sp = m_streams[idx]; |
93 | 2.84M | return stream_sp; |
94 | 2.84M | } |
95 | | |
96 | 4.30k | void SetStreamAtIndex(uint32_t idx, const lldb::StreamSP &stream_sp) { |
97 | 4.30k | 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 | 4.30k | if (idx >= m_streams.size()) |
102 | 4.24k | m_streams.resize(idx + 1); |
103 | 4.30k | m_streams[idx] = stream_sp; |
104 | 4.30k | } |
105 | | |
106 | | protected: |
107 | | typedef std::vector<lldb::StreamSP> collection; |
108 | | mutable std::recursive_mutex m_streams_mutex; |
109 | | collection m_streams; |
110 | | |
111 | 3.23M | size_t WriteImpl(const void *s, size_t length) override { |
112 | 3.23M | std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); |
113 | 3.23M | if (m_streams.empty()) |
114 | 0 | return 0; |
115 | | |
116 | 3.23M | size_t min_bytes_written = SIZE_MAX; |
117 | 3.23M | collection::iterator pos, end; |
118 | 6.47M | for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos3.23M ) { |
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 | 3.23M | Stream *strm = pos->get(); |
123 | 3.23M | if (strm) { |
124 | 3.23M | const size_t bytes_written = strm->Write(s, length); |
125 | 3.23M | if (min_bytes_written > bytes_written) |
126 | 3.23M | min_bytes_written = bytes_written; |
127 | 3.23M | } |
128 | 3.23M | } |
129 | 3.23M | if (min_bytes_written == SIZE_MAX) |
130 | 0 | return 0; |
131 | 3.23M | return min_bytes_written; |
132 | 3.23M | } |
133 | | }; |
134 | | |
135 | | } // namespace lldb_private |
136 | | |
137 | | #endif // LLDB_UTILITY_STREAMTEE_H |