| Index: src/IceThreading.h
|
| diff --git a/src/IceThreading.h b/src/IceThreading.h
|
| index 4f04935a1f2b188bbc03858b248f8f3bf7617e88..f59f46e3bad590a55b23ba71732a95f6e2a864d9 100644
|
| --- a/src/IceThreading.h
|
| +++ b/src/IceThreading.h
|
| @@ -6,9 +6,10 @@
|
| // License. See LICENSE.TXT for details.
|
| //
|
| //===----------------------------------------------------------------------===//
|
| -//
|
| -// This file declares threading-related functions.
|
| -//
|
| +///
|
| +/// \file
|
| +/// This file declares threading-related functions.
|
| +///
|
| //===----------------------------------------------------------------------===//
|
|
|
| #ifndef SUBZERO_SRC_ICETHREADING_H
|
| @@ -21,31 +22,31 @@
|
|
|
| namespace Ice {
|
|
|
| -// BoundedProducerConsumerQueue is a work queue that allows multiple
|
| -// producers and multiple consumers. A producer adds entries using
|
| -// blockingPush(), and may block if the queue is "full". A producer
|
| -// uses notifyEnd() to indicate that no more entries will be added. A
|
| -// consumer removes an item using blockingPop(), which will return
|
| -// nullptr if notifyEnd() has been called and the queue is empty (it
|
| -// never returns nullptr if the queue contained any items).
|
| -//
|
| -// The MaxSize ctor arg controls the maximum size the queue can grow
|
| -// to (subject to a hard limit of MaxStaticSize-1). The Sequential
|
| -// arg indicates purely sequential execution in which the single
|
| -// thread should never wait().
|
| -//
|
| -// Two condition variables are used in the implementation.
|
| -// GrewOrEnded signals a waiting worker that a producer has changed
|
| -// the state of the queue. Shrunk signals a blocked producer that a
|
| -// consumer has changed the state of the queue.
|
| -//
|
| -// The methods begin with Sequential-specific code to be most clear.
|
| -// The lock and condition variables are not used in the Sequential
|
| -// case.
|
| -//
|
| -// Internally, the queue is implemented as a circular array of size
|
| -// MaxStaticSize, where the queue boundaries are denoted by the Front
|
| -// and Back fields. Front==Back indicates an empty queue.
|
| +/// BoundedProducerConsumerQueue is a work queue that allows multiple
|
| +/// producers and multiple consumers. A producer adds entries using
|
| +/// blockingPush(), and may block if the queue is "full". A producer
|
| +/// uses notifyEnd() to indicate that no more entries will be added. A
|
| +/// consumer removes an item using blockingPop(), which will return
|
| +/// nullptr if notifyEnd() has been called and the queue is empty (it
|
| +/// never returns nullptr if the queue contained any items).
|
| +///
|
| +/// The MaxSize ctor arg controls the maximum size the queue can grow
|
| +/// to (subject to a hard limit of MaxStaticSize-1). The Sequential
|
| +/// arg indicates purely sequential execution in which the single
|
| +/// thread should never wait().
|
| +///
|
| +/// Two condition variables are used in the implementation.
|
| +/// GrewOrEnded signals a waiting worker that a producer has changed
|
| +/// the state of the queue. Shrunk signals a blocked producer that a
|
| +/// consumer has changed the state of the queue.
|
| +///
|
| +/// The methods begin with Sequential-specific code to be most clear.
|
| +/// The lock and condition variables are not used in the Sequential
|
| +/// case.
|
| +///
|
| +/// Internally, the queue is implemented as a circular array of size
|
| +/// MaxStaticSize, where the queue boundaries are denoted by the Front
|
| +/// and Back fields. Front==Back indicates an empty queue.
|
| template <typename T, size_t MaxStaticSize = 128>
|
| class BoundedProducerConsumerQueue {
|
| BoundedProducerConsumerQueue() = delete;
|
| @@ -94,47 +95,47 @@ private:
|
| static_assert(!(MaxStaticSize & (MaxStaticSize - 1)),
|
| "MaxStaticSize must be a power of 2");
|
|
|
| - // WorkItems and Lock are read/written by all.
|
| ICE_CACHELINE_BOUNDARY;
|
| + /// WorkItems and Lock are read/written by all.
|
| T *WorkItems[MaxStaticSize];
|
| ICE_CACHELINE_BOUNDARY;
|
| - // Lock guards access to WorkItems, Front, Back, and IsEnded.
|
| + /// Lock guards access to WorkItems, Front, Back, and IsEnded.
|
| GlobalLockType Lock;
|
|
|
| ICE_CACHELINE_BOUNDARY;
|
| - // GrewOrEnded is written by the producers and read by the
|
| - // consumers. It is notified (by the producer) when something is
|
| - // added to the queue, in case consumers are waiting for a non-empty
|
| - // queue.
|
| + /// GrewOrEnded is written by the producers and read by the
|
| + /// consumers. It is notified (by the producer) when something is
|
| + /// added to the queue, in case consumers are waiting for a non-empty
|
| + /// queue.
|
| std::condition_variable GrewOrEnded;
|
| - // Back is the index into WorkItems[] of where the next element will
|
| - // be pushed. (More precisely, Back&MaxStaticSize is the index.)
|
| - // It is written by the producers, and read by all via size() and
|
| - // empty().
|
| + /// Back is the index into WorkItems[] of where the next element will
|
| + /// be pushed. (More precisely, Back&MaxStaticSize is the index.)
|
| + /// It is written by the producers, and read by all via size() and
|
| + /// empty().
|
| size_t Back = 0;
|
|
|
| ICE_CACHELINE_BOUNDARY;
|
| - // Shrunk is notified (by the consumer) when something is removed
|
| - // from the queue, in case a producer is waiting for the queue to
|
| - // drop below maximum capacity. It is written by the consumers and
|
| - // read by the producers.
|
| + /// Shrunk is notified (by the consumer) when something is removed
|
| + /// from the queue, in case a producer is waiting for the queue to
|
| + /// drop below maximum capacity. It is written by the consumers and
|
| + /// read by the producers.
|
| std::condition_variable Shrunk;
|
| - // Front is the index into WorkItems[] of the oldest element,
|
| - // i.e. the next to be popped. (More precisely Front&MaxStaticSize
|
| - // is the index.) It is written by the consumers, and read by all
|
| - // via size() and empty().
|
| + /// Front is the index into WorkItems[] of the oldest element,
|
| + /// i.e. the next to be popped. (More precisely Front&MaxStaticSize
|
| + /// is the index.) It is written by the consumers, and read by all
|
| + /// via size() and empty().
|
| size_t Front = 0;
|
|
|
| ICE_CACHELINE_BOUNDARY;
|
|
|
| - // MaxSize and Sequential are read by all and written by none.
|
| + /// MaxSize and Sequential are read by all and written by none.
|
| const size_t MaxSize;
|
| const bool Sequential;
|
| - // IsEnded is read by the consumers, and only written once by the
|
| - // producer.
|
| + /// IsEnded is read by the consumers, and only written once by the
|
| + /// producer.
|
| bool IsEnded = false;
|
|
|
| - // The lock must be held when the following methods are called.
|
| + /// The lock must be held when the following methods are called.
|
| bool empty() const { return Front == Back; }
|
| size_t size() const { return Back - Front; }
|
| void push(T *Item) {
|
| @@ -147,45 +148,45 @@ private:
|
| }
|
| };
|
|
|
| -// EmitterWorkItem is a simple wrapper around a pointer that
|
| -// represents a work item to be emitted, i.e. a function or a set of
|
| -// global declarations and initializers, and it includes a sequence
|
| -// number so that work items can be emitted in a particular order for
|
| -// deterministic output. It acts like an interface class, but instead
|
| -// of making the classes of interest inherit from EmitterWorkItem, it
|
| -// wraps pointers to these classes. Some space is wasted compared to
|
| -// storing the pointers in a union, but not too much due to the work
|
| -// granularity.
|
| +/// EmitterWorkItem is a simple wrapper around a pointer that
|
| +/// represents a work item to be emitted, i.e. a function or a set of
|
| +/// global declarations and initializers, and it includes a sequence
|
| +/// number so that work items can be emitted in a particular order for
|
| +/// deterministic output. It acts like an interface class, but instead
|
| +/// of making the classes of interest inherit from EmitterWorkItem, it
|
| +/// wraps pointers to these classes. Some space is wasted compared to
|
| +/// storing the pointers in a union, but not too much due to the work
|
| +/// granularity.
|
| class EmitterWorkItem {
|
| EmitterWorkItem() = delete;
|
| EmitterWorkItem(const EmitterWorkItem &) = delete;
|
| EmitterWorkItem &operator=(const EmitterWorkItem &) = delete;
|
|
|
| public:
|
| - // ItemKind can be one of the following:
|
| - //
|
| - // WI_Nop: No actual work. This is a placeholder to maintain
|
| - // sequence numbers in case there is a translation error.
|
| - //
|
| - // WI_GlobalInits: A list of global declarations and initializers.
|
| - //
|
| - // WI_Asm: A function that has already had emitIAS() called on it.
|
| - // The work is transferred via the Assembler buffer, and the
|
| - // originating Cfg has been deleted (to recover lots of memory).
|
| - //
|
| - // WI_Cfg: A Cfg that has not yet had emit() or emitIAS() called on
|
| - // it. This is only used as a debugging configuration when we want
|
| - // to emit "readable" assembly code, possibly annotated with
|
| - // liveness and other information only available in the Cfg and not
|
| - // in the Assembler buffer.
|
| + /// ItemKind can be one of the following:
|
| + ///
|
| + /// WI_Nop: No actual work. This is a placeholder to maintain
|
| + /// sequence numbers in case there is a translation error.
|
| + ///
|
| + /// WI_GlobalInits: A list of global declarations and initializers.
|
| + ///
|
| + /// WI_Asm: A function that has already had emitIAS() called on it.
|
| + /// The work is transferred via the Assembler buffer, and the
|
| + /// originating Cfg has been deleted (to recover lots of memory).
|
| + ///
|
| + /// WI_Cfg: A Cfg that has not yet had emit() or emitIAS() called on
|
| + /// it. This is only used as a debugging configuration when we want
|
| + /// to emit "readable" assembly code, possibly annotated with
|
| + /// liveness and other information only available in the Cfg and not
|
| + /// in the Assembler buffer.
|
| enum ItemKind { WI_Nop, WI_GlobalInits, WI_Asm, WI_Cfg };
|
| - // Constructor for a WI_Nop work item.
|
| + /// Constructor for a WI_Nop work item.
|
| explicit EmitterWorkItem(uint32_t Seq);
|
| - // Constructor for a WI_GlobalInits work item.
|
| + /// Constructor for a WI_GlobalInits work item.
|
| EmitterWorkItem(uint32_t Seq, VariableDeclarationList *D);
|
| - // Constructor for a WI_Asm work item.
|
| + /// Constructor for a WI_Asm work item.
|
| EmitterWorkItem(uint32_t Seq, Assembler *A);
|
| - // Constructor for a WI_Cfg work item.
|
| + /// Constructor for a WI_Cfg work item.
|
| EmitterWorkItem(uint32_t Seq, Cfg *F);
|
| uint32_t getSequenceNumber() const { return Sequence; }
|
| ItemKind getKind() const { return Kind; }
|
|
|