]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/compiler-rt/lib/xray/xray_buffer_queue.h
Import tzdata 2018f
[FreeBSD/FreeBSD.git] / contrib / compiler-rt / lib / xray / xray_buffer_queue.h
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 alignas(64) BufferExtents {
32     __sanitizer::atomic_uint64_t Size;
33   };
34
35   struct Buffer {
36     void *Buffer = nullptr;
37     size_t Size = 0;
38     BufferExtents* Extents;
39   };
40
41  private:
42   struct BufferRep {
43     // The managed buffer.
44     Buffer Buff;
45
46     // This is true if the buffer has been returned to the available queue, and
47     // is considered "used" by another thread.
48     bool Used = false;
49   };
50
51   // Size of each individual Buffer.
52   size_t BufferSize;
53
54   BufferRep *Buffers;
55   size_t BufferCount;
56
57   __sanitizer::SpinMutex Mutex;
58   __sanitizer::atomic_uint8_t Finalizing;
59
60   // Pointers to buffers managed/owned by the BufferQueue.
61   void **OwnedBuffers;
62
63   // Pointer to the next buffer to be handed out.
64   BufferRep *Next;
65
66   // Pointer to the entry in the array where the next released buffer will be
67   // placed.
68   BufferRep *First;
69
70   // Count of buffers that have been handed out through 'getBuffer'.
71   size_t LiveBuffers;
72
73  public:
74   enum class ErrorCode : unsigned {
75     Ok,
76     NotEnoughMemory,
77     QueueFinalizing,
78     UnrecognizedBuffer,
79     AlreadyFinalized,
80   };
81
82   static const char *getErrorString(ErrorCode E) {
83     switch (E) {
84       case ErrorCode::Ok:
85         return "(none)";
86       case ErrorCode::NotEnoughMemory:
87         return "no available buffers in the queue";
88       case ErrorCode::QueueFinalizing:
89         return "queue already finalizing";
90       case ErrorCode::UnrecognizedBuffer:
91         return "buffer being returned not owned by buffer queue";
92       case ErrorCode::AlreadyFinalized:
93         return "queue already finalized";
94     }
95     return "unknown error";
96   }
97
98   /// Initialise a queue of size |N| with buffers of size |B|. We report success
99   /// through |Success|.
100   BufferQueue(size_t B, size_t N, bool &Success);
101
102   /// Updates |Buf| to contain the pointer to an appropriate buffer. Returns an
103   /// error in case there are no available buffers to return when we will run
104   /// over the upper bound for the total buffers.
105   ///
106   /// Requirements:
107   ///   - BufferQueue is not finalising.
108   ///
109   /// Returns:
110   ///   - ErrorCode::NotEnoughMemory on exceeding MaxSize.
111   ///   - ErrorCode::Ok when we find a Buffer.
112   ///   - ErrorCode::QueueFinalizing or ErrorCode::AlreadyFinalized on
113   ///     a finalizing/finalized BufferQueue.
114   ErrorCode getBuffer(Buffer &Buf);
115
116   /// Updates |Buf| to point to nullptr, with size 0.
117   ///
118   /// Returns:
119   ///   - ErrorCode::Ok when we successfully release the buffer.
120   ///   - ErrorCode::UnrecognizedBuffer for when this BufferQueue does not own
121   ///     the buffer being released.
122   ErrorCode releaseBuffer(Buffer &Buf);
123
124   bool finalizing() const {
125     return __sanitizer::atomic_load(&Finalizing,
126                                     __sanitizer::memory_order_acquire);
127   }
128
129   /// Returns the configured size of the buffers in the buffer queue.
130   size_t ConfiguredBufferSize() const { return BufferSize; }
131
132   /// Sets the state of the BufferQueue to finalizing, which ensures that:
133   ///
134   ///   - All subsequent attempts to retrieve a Buffer will fail.
135   ///   - All releaseBuffer operations will not fail.
136   ///
137   /// After a call to finalize succeeds, all subsequent calls to finalize will
138   /// fail with ErrorCode::QueueFinalizing.
139   ErrorCode finalize();
140
141   /// Applies the provided function F to each Buffer in the queue, only if the
142   /// Buffer is marked 'used' (i.e. has been the result of getBuffer(...) and a
143   /// releaseBuffer(...) operation).
144   template <class F>
145   void apply(F Fn) {
146     __sanitizer::SpinMutexLock G(&Mutex);
147     for (auto I = Buffers, E = Buffers + BufferCount; I != E; ++I) {
148       const auto &T = *I;
149       if (T.Used) Fn(T.Buff);
150     }
151   }
152
153   // Cleans up allocated buffers.
154   ~BufferQueue();
155 };
156
157 }  // namespace __xray
158
159 #endif  // XRAY_BUFFER_QUEUE_H