1 //===-- xray_buffer_queue.h ------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of XRay, a dynamic runtime instrumentation system. 11 // 12 // Defines the interface for a buffer queue implementation. 13 // 14 //===----------------------------------------------------------------------===// 15 #ifndef XRAY_BUFFER_QUEUE_H 16 #define XRAY_BUFFER_QUEUE_H 17 18 #include <cstddef> 19 #include "sanitizer_common/sanitizer_atomic.h" 20 #include "sanitizer_common/sanitizer_mutex.h" 21 22 namespace __xray { 23 24 /// BufferQueue implements a circular queue of fixed sized buffers (much like a 25 /// freelist) but is concerned mostly with making it really quick to initialise, 26 /// finalise, and get/return buffers to the queue. This is one key component of 27 /// the "flight data recorder" (FDR) mode to support ongoing XRay function call 28 /// trace collection. 29 class BufferQueue { 30 public: 31 struct Buffer { 32 void *Buffer = nullptr; 33 size_t Size = 0; 34 }; 35 36 private: 37 struct BufferRep { 38 // The managed buffer. 39 Buffer Buff; 40 41 // This is true if the buffer has been returned to the available queue, and 42 // is considered "used" by another thread. 43 bool Used = false; 44 }; 45 46 // Size of each individual Buffer. 47 size_t BufferSize; 48 49 BufferRep *Buffers; 50 size_t BufferCount; 51 52 __sanitizer::SpinMutex Mutex; 53 __sanitizer::atomic_uint8_t Finalizing; 54 55 // Pointers to buffers managed/owned by the BufferQueue. 56 void **OwnedBuffers; 57 58 // Pointer to the next buffer to be handed out. 59 BufferRep *Next; 60 61 // Pointer to the entry in the array where the next released buffer will be 62 // placed. 63 BufferRep *First; 64 65 // Count of buffers that have been handed out through 'getBuffer'. 66 size_t LiveBuffers; 67 68 public: 69 enum class ErrorCode : unsigned { 70 Ok, 71 NotEnoughMemory, 72 QueueFinalizing, 73 UnrecognizedBuffer, 74 AlreadyFinalized, 75 }; 76 77 static const char *getErrorString(ErrorCode E) { 78 switch (E) { 79 case ErrorCode::Ok: 80 return "(none)"; 81 case ErrorCode::NotEnoughMemory: 82 return "no available buffers in the queue"; 83 case ErrorCode::QueueFinalizing: 84 return "queue already finalizing"; 85 case ErrorCode::UnrecognizedBuffer: 86 return "buffer being returned not owned by buffer queue"; 87 case ErrorCode::AlreadyFinalized: 88 return "queue already finalized"; 89 } 90 return "unknown error"; 91 } 92 93 /// Initialise a queue of size |N| with buffers of size |B|. We report success 94 /// through |Success|. 95 BufferQueue(size_t B, size_t N, bool &Success); 96 97 /// Updates |Buf| to contain the pointer to an appropriate buffer. Returns an 98 /// error in case there are no available buffers to return when we will run 99 /// over the upper bound for the total buffers. 100 /// 101 /// Requirements: 102 /// - BufferQueue is not finalising. 103 /// 104 /// Returns: 105 /// - ErrorCode::NotEnoughMemory on exceeding MaxSize. 106 /// - ErrorCode::Ok when we find a Buffer. 107 /// - ErrorCode::QueueFinalizing or ErrorCode::AlreadyFinalized on 108 /// a finalizing/finalized BufferQueue. 109 ErrorCode getBuffer(Buffer &Buf); 110 111 /// Updates |Buf| to point to nullptr, with size 0. 112 /// 113 /// Returns: 114 /// - ErrorCode::Ok when we successfully release the buffer. 115 /// - ErrorCode::UnrecognizedBuffer for when this BufferQueue does not own 116 /// the buffer being released. 117 ErrorCode releaseBuffer(Buffer &Buf); 118 119 bool finalizing() const { 120 return __sanitizer::atomic_load(&Finalizing, 121 __sanitizer::memory_order_acquire); 122 } 123 124 /// Returns the configured size of the buffers in the buffer queue. 125 size_t ConfiguredBufferSize() const { return BufferSize; } 126 127 /// Sets the state of the BufferQueue to finalizing, which ensures that: 128 /// 129 /// - All subsequent attempts to retrieve a Buffer will fail. 130 /// - All releaseBuffer operations will not fail. 131 /// 132 /// After a call to finalize succeeds, all subsequent calls to finalize will 133 /// fail with ErrorCode::QueueFinalizing. 134 ErrorCode finalize(); 135 136 /// Applies the provided function F to each Buffer in the queue, only if the 137 /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a 138 /// releaseBuffer(...) operation). 139 template <class F> 140 void apply(F Fn) { 141 __sanitizer::SpinMutexLock G(&Mutex); 142 for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) { 143 const auto &T = *I; 144 if (T.Used) Fn(T.Buff); 145 } 146 } 147 148 // Cleans up allocated buffers. 149 ~BufferQueue(); 150 }; 151 152 } // namespace __xray 153 154 #endif // XRAY_BUFFER_QUEUE_H 155