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