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