OLD | NEW |
1 //===- subzero/src/IceThreading.h - Threading functions ---------*- C++ -*-===// | 1 //===- subzero/src/IceThreading.h - Threading functions ---------*- C++ -*-===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
11 /// \brief Declares threading-related functions. | 11 /// \brief Declares threading-related functions. |
12 /// | 12 /// |
13 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
14 | 14 |
15 #ifndef SUBZERO_SRC_ICETHREADING_H | 15 #ifndef SUBZERO_SRC_ICETHREADING_H |
16 #define SUBZERO_SRC_ICETHREADING_H | 16 #define SUBZERO_SRC_ICETHREADING_H |
17 | 17 |
18 #include "IceDefs.h" | 18 #include "IceDefs.h" |
19 | 19 |
20 #include <condition_variable> | 20 #include <condition_variable> |
| 21 #include <memory> |
21 #include <mutex> | 22 #include <mutex> |
| 23 #include <utility> |
22 | 24 |
23 namespace Ice { | 25 namespace Ice { |
24 | 26 |
25 /// BoundedProducerConsumerQueue is a work queue that allows multiple producers | 27 /// BoundedProducerConsumerQueue is a work queue that allows multiple producers |
26 /// and multiple consumers. A producer adds entries using blockingPush(), and | 28 /// and multiple consumers. A producer adds entries using blockingPush(), and |
27 /// may block if the queue is "full". A producer uses notifyEnd() to indicate | 29 /// may block if the queue is "full". A producer uses notifyEnd() to indicate |
28 /// that no more entries will be added. A consumer removes an item using | 30 /// that no more entries will be added. A consumer removes an item using |
29 /// blockingPop(), which will return nullptr if notifyEnd() has been called and | 31 /// blockingPop(), which will return nullptr if notifyEnd() has been called and |
30 /// the queue is empty (it never returns nullptr if the queue contained any | 32 /// the queue is empty (it never returns nullptr if the queue contained any |
31 /// items). | 33 /// items). |
(...skipping 16 matching lines...) Expand all Loading... |
48 template <typename T, size_t MaxStaticSize = 128> | 50 template <typename T, size_t MaxStaticSize = 128> |
49 class BoundedProducerConsumerQueue { | 51 class BoundedProducerConsumerQueue { |
50 BoundedProducerConsumerQueue() = delete; | 52 BoundedProducerConsumerQueue() = delete; |
51 BoundedProducerConsumerQueue(const BoundedProducerConsumerQueue &) = delete; | 53 BoundedProducerConsumerQueue(const BoundedProducerConsumerQueue &) = delete; |
52 BoundedProducerConsumerQueue & | 54 BoundedProducerConsumerQueue & |
53 operator=(const BoundedProducerConsumerQueue &) = delete; | 55 operator=(const BoundedProducerConsumerQueue &) = delete; |
54 | 56 |
55 public: | 57 public: |
56 BoundedProducerConsumerQueue(bool Sequential, size_t MaxSize = MaxStaticSize) | 58 BoundedProducerConsumerQueue(bool Sequential, size_t MaxSize = MaxStaticSize) |
57 : MaxSize(std::min(MaxSize, MaxStaticSize)), Sequential(Sequential) {} | 59 : MaxSize(std::min(MaxSize, MaxStaticSize)), Sequential(Sequential) {} |
58 void blockingPush(T *Item) { | 60 void blockingPush(std::unique_ptr<T> Item) { |
59 { | 61 { |
60 std::unique_lock<GlobalLockType> L(Lock); | 62 std::unique_lock<GlobalLockType> L(Lock); |
61 // If the work queue is already "full", wait for a consumer to grab an | 63 // If the work queue is already "full", wait for a consumer to grab an |
62 // element and shrink the queue. | 64 // element and shrink the queue. |
63 Shrunk.wait(L, [this] { return size() < MaxSize || Sequential; }); | 65 Shrunk.wait(L, [this] { return size() < MaxSize || Sequential; }); |
64 push(Item); | 66 push(std::move(Item)); |
65 } | 67 } |
66 GrewOrEnded.notify_one(); | 68 GrewOrEnded.notify_one(); |
67 } | 69 } |
68 T *blockingPop() { | 70 std::unique_ptr<T> blockingPop() { |
69 T *Item = nullptr; | 71 std::unique_ptr<T> Item; |
70 bool ShouldNotifyProducer = false; | 72 bool ShouldNotifyProducer = false; |
71 { | 73 { |
72 std::unique_lock<GlobalLockType> L(Lock); | 74 std::unique_lock<GlobalLockType> L(Lock); |
73 GrewOrEnded.wait(L, [this] { return IsEnded || !empty() || Sequential; }); | 75 GrewOrEnded.wait(L, [this] { return IsEnded || !empty() || Sequential; }); |
74 if (!empty()) { | 76 if (!empty()) { |
75 Item = pop(); | 77 Item = pop(); |
76 ShouldNotifyProducer = !IsEnded; | 78 ShouldNotifyProducer = !IsEnded; |
77 } | 79 } |
78 } | 80 } |
79 if (ShouldNotifyProducer) | 81 if (ShouldNotifyProducer) |
80 Shrunk.notify_one(); | 82 Shrunk.notify_one(); |
81 return Item; | 83 return Item; |
82 } | 84 } |
83 void notifyEnd() { | 85 void notifyEnd() { |
84 { | 86 { |
85 std::lock_guard<GlobalLockType> L(Lock); | 87 std::lock_guard<GlobalLockType> L(Lock); |
86 IsEnded = true; | 88 IsEnded = true; |
87 } | 89 } |
88 GrewOrEnded.notify_all(); | 90 GrewOrEnded.notify_all(); |
89 } | 91 } |
90 | 92 |
91 private: | 93 private: |
92 const static size_t MaxStaticSizeMask = MaxStaticSize - 1; | 94 const static size_t MaxStaticSizeMask = MaxStaticSize - 1; |
93 static_assert(!(MaxStaticSize & (MaxStaticSize - 1)), | 95 static_assert(!(MaxStaticSize & (MaxStaticSize - 1)), |
94 "MaxStaticSize must be a power of 2"); | 96 "MaxStaticSize must be a power of 2"); |
95 | 97 |
96 ICE_CACHELINE_BOUNDARY; | 98 ICE_CACHELINE_BOUNDARY; |
97 /// WorkItems and Lock are read/written by all. | 99 /// WorkItems and Lock are read/written by all. |
98 T *WorkItems[MaxStaticSize]; | 100 std::unique_ptr<T> WorkItems[MaxStaticSize]; |
99 ICE_CACHELINE_BOUNDARY; | 101 ICE_CACHELINE_BOUNDARY; |
100 /// Lock guards access to WorkItems, Front, Back, and IsEnded. | 102 /// Lock guards access to WorkItems, Front, Back, and IsEnded. |
101 GlobalLockType Lock; | 103 GlobalLockType Lock; |
102 | 104 |
103 ICE_CACHELINE_BOUNDARY; | 105 ICE_CACHELINE_BOUNDARY; |
104 /// GrewOrEnded is written by the producers and read by the consumers. It is | 106 /// GrewOrEnded is written by the producers and read by the consumers. It is |
105 /// notified (by the producer) when something is added to the queue, in case | 107 /// notified (by the producer) when something is added to the queue, in case |
106 /// consumers are waiting for a non-empty queue. | 108 /// consumers are waiting for a non-empty queue. |
107 std::condition_variable GrewOrEnded; | 109 std::condition_variable GrewOrEnded; |
108 /// Back is the index into WorkItems[] of where the next element will be | 110 /// Back is the index into WorkItems[] of where the next element will be |
(...skipping 15 matching lines...) Expand all Loading... |
124 | 126 |
125 /// MaxSize and Sequential are read by all and written by none. | 127 /// MaxSize and Sequential are read by all and written by none. |
126 const size_t MaxSize; | 128 const size_t MaxSize; |
127 const bool Sequential; | 129 const bool Sequential; |
128 /// IsEnded is read by the consumers, and only written once by the producer. | 130 /// IsEnded is read by the consumers, and only written once by the producer. |
129 bool IsEnded = false; | 131 bool IsEnded = false; |
130 | 132 |
131 /// The lock must be held when the following methods are called. | 133 /// The lock must be held when the following methods are called. |
132 bool empty() const { return Front == Back; } | 134 bool empty() const { return Front == Back; } |
133 size_t size() const { return Back - Front; } | 135 size_t size() const { return Back - Front; } |
134 void push(T *Item) { | 136 void push(std::unique_ptr<T> Item) { |
135 WorkItems[Back++ & MaxStaticSizeMask] = Item; | 137 WorkItems[Back++ & MaxStaticSizeMask] = std::move(Item); |
136 assert(size() <= MaxStaticSize); | 138 assert(size() <= MaxStaticSize); |
137 } | 139 } |
138 T *pop() { | 140 std::unique_ptr<T> pop() { |
139 assert(!empty()); | 141 assert(!empty()); |
140 return WorkItems[Front++ & MaxStaticSizeMask]; | 142 return std::move(WorkItems[Front++ & MaxStaticSizeMask]); |
141 } | 143 } |
142 }; | 144 }; |
143 | 145 |
144 /// EmitterWorkItem is a simple wrapper around a pointer that represents a work | 146 /// EmitterWorkItem is a simple wrapper around a pointer that represents a work |
145 /// item to be emitted, i.e. a function or a set of global declarations and | 147 /// item to be emitted, i.e. a function or a set of global declarations and |
146 /// initializers, and it includes a sequence number so that work items can be | 148 /// initializers, and it includes a sequence number so that work items can be |
147 /// emitted in a particular order for deterministic output. It acts like an | 149 /// emitted in a particular order for deterministic output. It acts like an |
148 /// interface class, but instead of making the classes of interest inherit from | 150 /// interface class, but instead of making the classes of interest inherit from |
149 /// EmitterWorkItem, it wraps pointers to these classes. Some space is wasted | 151 /// EmitterWorkItem, it wraps pointers to these classes. Some space is wasted |
150 /// compared to storing the pointers in a union, but not too much due to the | 152 /// compared to storing the pointers in a union, but not too much due to the |
(...skipping 16 matching lines...) Expand all Loading... |
167 /// deleted (to recover lots of memory). | 169 /// deleted (to recover lots of memory). |
168 /// | 170 /// |
169 /// WI_Cfg: A Cfg that has not yet had emit() or emitIAS() called on it. This | 171 /// WI_Cfg: A Cfg that has not yet had emit() or emitIAS() called on it. This |
170 /// is only used as a debugging configuration when we want to emit "readable" | 172 /// is only used as a debugging configuration when we want to emit "readable" |
171 /// assembly code, possibly annotated with liveness and other information only | 173 /// assembly code, possibly annotated with liveness and other information only |
172 /// available in the Cfg and not in the Assembler buffer. | 174 /// available in the Cfg and not in the Assembler buffer. |
173 enum ItemKind { WI_Nop, WI_GlobalInits, WI_Asm, WI_Cfg }; | 175 enum ItemKind { WI_Nop, WI_GlobalInits, WI_Asm, WI_Cfg }; |
174 /// Constructor for a WI_Nop work item. | 176 /// Constructor for a WI_Nop work item. |
175 explicit EmitterWorkItem(uint32_t Seq); | 177 explicit EmitterWorkItem(uint32_t Seq); |
176 /// Constructor for a WI_GlobalInits work item. | 178 /// Constructor for a WI_GlobalInits work item. |
177 EmitterWorkItem(uint32_t Seq, VariableDeclarationList *D); | 179 EmitterWorkItem(uint32_t Seq, std::unique_ptr<VariableDeclarationList> D); |
178 /// Constructor for a WI_Asm work item. | 180 /// Constructor for a WI_Asm work item. |
179 EmitterWorkItem(uint32_t Seq, Assembler *A); | 181 EmitterWorkItem(uint32_t Seq, std::unique_ptr<Assembler> A); |
180 /// Constructor for a WI_Cfg work item. | 182 /// Constructor for a WI_Cfg work item. |
181 EmitterWorkItem(uint32_t Seq, Cfg *F); | 183 EmitterWorkItem(uint32_t Seq, std::unique_ptr<Cfg> F); |
182 uint32_t getSequenceNumber() const { return Sequence; } | 184 uint32_t getSequenceNumber() const { return Sequence; } |
183 ItemKind getKind() const { return Kind; } | 185 ItemKind getKind() const { return Kind; } |
184 void setGlobalInits(std::unique_ptr<VariableDeclarationList> GloblInits); | 186 void setGlobalInits(std::unique_ptr<VariableDeclarationList> GloblInits); |
185 std::unique_ptr<VariableDeclarationList> getGlobalInits(); | 187 std::unique_ptr<VariableDeclarationList> getGlobalInits(); |
186 std::unique_ptr<Assembler> getAsm(); | 188 std::unique_ptr<Assembler> getAsm(); |
187 std::unique_ptr<Cfg> getCfg(); | 189 std::unique_ptr<Cfg> getCfg(); |
188 | 190 |
189 private: | 191 private: |
190 const uint32_t Sequence; | 192 const uint32_t Sequence; |
191 const ItemKind Kind; | 193 const ItemKind Kind; |
192 std::unique_ptr<VariableDeclarationList> GlobalInits; | 194 std::unique_ptr<VariableDeclarationList> GlobalInits; |
193 std::unique_ptr<Assembler> Function; | 195 std::unique_ptr<Assembler> Function; |
194 std::unique_ptr<Cfg> RawFunc; | 196 std::unique_ptr<Cfg> RawFunc; |
195 }; | 197 }; |
196 | 198 |
197 } // end of namespace Ice | 199 } // end of namespace Ice |
198 | 200 |
199 #endif // SUBZERO_SRC_ICETHREADING_H | 201 #endif // SUBZERO_SRC_ICETHREADING_H |
OLD | NEW |