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/tracing/core/basic_types.h" 25 #include "perfetto/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 PERFETTO_DCHECK(empty() || last_->chunk_id != chunk_id || 75 offset >= last_->offset + sizeof(Patch::PatchContent)); 76 last_ = list_.emplace_after(last_, chunk_id, offset); 77 return &*last_; 78 } 79 pop_front()80 void pop_front() { 81 PERFETTO_DCHECK(!list_.empty()); 82 list_.pop_front(); 83 if (empty()) 84 last_ = list_.before_begin(); 85 } 86 front()87 const Patch& front() const { 88 PERFETTO_DCHECK(!list_.empty()); 89 return list_.front(); 90 } 91 back()92 const Patch& back() const { 93 PERFETTO_DCHECK(!list_.empty()); 94 return *last_; 95 } 96 begin()97 ListType::const_iterator begin() const { return list_.begin(); } end()98 ListType::const_iterator end() const { return list_.end(); } empty()99 bool empty() const { return list_.empty(); } 100 101 private: 102 ListType list_; 103 ListType::iterator last_; 104 }; 105 106 } // namespace perfetto 107 108 #endif // SRC_TRACING_CORE_PATCH_LIST_H_ 109