aboutsummaryrefslogtreecommitdiff
path: root/include/lldb/Core/StreamTee.h
blob: 48f92c839481a2d9f54b085c0b05b1ab9faa702a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//===-- StreamTee.h ------------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_StreamTee_h_
#define liblldb_StreamTee_h_

#include <limits.h>

#include <mutex>

#include "lldb/Core/Stream.h"

namespace lldb_private {

class StreamTee : public Stream {
public:
  StreamTee() : Stream(), m_streams_mutex(), m_streams() {}

  StreamTee(lldb::StreamSP &stream_sp)
      : Stream(), m_streams_mutex(), m_streams() {
    // No need to lock mutex during construction
    if (stream_sp)
      m_streams.push_back(stream_sp);
  }

  StreamTee(lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp)
      : Stream(), m_streams_mutex(), m_streams() {
    // No need to lock mutex during construction
    if (stream_sp)
      m_streams.push_back(stream_sp);
    if (stream_2_sp)
      m_streams.push_back(stream_2_sp);
  }

  StreamTee(const StreamTee &rhs)
      : Stream(rhs), m_streams_mutex(), m_streams() {
    // Don't copy until we lock down "rhs"
    std::lock_guard<std::recursive_mutex> guard(rhs.m_streams_mutex);
    m_streams = rhs.m_streams;
  }

  ~StreamTee() override {}

  StreamTee &operator=(const StreamTee &rhs) {
    if (this != &rhs) {
      Stream::operator=(rhs);
      std::lock_guard<std::recursive_mutex> lhs_locker(m_streams_mutex);
      std::lock_guard<std::recursive_mutex> rhs_locker(rhs.m_streams_mutex);
      m_streams = rhs.m_streams;
    }
    return *this;
  }

  void Flush() override {
    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
    collection::iterator pos, end;
    for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
      // Allow for our collection to contain NULL streams. This allows
      // the StreamTee to be used with hard coded indexes for clients
      // that might want N total streams with only a few that are set
      // to valid values.
      Stream *strm = pos->get();
      if (strm)
        strm->Flush();
    }
  }

  size_t Write(const void *s, size_t length) override {
    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
    if (m_streams.empty())
      return 0;

    size_t min_bytes_written = SIZE_MAX;
    collection::iterator pos, end;
    for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) {
      // Allow for our collection to contain NULL streams. This allows
      // the StreamTee to be used with hard coded indexes for clients
      // that might want N total streams with only a few that are set
      // to valid values.
      Stream *strm = pos->get();
      if (strm) {
        const size_t bytes_written = strm->Write(s, length);
        if (min_bytes_written > bytes_written)
          min_bytes_written = bytes_written;
      }
    }
    if (min_bytes_written == SIZE_MAX)
      return 0;
    return min_bytes_written;
  }

  size_t AppendStream(const lldb::StreamSP &stream_sp) {
    size_t new_idx = m_streams.size();
    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
    m_streams.push_back(stream_sp);
    return new_idx;
  }

  size_t GetNumStreams() const {
    size_t result = 0;
    {
      std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
      result = m_streams.size();
    }
    return result;
  }

  lldb::StreamSP GetStreamAtIndex(uint32_t idx) {
    lldb::StreamSP stream_sp;
    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
    if (idx < m_streams.size())
      stream_sp = m_streams[idx];
    return stream_sp;
  }

  void SetStreamAtIndex(uint32_t idx, const lldb::StreamSP &stream_sp) {
    std::lock_guard<std::recursive_mutex> guard(m_streams_mutex);
    // Resize our stream vector as necessary to fit as many streams
    // as needed. This also allows this class to be used with hard
    // coded indexes that can be used contain many streams, not all
    // of which are valid.
    if (idx >= m_streams.size())
      m_streams.resize(idx + 1);
    m_streams[idx] = stream_sp;
  }

protected:
  typedef std::vector<lldb::StreamSP> collection;
  mutable std::recursive_mutex m_streams_mutex;
  collection m_streams;
};

} // namespace lldb_private

#endif // liblldb_StreamTee_h_