1 //===-- StreamTee.h ------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef liblldb_StreamTee_h_
11 #define liblldb_StreamTee_h_
12 
13 #include <limits.h>
14 
15 #include "lldb/Core/Stream.h"
16 #include "lldb/Host/Mutex.h"
17 
18 namespace lldb_private {
19 
20 class StreamTee : public Stream
21 {
22 public:
StreamTee()23     StreamTee () :
24         Stream (),
25         m_streams_mutex (Mutex::eMutexTypeRecursive),
26         m_streams ()
27     {
28     }
29 
StreamTee(lldb::StreamSP & stream_sp)30     StreamTee (lldb::StreamSP &stream_sp):
31         Stream (),
32         m_streams_mutex (Mutex::eMutexTypeRecursive),
33         m_streams ()
34     {
35         // No need to lock mutex during construction
36         if (stream_sp)
37             m_streams.push_back (stream_sp);
38     }
39 
40 
StreamTee(lldb::StreamSP & stream_sp,lldb::StreamSP & stream_2_sp)41     StreamTee (lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp) :
42         Stream (),
43         m_streams_mutex (Mutex::eMutexTypeRecursive),
44         m_streams ()
45     {
46         // No need to lock mutex during construction
47         if (stream_sp)
48             m_streams.push_back (stream_sp);
49         if (stream_2_sp)
50             m_streams.push_back (stream_2_sp);
51     }
52 
StreamTee(const StreamTee & rhs)53     StreamTee (const StreamTee &rhs) :
54         Stream (rhs),
55         m_streams_mutex (Mutex::eMutexTypeRecursive),
56         m_streams() // Don't copy until we lock down "rhs"
57     {
58         Mutex::Locker locker (rhs.m_streams_mutex);
59         m_streams = rhs.m_streams;
60     }
61 
62     virtual
~StreamTee()63     ~StreamTee ()
64     {
65     }
66 
67     StreamTee &
68     operator = (const StreamTee &rhs)
69     {
70         if (this != &rhs) {
71             Stream::operator=(rhs);
72             Mutex::Locker lhs_locker (m_streams_mutex);
73             Mutex::Locker rhs_locker (rhs.m_streams_mutex);
74             m_streams = rhs.m_streams;
75         }
76         return *this;
77     }
78 
79     virtual void
Flush()80     Flush ()
81     {
82         Mutex::Locker locker (m_streams_mutex);
83         collection::iterator pos, end;
84         for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
85         {
86             // Allow for our collection to contain NULL streams. This allows
87             // the StreamTee to be used with hard coded indexes for clients
88             // that might want N total streams with only a few that are set
89             // to valid values.
90             Stream *strm = pos->get();
91             if (strm)
92                 strm->Flush ();
93         }
94     }
95 
96     virtual size_t
Write(const void * s,size_t length)97     Write (const void *s, size_t length)
98     {
99         Mutex::Locker locker (m_streams_mutex);
100         if (m_streams.empty())
101             return 0;
102 
103         size_t min_bytes_written = SIZE_MAX;
104         collection::iterator pos, end;
105         for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos)
106         {
107             // Allow for our collection to contain NULL streams. This allows
108             // the StreamTee to be used with hard coded indexes for clients
109             // that might want N total streams with only a few that are set
110             // to valid values.
111             Stream *strm = pos->get();
112             if (strm)
113             {
114                 const size_t bytes_written = strm->Write (s, length);
115                 if (min_bytes_written > bytes_written)
116                     min_bytes_written = bytes_written;
117             }
118         }
119         if (min_bytes_written == SIZE_MAX)
120             return 0;
121         return min_bytes_written;
122     }
123 
124     size_t
AppendStream(const lldb::StreamSP & stream_sp)125     AppendStream (const lldb::StreamSP &stream_sp)
126     {
127         size_t new_idx = m_streams.size();
128         Mutex::Locker locker (m_streams_mutex);
129         m_streams.push_back (stream_sp);
130         return new_idx;
131     }
132 
133     size_t
GetNumStreams()134     GetNumStreams () const
135     {
136         size_t result = 0;
137         {
138             Mutex::Locker locker (m_streams_mutex);
139             result = m_streams.size();
140         }
141         return result;
142     }
143 
144     lldb::StreamSP
GetStreamAtIndex(uint32_t idx)145     GetStreamAtIndex (uint32_t idx)
146     {
147         lldb::StreamSP stream_sp;
148         Mutex::Locker locker (m_streams_mutex);
149         if (idx < m_streams.size())
150             stream_sp = m_streams[idx];
151         return stream_sp;
152     }
153 
154     void
SetStreamAtIndex(uint32_t idx,const lldb::StreamSP & stream_sp)155     SetStreamAtIndex (uint32_t idx, const lldb::StreamSP& stream_sp)
156     {
157         Mutex::Locker locker (m_streams_mutex);
158         // Resize our stream vector as necessary to fit as many streams
159         // as needed. This also allows this class to be used with hard
160         // coded indexes that can be used contain many streams, not all
161         // of which are valid.
162         if (idx >= m_streams.size())
163             m_streams.resize(idx + 1);
164         m_streams[idx] = stream_sp;
165     }
166 
167 
168 protected:
169     typedef std::vector<lldb::StreamSP> collection;
170     mutable Mutex m_streams_mutex;
171     collection m_streams;
172 };
173 
174 } // namespace lldb_private
175 #endif  // #ifndef liblldb_StreamTee_h_
176