blob: 69478104d2990fcc405edb84ab23f9cbfeb74a99 [file] [log] [blame]
#pragma once
#include <string.h>
#include <analyzer/service_data.hpp>
#include <hei_chip.hpp>
#include <util/trace.hpp>
#include <functional>
#include <map>
namespace analyzer
{
// A plugin is special function called by the RAS data files specifically for
// service actions that cannot be characterized by the RAS data files.
//
// IMPORTANT:
// Use of these plugins should be limited to avoid maintaining chip specific
// functionality in this repository.
//
// Each plugin must be defined in a specific form. See PluginFunction below.
// Then the plugin must registered in the PluginMap using the PLUGIN_DEFINE or
// PLUGIN_DEFINE_NS macros below.
// All plugins will have the following parameters:
// - The plugin instance for plugins that may be defined for a chip that has
// multiple instance of a unit/register.
// - The chip containing the root cause attention.
// - The service data object containing service actions and FFDC for the root
// cause attention.
using PluginFunction =
std::function<void(unsigned int, const libhei::Chip&, ServiceData&)>;
// These are provided as know chip types for plugin definitions.
constexpr libhei::ChipType_t EXPLORER_11 = 0x60d20011;
constexpr libhei::ChipType_t EXPLORER_20 = 0x60d20020;
constexpr libhei::ChipType_t ODYSSEY_10 = 0x60c00010;
constexpr libhei::ChipType_t P10_10 = 0x20da0010;
constexpr libhei::ChipType_t P10_20 = 0x20da0020;
/**
* @brief This is simply a global container for all of the registered plugins.
*
* @note This class cannot be instantiated. Instead, use the getSingleton()
* function to access.
*/
class PluginMap
{
private:
/** @brief Default constructor. */
PluginMap() = default;
/** @brief Destructor. */
~PluginMap() = default;
/** @brief Copy constructor. */
PluginMap(const PluginMap&) = delete;
/** @brief Assignment operator. */
PluginMap& operator=(const PluginMap&) = delete;
public:
/** @brief Provides access to a singleton instance of this object. */
static PluginMap& getSingleton()
{
static PluginMap thePluginMap;
return thePluginMap;
}
private:
/** A nested map that contains the function for each chip type and plugin
* name. */
std::map<libhei::ChipType_t, std::map<std::string, PluginFunction>> iv_map;
public:
/**
* @brief Registers a plugin with the plugin map.
*
* @param i_type The chip type associated with the plugin.
* @param i_name The name of the plugin.
* @param i_plugin The plugin function.
*
* @throw std::logic_error if a plugin is defined more than once.
*/
void add(libhei::ChipType_t i_type, const std::string& i_name,
PluginFunction i_plugin)
{
auto itr = iv_map.find(i_type);
if (iv_map.end() == itr ||
itr->second.end() == itr->second.find(i_name))
{
iv_map[i_type][i_name] = i_plugin;
}
else
{
throw std::logic_error("Duplicate plugin found");
}
}
/**
* @return The plugin function for the target plugin.
*
* @param i_type The chip type associated with the plugin.
* @param i_name The name of the plugin.
*
* @throw std::out_of_range if the target plugin does not exist.
*/
PluginFunction get(libhei::ChipType_t i_type,
const std::string& i_name) const
{
PluginFunction func;
try
{
func = iv_map.at(i_type).at(i_name);
}
catch (const std::out_of_range& e)
{
trace::err("Plugin not defined: i_type=0x%08x i_name=%s", i_type,
i_name.c_str());
throw; // caught later downstream
}
return func;
}
};
// These defines a unique class and a global variable for each plugin. Because
// the variables are defined in the global scope, they will be initialized with
// the default constructor before execution of the program. This allows all of
// the plugins to be registered in the plugin map before execution.
#define __PLUGIN_MAKE(X, Y, Z) X##Y##Z
#define __PLUGIN_DEFINE(CHIP, NAME, FUNC) \
class __PLUGIN_MAKE(Plugin_, CHIP, NAME) \
{ \
public: \
__PLUGIN_MAKE(Plugin_, CHIP, NAME) \
() \
{ \
PluginMap::getSingleton().add(CHIP, #NAME, &FUNC); \
} \
}; \
__PLUGIN_MAKE(Plugin_, CHIP, NAME) __PLUGIN_MAKE(g_Plugin_, CHIP, NAME)
#define PLUGIN_DEFINE(CHIP, NAME) __PLUGIN_DEFINE(CHIP, NAME, CHIP::NAME)
#define PLUGIN_DEFINE_NS(CHIP, NS, NAME) __PLUGIN_DEFINE(CHIP, NAME, NS::NAME)
// Regarding the use of PLUGIN_DEFINE_NS. This is provided for cases where the
// same plugin needs to be defined differently for different chips. Example:
//
// namespace A
// {
// void foo(...) { /* definition for chip A */ }
// };
//
// namespace B
// {
// void foo(...) { /* definition for chip B */ }
// };
//
// PLUGIN_DEFINE_NS(CHIP_A, A, foo);
// PLUGIN_DEFINE_NS(CHIP_B, B, foo);
//
// Also, it is important that the plugin definitions should be declared outside
// of the function namespaces (see the example above). This helps find
// duplicate plugin definitions at compile time. Otherwise, if you do something
// like this:
//
// namespace A
// {
// void foo(...) { /* definition for chip A */ }
// PLUGIN_DEFINE_NS(CHIP_A, A, foo);
// };
//
// namespace B
// {
// void foo(...) { /* definition again for chip A */ }
// PLUGIN_DEFINE_NS(CHIP_A, B, foo);
// };
//
// The compiler will not find the duplicate and instead it will be found during
// program execution, which will result in an exception.
} // namespace analyzer