StreamTee.h revision 360660
1157184Sache//===-- StreamTee.h ------------------------------------------*- C++ -*-===//
2157184Sache//
3157184Sache// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4157184Sache// See https://llvm.org/LICENSE.txt for license information.
5157184Sache// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6157184Sache//
7157184Sache//===----------------------------------------------------------------------===//
8157184Sache
9157184Sache#ifndef liblldb_StreamTee_h_
10157184Sache#define liblldb_StreamTee_h_
11157184Sache
12157184Sache#include <limits.h>
13157184Sache
14157184Sache#include <mutex>
15157184Sache
16157184Sache#include "lldb/Utility/Stream.h"
17157184Sache
18157184Sachenamespace lldb_private {
19157184Sache
20157184Sacheclass StreamTee : public Stream {
21157184Sachepublic:
22157184Sache  StreamTee() : Stream(), m_streams_mutex(), m_streams() {}
23157184Sache
24157184Sache  StreamTee(lldb::StreamSP &stream_sp)
25157184Sache      : Stream(), m_streams_mutex(), m_streams() {
26157184Sache    // No need to lock mutex during construction
27157184Sache    if (stream_sp)
28157184Sache      m_streams.push_back(stream_sp);
29157184Sache  }
30157184Sache
31157184Sache  StreamTee(lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp)
32157184Sache      : Stream(), m_streams_mutex(), m_streams() {
33157184Sache    // No need to lock mutex during construction
34157184Sache    if (stream_sp)
35157184Sache      m_streams.push_back(stream_sp);
36157184Sache    if (stream_2_sp)
37157184Sache      m_streams.push_back(stream_2_sp);
38157184Sache  }
39157184Sache
40157184Sache  StreamTee(const StreamTee &rhs)
41157184Sache      : Stream(rhs), m_streams_mutex(), m_streams() {
42157184Sache    // Don't copy until we lock down "rhs"
43157184Sache    std::lock_guard<std::recursive_mutex> guard(rhs.m_streams_mutex);
44157184Sache    m_streams = rhs.m_streams;
45157184Sache  }
46157184Sache
47157184Sache  ~StreamTee() override {}
48157184Sache
49157184Sache  StreamTee &operator=(const StreamTee &rhs) {
50157184Sache    if (this != &rhs) {
51157184Sache      Stream::operator=(rhs);
52157184Sache      std::lock(m_streams_mutex, rhs.m_streams_mutex);
53157184Sache      std::lock_guard<std::recursive_mutex> lhs_locker(m_streams_mutex,
54157184Sache                                                       std::adopt_lock);
55157184Sache      std::lock_guard<std::recursive_mutex> rhs_locker(rhs.m_streams_mutex,
56157184Sache                                                       std::adopt_lock);
57157184Sache      m_streams = rhs.m_streams;
58157184Sache    }
59157184Sache    return *this;
60157184Sache  }
61157184Sache
62157184Sache  void Flush() override {
63157184Sache    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
64157184Sache    collection::iterator pos, end;
65157184Sache    for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
66157184Sache      // Allow for our collection to contain NULL streams. This allows the
67157184Sache      // StreamTee to be used with hard coded indexes for clients that might
68157184Sache      // want N total streams with only a few that are set to valid values.
69157184Sache      Stream *strm = pos->get();
70157184Sache      if (strm)
71157184Sache        strm->Flush();
72157184Sache    }
73157184Sache  }
74157184Sache
75157184Sache  size_t AppendStream(const lldb::StreamSP &stream_sp) {
76157184Sache    size_t new_idx = m_streams.size();
77157184Sache    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
78157184Sache    m_streams.push_back(stream_sp);
79157184Sache    return new_idx;
80157184Sache  }
81157184Sache
82157184Sache  size_t GetNumStreams() const {
83157184Sache    size_t result = 0;
84157184Sache    {
85157184Sache      std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
86157184Sache      result = m_streams.size();
87157184Sache    }
88157184Sache    return result;
89157184Sache  }
90157184Sache
91157184Sache  lldb::StreamSP GetStreamAtIndex(uint32_t idx) {
92157184Sache    lldb::StreamSP stream_sp;
93157184Sache    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
94157184Sache    if (idx < m_streams.size())
95157184Sache      stream_sp = m_streams[idx];
96157184Sache    return stream_sp;
97157184Sache  }
98157184Sache
99157184Sache  void SetStreamAtIndex(uint32_t idx, const lldb::StreamSP &stream_sp) {
100157184Sache    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
101157184Sache    // Resize our stream vector as necessary to fit as many streams as needed.
102157184Sache    // This also allows this class to be used with hard coded indexes that can
103157184Sache    // be used contain many streams, not all of which are valid.
104157184Sache    if (idx >= m_streams.size())
105157184Sache      m_streams.resize(idx + 1);
106157184Sache    m_streams[idx] = stream_sp;
107157184Sache  }
108157184Sache
109157184Sacheprotected:
110157184Sache  typedef std::vector<lldb::StreamSP> collection;
111157184Sache  mutable std::recursive_mutex m_streams_mutex;
112157184Sache  collection m_streams;
113157184Sache
114157184Sache  size_t WriteImpl(const void *s, size_t length) override {
115157184Sache    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
116157184Sache    if (m_streams.empty())
117157184Sache      return 0;
118157184Sache
119157184Sache    size_t min_bytes_written = SIZE_MAX;
120157184Sache    collection::iterator pos, end;
121157184Sache    for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
122157184Sache      // Allow for our collection to contain NULL streams. This allows the
123157184Sache      // StreamTee to be used with hard coded indexes for clients that might
124157184Sache      // want N total streams with only a few that are set to valid values.
125157184Sache      Stream *strm = pos->get();
126157184Sache      if (strm) {
127157184Sache        const size_t bytes_written = strm->Write(s, length);
128157184Sache        if (min_bytes_written > bytes_written)
129157184Sache          min_bytes_written = bytes_written;
130157184Sache      }
131157184Sache    }
132157184Sache    if (min_bytes_written == SIZE_MAX)
133157184Sache      return 0;
134157184Sache    return min_bytes_written;
135157184Sache  }
136157184Sache};
137157184Sache
138157184Sache} // namespace lldb_private
139157184Sache
140157184Sache#endif // liblldb_StreamTee_h_
141157184Sache