1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef INCLUDE_PERFETTO_PROTOZERO_MESSAGE_HANDLE_H_ 18 #define INCLUDE_PERFETTO_PROTOZERO_MESSAGE_HANDLE_H_ 19 20 #include <functional> 21 22 #include "perfetto/base/export.h" 23 #include "perfetto/protozero/message.h" 24 #include "perfetto/protozero/scattered_stream_writer.h" 25 26 namespace protozero { 27 28 class Message; 29 30 // MessageHandle allows to decouple the lifetime of a proto message 31 // from the underlying storage. It gives the following guarantees: 32 // - The underlying message is finalized (if still alive) if the handle goes 33 // out of scope. 34 // - In Debug / DCHECK_ALWAYS_ON builds, the handle becomes null once the 35 // message is finalized. This is to enforce the append-only API. For instance 36 // when adding two repeated messages, the addition of the 2nd one forces 37 // the finalization of the first. 38 // Think about this as a WeakPtr<Message> which calls 39 // Message::Finalize() when going out of scope. 40 41 class PERFETTO_EXPORT_COMPONENT MessageHandleBase { 42 public: ~MessageHandleBase()43 ~MessageHandleBase() { 44 if (message_) { 45 #if PERFETTO_DCHECK_IS_ON() 46 PERFETTO_DCHECK(generation_ == message_->generation_); 47 #endif 48 FinalizeMessage(); 49 } 50 } 51 52 // Move-only type. MessageHandleBase(MessageHandleBase && other)53 MessageHandleBase(MessageHandleBase&& other) noexcept { 54 Move(std::move(other)); 55 } 56 57 MessageHandleBase& operator=(MessageHandleBase&& other) noexcept { 58 // If the current handle was pointing to a message and is being reset to a 59 // new one, finalize the old message. However, if the other message is the 60 // same as the one we point to, don't finalize. 61 if (message_ && message_ != other.message_) 62 FinalizeMessage(); 63 Move(std::move(other)); 64 return *this; 65 } 66 67 explicit operator bool() const { 68 #if PERFETTO_DCHECK_IS_ON() 69 PERFETTO_DCHECK(!message_ || generation_ == message_->generation_); 70 #endif 71 return !!message_; 72 } 73 74 // Returns a (non-owned, it should not be deleted) pointer to the 75 // ScatteredStreamWriter used to write the message data. The Message becomes 76 // unusable after this point. 77 // 78 // The caller can now write directly, without using protozero::Message. TakeStreamWriter()79 ScatteredStreamWriter* TakeStreamWriter() { 80 ScatteredStreamWriter* stream_writer = message_->stream_writer_; 81 #if PERFETTO_DCHECK_IS_ON() 82 message_->set_handle(nullptr); 83 #endif 84 message_ = nullptr; 85 return stream_writer; 86 } 87 88 protected: message_(message)89 explicit MessageHandleBase(Message* message = nullptr) : message_(message) { 90 #if PERFETTO_DCHECK_IS_ON() 91 generation_ = message_ ? message->generation_ : 0; 92 if (message_) 93 message_->set_handle(this); 94 #endif 95 } 96 97 Message* operator->() const { 98 #if PERFETTO_DCHECK_IS_ON() 99 PERFETTO_DCHECK(!message_ || generation_ == message_->generation_); 100 #endif 101 return message_; 102 } 103 Message& operator*() const { return *(operator->()); } 104 105 private: 106 friend class Message; 107 MessageHandleBase(const MessageHandleBase&) = delete; 108 MessageHandleBase& operator=(const MessageHandleBase&) = delete; 109 reset_message()110 void reset_message() { 111 // This is called by Message::Finalize(). 112 PERFETTO_DCHECK(message_->is_finalized()); 113 message_ = nullptr; 114 } 115 Move(MessageHandleBase && other)116 void Move(MessageHandleBase&& other) { 117 message_ = other.message_; 118 other.message_ = nullptr; 119 #if PERFETTO_DCHECK_IS_ON() 120 if (message_) { 121 generation_ = message_->generation_; 122 message_->set_handle(this); 123 } 124 #endif 125 } 126 FinalizeMessage()127 void FinalizeMessage() { message_->Finalize(); } 128 129 Message* message_; 130 #if PERFETTO_DCHECK_IS_ON() 131 uint32_t generation_; 132 #endif 133 }; 134 135 template <typename T> 136 class MessageHandle : public MessageHandleBase { 137 public: MessageHandle()138 MessageHandle() : MessageHandle(nullptr) {} MessageHandle(T * message)139 explicit MessageHandle(T* message) : MessageHandleBase(message) {} 140 141 explicit operator bool() const { return MessageHandleBase::operator bool(); } 142 143 T& operator*() const { 144 return static_cast<T&>(MessageHandleBase::operator*()); 145 } 146 147 T* operator->() const { 148 return static_cast<T*>(MessageHandleBase::operator->()); 149 } 150 get()151 T* get() const { return static_cast<T*>(MessageHandleBase::operator->()); } 152 }; 153 154 } // namespace protozero 155 156 #endif // INCLUDE_PERFETTO_PROTOZERO_MESSAGE_HANDLE_H_ 157