summaryrefslogtreecommitdiffstats
path: root/src/usr/trace/buffer.H
diff options
context:
space:
mode:
Diffstat (limited to 'src/usr/trace/buffer.H')
-rw-r--r--src/usr/trace/buffer.H197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/usr/trace/buffer.H b/src/usr/trace/buffer.H
new file mode 100644
index 000000000..04cb6f672
--- /dev/null
+++ b/src/usr/trace/buffer.H
@@ -0,0 +1,197 @@
+/* IBM_PROLOG_BEGIN_TAG */
+/* This is an automatically generated prolog. */
+/* */
+/* $Source: src/usr/trace/buffer.H $ */
+/* */
+/* IBM CONFIDENTIAL */
+/* */
+/* COPYRIGHT International Business Machines Corp. 2012 */
+/* */
+/* p1 */
+/* */
+/* Object Code Only (OCO) source materials */
+/* Licensed Internal Code Source Materials */
+/* IBM HostBoot Licensed Internal Code */
+/* */
+/* The source code for this program is not published or otherwise */
+/* divested of its trade secrets, irrespective of what has been */
+/* deposited with the U.S. Copyright Office. */
+/* */
+/* Origin: 30 */
+/* */
+/* IBM_PROLOG_END_TAG */
+#ifndef __TRACE_BUFFER_H
+#define __TRACE_BUFFER_H
+
+/** @file buffer.H
+ * Declarations for the buffer class.
+ */
+
+#include <trace/interface.H>
+#include <sys/sync.h>
+
+namespace TRACEDAEMON { class Daemon; } // Forward declaration.
+
+namespace TRACE
+{
+ // Forward declarations.
+ class BufferPage;
+ class Entry;
+ class DaemonIf;
+
+ /** @class Buffer
+ * @brief Class to manage the front-side (client) buffers
+ *
+ * Provides interfaces for getting an entry to write trace data to and
+ * committing that entry as well as extracting the component trace.
+ *
+ * Private interfaces for the daemon to ensure lockless ordering is
+ * maintained.
+ */
+ class Buffer
+ {
+ public:
+
+ enum
+ {
+ /** Used as a parameter to the constructor to indicate that
+ * the buffer should never block (and could instead run
+ * the system out of memory). */
+ UNLIMITED = UINT32_MAX
+ };
+
+ /** Constructor.
+ *
+ * @param[in] i_daemon - Daemon interface for this buffer.
+ * @param[in] i_maxPages - Maximum number of pages to consume
+ * before 'claimEntry' blocks.
+ */
+ Buffer(DaemonIf* i_daemon, size_t i_maxPages = 4);
+
+ /** @brief Claim an entry from the buffer to write data to.
+ *
+ * @param[in] i_comp - Component which will own entry.
+ * @param[in] i_size - Size of data portion of entry.
+ *
+ * @return An entry to write to.
+ *
+ * If pages allocated is at max pages and there is no room to
+ * create an entry, this function may block. For components
+ * which cannot block, it is expected that the buffer will be
+ * constructed large enough that we run out of memory before
+ * we block.
+ */
+ Entry* claimEntry(ComponentDesc* i_comp, size_t i_size);
+
+ /** @brief Commit entry to buffer and component linked-list.
+ *
+ * @param[in] i_entry - Entry to commit.
+ */
+ void commitEntry(Entry* i_entry);
+
+ /** @brief Extract component trace.
+ *
+ * See service::getBuffer. Defined here due to lockless ordering
+ * needs.
+ */
+ size_t getTrace(ComponentDesc* i_comp, void* o_data, size_t i_size);
+
+ private:
+ volatile uint64_t iv_pagesAlloc; //< Number of pages allocated.
+ uint64_t iv_pagesMax; //< Maximum pages allowed.
+
+ BufferPage* volatile iv_firstPage; //< Most recent page.
+
+ /** @union locklessCounter
+ *
+ * This class is mostly lockless in that multiple trace entries
+ * can be created at the same time along with buffer extraction.
+ * This means that all client operations are lockless.
+ *
+ * There are minor operations that the daemon must do to ensure
+ * that a client is not in the middle of another operation, such
+ * as when the daemon removes the pages from the front-end to
+ * merge them into the backend. During this time, the daemon
+ * will obtain the equivalent of a write-lock, which will block
+ * all clients.
+ *
+ * It is required that all times where the write-lock is held
+ * are short and cannot cause page-faults that might deadlock
+ * components such as VFS and PNOR. This means that all code
+ * inside the write-lock is in the base image.
+ *
+ * This read/write lock is modeled here as "producers" (clients)
+ * and a "consumer" (daemon). The active counts of each are
+ * recorded with this structure and unioned to a single uint64_t
+ * so that they can be atomically updated as one entity.
+ */
+ union locklessCounter
+ {
+ struct
+ {
+ uint32_t producerCount;
+ uint32_t consumerCount;
+ };
+ uint64_t totals;
+ };
+
+ locklessCounter iv_counters; //< The producer/consumer counts.
+
+ DaemonIf* iv_daemon; //< Daemon interface.
+
+ /** @brief Claim front-side buffer pages to be merged into the
+ * common buffer.
+ *
+ * @return Pointer to the first page (most recent) from this
+ * buffer.
+ *
+ * Gives ownership of all the current pages to the caller and
+ * resets this buffer's allocated page counts.
+ */
+ BufferPage* claimPages();
+
+ /** @brief Perform operations with the consumer lock held.
+ *
+ * These operations cannot be done in the daemon code directly
+ * because the daemon code is swappable and we cannot block
+ * producers.
+ *
+ * This function gives a set of primatives to the daemon to
+ * manipulate Entry pointers while secured under the consumer lock.
+ *
+ * The primatives that can be done are:
+ * 1) if (condAddr == condVal) { condActAddr = condActVal }
+ * 2) addr = val
+ *
+ * If any of the address parameters are NULL, their action will
+ * not be performed. So, just calling consumerOp() has the
+ * side-effect of simply toggling the consumer lock on and off.
+ *
+ * The return value indicates if primative #1 failed.
+ *
+ * @param[in] i_condAddr - The address to read for primative 1.
+ * @param[in] i_condVal - The value to expect for primative 1.
+ * @param[in] i_condActAddr - The address to store for primative 1.
+ * @param[in] i_condActVal - The value to store for primative 1.
+ *
+ * @param[in] i_addr - The address to store for primative 2.
+ * @param[in] i_val - The value to store for primative 2.
+ *
+ * @return bool - false if condAddr != condVal, true otherwise.
+ */
+ bool consumerOp(Entry** i_condAddr = NULL, Entry* i_condVal = NULL,
+ Entry** i_condActAddr = NULL,
+ Entry* i_condActVal = NULL,
+ Entry** i_addr = NULL, Entry* i_val = NULL);
+
+ void _producerEnter(); //< Enter client section.
+ void _producerExit(); //< Exit client section.
+ void _consumerEnter(); //< Enter daemon section.
+ void _consumerExit(); //< Exit daemon section.
+
+ friend class BufferTest;
+ friend class TRACEDAEMON::Daemon;
+ };
+}
+
+#endif
OpenPOWER on IntegriCloud