StreamTee.h revision 317032
148187Skato//===-- StreamTee.h ------------------------------------------*- C++ -*-===// 248516Skato// 348516Skato// The LLVM Compiler Infrastructure 448516Skato// 548516Skato// This file is distributed under the University of Illinois Open Source 648516Skato// License. See LICENSE.TXT for details. 748516Skato// 848516Skato//===----------------------------------------------------------------------===// 948516Skato 1048516Skato#ifndef liblldb_StreamTee_h_ 1148516Skato#define liblldb_StreamTee_h_ 1248516Skato 1348516Skato#include <limits.h> 1448516Skato 1548516Skato#include <mutex> 1648516Skato 1748516Skato#include "lldb/Utility/Stream.h" 1848516Skato 1948516Skatonamespace lldb_private { 2048516Skato 2148516Skatoclass StreamTee : public Stream { 2248516Skatopublic: 2348516Skato StreamTee() : Stream(), m_streams_mutex(), m_streams() {} 2448516Skato 2548516Skato StreamTee(lldb::StreamSP &stream_sp) 2650477Speter : Stream(), m_streams_mutex(), m_streams() { 2748187Skato // No need to lock mutex during construction 2848187Skato if (stream_sp) 2948187Skato m_streams.push_back(stream_sp); 3048187Skato } 3148187Skato 3248187Skato StreamTee(lldb::StreamSP &stream_sp, lldb::StreamSP &stream_2_sp) 3383875Snyan : Stream(), m_streams_mutex(), m_streams() { 3448187Skato // No need to lock mutex during construction 35130070Sphk if (stream_sp) 3683875Snyan m_streams.push_back(stream_sp); 3766870Skato if (stream_2_sp) 3848187Skato m_streams.push_back(stream_2_sp); 3948187Skato } 4048187Skato 4148187Skato StreamTee(const StreamTee &rhs) 4248187Skato : Stream(rhs), m_streams_mutex(), m_streams() { 4348187Skato // Don't copy until we lock down "rhs" 4448187Skato std::lock_guard<std::recursive_mutex> guard(rhs.m_streams_mutex); 4548187Skato m_streams = rhs.m_streams; 4648187Skato } 4748187Skato 4848187Skato ~StreamTee() override {} 4948187Skato 5048187Skato StreamTee &operator=(const StreamTee &rhs) { 5148187Skato if (this != &rhs) { 5248187Skato Stream::operator=(rhs); 5348187Skato std::lock_guard<std::recursive_mutex> lhs_locker(m_streams_mutex); 5448187Skato std::lock_guard<std::recursive_mutex> rhs_locker(rhs.m_streams_mutex); 5548187Skato m_streams = rhs.m_streams; 5648187Skato } 5748187Skato return *this; 5848187Skato } 5948187Skato 6048187Skato void Flush() override { 6148187Skato std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 6248187Skato collection::iterator pos, end; 6348187Skato for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) { 6448187Skato // Allow for our collection to contain NULL streams. This allows 6548187Skato // the StreamTee to be used with hard coded indexes for clients 6648187Skato // that might want N total streams with only a few that are set 6748187Skato // to valid values. 6848187Skato Stream *strm = pos->get(); 6948187Skato if (strm) 7048187Skato strm->Flush(); 7148187Skato } 7248187Skato } 7356337Skato 7448187Skato size_t Write(const void *s, size_t length) override { 7548187Skato std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 7648187Skato if (m_streams.empty()) 7748187Skato return 0; 7848187Skato 7948187Skato size_t min_bytes_written = SIZE_MAX; 8048187Skato collection::iterator pos, end; 8148187Skato for (pos = m_streams.begin(), end = m_streams.end(); pos != end; ++pos) { 8248187Skato // Allow for our collection to contain NULL streams. This allows 8348187Skato // the StreamTee to be used with hard coded indexes for clients 8448187Skato // that might want N total streams with only a few that are set 8548187Skato // to valid values. 8656337Skato Stream *strm = pos->get(); 8748187Skato if (strm) { 8848187Skato const size_t bytes_written = strm->Write(s, length); 8956337Skato if (min_bytes_written > bytes_written) 9056337Skato min_bytes_written = bytes_written; 9148187Skato } 9248187Skato } 9348187Skato if (min_bytes_written == SIZE_MAX) 9448187Skato return 0; 9548187Skato return min_bytes_written; 9648187Skato } 9748187Skato 9848187Skato size_t AppendStream(const lldb::StreamSP &stream_sp) { 9948187Skato size_t new_idx = m_streams.size(); 10048187Skato std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 10148187Skato m_streams.push_back(stream_sp); 10248187Skato return new_idx; 10348187Skato } 10448187Skato 10548187Skato size_t GetNumStreams() const { 10648187Skato size_t result = 0; 10748187Skato { 10848187Skato std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 10948187Skato result = m_streams.size(); 11048187Skato } 11148187Skato return result; 11248187Skato } 11348187Skato 11448187Skato lldb::StreamSP GetStreamAtIndex(uint32_t idx) { 11548187Skato lldb::StreamSP stream_sp; 11648187Skato std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 11748187Skato if (idx < m_streams.size()) 11848187Skato stream_sp = m_streams[idx]; 11948187Skato return stream_sp; 12048187Skato } 12190464Snyan 12248187Skato void SetStreamAtIndex(uint32_t idx, const lldb::StreamSP &stream_sp) { 12390464Snyan std::lock_guard<std::recursive_mutex> guard(m_streams_mutex); 12490464Snyan // Resize our stream vector as necessary to fit as many streams 12590464Snyan // as needed. This also allows this class to be used with hard 12690464Snyan // coded indexes that can be used contain many streams, not all 12790464Snyan // of which are valid. 12890464Snyan if (idx >= m_streams.size()) 12990464Snyan m_streams.resize(idx + 1); 13087886Snyan m_streams[idx] = stream_sp; 13148187Skato } 13248187Skato 13348187Skatoprotected: 13448187Skato typedef std::vector<lldb::StreamSP> collection; 13548187Skato mutable std::recursive_mutex m_streams_mutex; 13648187Skato collection m_streams; 13748187Skato}; 13848187Skato 13948187Skato} // namespace lldb_private 14048187Skato 14148187Skato#endif // liblldb_StreamTee_h_ 14248187Skato