• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 class PERFETTO_EXPORT_COMPONENT MessageFinalizationListener {
31  public:
32   virtual ~MessageFinalizationListener();
33   virtual void OnMessageFinalized(Message* message) = 0;
34 };
35 
36 // MessageHandle allows to decouple the lifetime of a proto message
37 // from the underlying storage. It gives the following guarantees:
38 // - The underlying message is finalized (if still alive) if the handle goes
39 //   out of scope.
40 // - In Debug / DCHECK_ALWAYS_ON builds, the handle becomes null once the
41 //   message is finalized. This is to enforce the append-only API. For instance
42 //   when adding two repeated messages, the addition of the 2nd one forces
43 //   the finalization of the first.
44 // Think about this as a WeakPtr<Message> which calls
45 // Message::Finalize() when going out of scope.
46 
47 class PERFETTO_EXPORT_COMPONENT MessageHandleBase {
48  public:
~MessageHandleBase()49   ~MessageHandleBase() {
50     if (message_) {
51 #if PERFETTO_DCHECK_IS_ON()
52       PERFETTO_DCHECK(generation_ == message_->generation_);
53 #endif
54       FinalizeMessage();
55     }
56   }
57 
58   // Move-only type.
MessageHandleBase(MessageHandleBase && other)59   MessageHandleBase(MessageHandleBase&& other) noexcept {
60     Move(std::move(other));
61   }
62 
63   MessageHandleBase& operator=(MessageHandleBase&& other) noexcept {
64     // If the current handle was pointing to a message and is being reset to a
65     // new one, finalize the old message. However, if the other message is the
66     // same as the one we point to, don't finalize.
67     if (message_ && message_ != other.message_)
68       FinalizeMessage();
69     Move(std::move(other));
70     return *this;
71   }
72 
73   explicit operator bool() const {
74 #if PERFETTO_DCHECK_IS_ON()
75     PERFETTO_DCHECK(!message_ || generation_ == message_->generation_);
76 #endif
77     return !!message_;
78   }
79 
set_finalization_listener(MessageFinalizationListener * listener)80   void set_finalization_listener(MessageFinalizationListener* listener) {
81     listener_ = listener;
82   }
83 
84   // Returns a (non-owned, it should not be deleted) pointer to the
85   // ScatteredStreamWriter used to write the message data. The Message becomes
86   // unusable after this point.
87   //
88   // The caller can now write directly, without using protozero::Message.
TakeStreamWriter()89   ScatteredStreamWriter* TakeStreamWriter() {
90     ScatteredStreamWriter* stream_writer = message_->stream_writer_;
91 #if PERFETTO_DCHECK_IS_ON()
92     message_->set_handle(nullptr);
93 #endif
94     message_ = nullptr;
95     listener_ = nullptr;
96     return stream_writer;
97   }
98 
99  protected:
message_(message)100   explicit MessageHandleBase(Message* message = nullptr) : message_(message) {
101 #if PERFETTO_DCHECK_IS_ON()
102     generation_ = message_ ? message->generation_ : 0;
103     if (message_)
104       message_->set_handle(this);
105 #endif
106   }
107 
108   Message* operator->() const {
109 #if PERFETTO_DCHECK_IS_ON()
110     PERFETTO_DCHECK(!message_ || generation_ == message_->generation_);
111 #endif
112     return message_;
113   }
114   Message& operator*() const { return *(operator->()); }
115 
116  private:
117   friend class Message;
118   MessageHandleBase(const MessageHandleBase&) = delete;
119   MessageHandleBase& operator=(const MessageHandleBase&) = delete;
120 
reset_message()121   void reset_message() {
122     // This is called by Message::Finalize().
123     PERFETTO_DCHECK(message_->is_finalized());
124     message_ = nullptr;
125     listener_ = nullptr;
126   }
127 
Move(MessageHandleBase && other)128   void Move(MessageHandleBase&& other) {
129     message_ = other.message_;
130     other.message_ = nullptr;
131     listener_ = other.listener_;
132     other.listener_ = nullptr;
133 #if PERFETTO_DCHECK_IS_ON()
134     if (message_) {
135       generation_ = message_->generation_;
136       message_->set_handle(this);
137     }
138 #endif
139   }
140 
FinalizeMessage()141   void FinalizeMessage() {
142     // |message_| and |listener_| may be cleared by reset_message() during
143     // Message::Finalize().
144     auto* listener = listener_;
145     auto* message = message_;
146     message->Finalize();
147     if (listener)
148       listener->OnMessageFinalized(message);
149   }
150 
151   Message* message_;
152   MessageFinalizationListener* listener_ = nullptr;
153 #if PERFETTO_DCHECK_IS_ON()
154   uint32_t generation_;
155 #endif
156 };
157 
158 template <typename T>
159 class MessageHandle : public MessageHandleBase {
160  public:
MessageHandle()161   MessageHandle() : MessageHandle(nullptr) {}
MessageHandle(T * message)162   explicit MessageHandle(T* message) : MessageHandleBase(message) {}
163 
164   explicit operator bool() const { return MessageHandleBase::operator bool(); }
165 
166   T& operator*() const {
167     return static_cast<T&>(MessageHandleBase::operator*());
168   }
169 
170   T* operator->() const {
171     return static_cast<T*>(MessageHandleBase::operator->());
172   }
173 
get()174   T* get() const { return static_cast<T*>(MessageHandleBase::operator->()); }
175 };
176 
177 }  // namespace protozero
178 
179 #endif  // INCLUDE_PERFETTO_PROTOZERO_MESSAGE_HANDLE_H_
180