1 //===-- xray_buffer_queue.cc -----------------------------------*- 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 instruementation system. 11 // 12 // Defines the interface for a buffer queue implementation. 13 // 14 //===----------------------------------------------------------------------===// 15 #include "xray_buffer_queue.h" 16 #include "sanitizer_common/sanitizer_allocator_internal.h" 17 #include "sanitizer_common/sanitizer_common.h" 18 #include "sanitizer_common/sanitizer_libc.h" 19 20 using namespace __xray; 21 using namespace __sanitizer; 22 23 BufferQueue::BufferQueue(size_t B, size_t N, bool &Success) 24 : BufferSize(B), Buffers(new BufferRep[N]()), BufferCount(N), Finalizing{0}, 25 OwnedBuffers(new void *[N]()), Next(Buffers), First(Buffers), 26 LiveBuffers(0) { 27 for (size_t i = 0; i < N; ++i) { 28 auto &T = Buffers[i]; 29 void *Tmp = InternalAlloc(BufferSize, nullptr, 64); 30 if (Tmp == nullptr) { 31 Success = false; 32 return; 33 } 34 void *Extents = InternalAlloc(sizeof(BufferExtents), nullptr, 64); 35 if (Extents == nullptr) { 36 Success = false; 37 return; 38 } 39 auto &Buf = T.Buff; 40 Buf.Buffer = Tmp; 41 Buf.Size = B; 42 Buf.Extents = reinterpret_cast<BufferExtents *>(Extents); 43 OwnedBuffers[i] = Tmp; 44 } 45 Success = true; 46 } 47 48 BufferQueue::ErrorCode BufferQueue::getBuffer(Buffer &Buf) { 49 if (__sanitizer::atomic_load(&Finalizing, __sanitizer::memory_order_acquire)) 50 return ErrorCode::QueueFinalizing; 51 __sanitizer::SpinMutexLock Guard(&Mutex); 52 if (LiveBuffers == BufferCount) 53 return ErrorCode::NotEnoughMemory; 54 55 auto &T = *Next; 56 auto &B = T.Buff; 57 Buf = B; 58 T.Used = true; 59 ++LiveBuffers; 60 61 if (++Next == (Buffers + BufferCount)) 62 Next = Buffers; 63 64 return ErrorCode::Ok; 65 } 66 67 BufferQueue::ErrorCode BufferQueue::releaseBuffer(Buffer &Buf) { 68 // Blitz through the buffers array to find the buffer. 69 bool Found = false; 70 for (auto I = OwnedBuffers, E = OwnedBuffers + BufferCount; I != E; ++I) { 71 if (*I == Buf.Buffer) { 72 Found = true; 73 break; 74 } 75 } 76 if (!Found) 77 return ErrorCode::UnrecognizedBuffer; 78 79 __sanitizer::SpinMutexLock Guard(&Mutex); 80 81 // This points to a semantic bug, we really ought to not be releasing more 82 // buffers than we actually get. 83 if (LiveBuffers == 0) 84 return ErrorCode::NotEnoughMemory; 85 86 // Now that the buffer has been released, we mark it as "used". 87 First->Buff = Buf; 88 First->Used = true; 89 Buf.Buffer = nullptr; 90 Buf.Size = 0; 91 --LiveBuffers; 92 if (++First == (Buffers + BufferCount)) 93 First = Buffers; 94 95 return ErrorCode::Ok; 96 } 97 98 BufferQueue::ErrorCode BufferQueue::finalize() { 99 if (__sanitizer::atomic_exchange(&Finalizing, 1, 100 __sanitizer::memory_order_acq_rel)) 101 return ErrorCode::QueueFinalizing; 102 return ErrorCode::Ok; 103 } 104 105 BufferQueue::~BufferQueue() { 106 for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) { 107 auto &T = *I; 108 auto &Buf = T.Buff; 109 InternalFree(Buf.Buffer); 110 InternalFree(Buf.Extents); 111 } 112 delete[] Buffers; 113 delete[] OwnedBuffers; 114 } 115