1 /* 2 * Copyright (C) 2018 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 SRC_TRACING_CORE_PATCH_LIST_H_ 18 #define SRC_TRACING_CORE_PATCH_LIST_H_ 19 20 #include <array> 21 #include <forward_list> 22 23 #include "perfetto/base/logging.h" 24 #include "perfetto/ext/tracing/core/basic_types.h" 25 #include "perfetto/ext/tracing/core/shared_memory_abi.h" 26 27 namespace perfetto { 28 29 // Used to handle the backfilling of the headers (the |size_field|) of nested 30 // messages when a proto is fragmented over several chunks. These patches are 31 // sent out-of-band to the tracing service, after having returned the initial 32 // chunks of the fragment. 33 // TODO(crbug.com/904477): Re-disable the move constructors when all usses of 34 // this class have been fixed. 35 class Patch { 36 public: 37 using PatchContent = std::array<uint8_t, SharedMemoryABI::kPacketHeaderSize>; Patch(ChunkID c,uint16_t o)38 Patch(ChunkID c, uint16_t o) : chunk_id(c), offset(o) {} 39 Patch(const Patch&) = default; // For tests. 40 41 const ChunkID chunk_id; 42 const uint16_t offset; 43 PatchContent size_field{}; 44 45 // |size_field| contains a varint. Any varint must start with != 0. Even in 46 // the case we want to encode a size == 0, protozero will write a redundant 47 // varint for that, that is [0x80, 0x80, 0x80, 0x00]. So the first byte is 0 48 // iff we never wrote any varint into that. is_patched()49 bool is_patched() const { return size_field[0] != 0; } 50 51 // For tests. 52 bool operator==(const Patch& o) const { 53 return chunk_id == o.chunk_id && offset == o.offset && 54 size_field == o.size_field; 55 } 56 57 private: 58 Patch& operator=(const Patch&) = delete; 59 }; 60 61 // Note: the protozero::Message(s) will take pointers to the |size_field| of 62 // these entries. This container must guarantee that the Patch objects are never 63 // moved around (i.e. cannot be a vector because of reallocations can change 64 // addresses of pre-existing entries). 65 class PatchList { 66 public: 67 using ListType = std::forward_list<Patch>; 68 using value_type = ListType::value_type; // For gtest. 69 using const_iterator = ListType::const_iterator; // For gtest. 70 PatchList()71 PatchList() : last_(list_.before_begin()) {} 72 emplace_back(ChunkID chunk_id,uint16_t offset)73 Patch* emplace_back(ChunkID chunk_id, uint16_t offset) { 74 last_ = list_.emplace_after(last_, chunk_id, offset); 75 return &*last_; 76 } 77 pop_front()78 void pop_front() { 79 PERFETTO_DCHECK(!list_.empty()); 80 list_.pop_front(); 81 if (empty()) 82 last_ = list_.before_begin(); 83 } 84 front()85 const Patch& front() const { 86 PERFETTO_DCHECK(!list_.empty()); 87 return list_.front(); 88 } 89 back()90 const Patch& back() const { 91 PERFETTO_DCHECK(!list_.empty()); 92 return *last_; 93 } 94 begin()95 ListType::const_iterator begin() const { return list_.begin(); } end()96 ListType::const_iterator end() const { return list_.end(); } empty()97 bool empty() const { return list_.empty(); } 98 99 private: 100 ListType list_; 101 ListType::iterator last_; 102 }; 103 104 } // namespace perfetto 105 106 #endif // SRC_TRACING_CORE_PATCH_LIST_H_ 107