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