1 /** 2 * Copyright © 2019 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #pragma once 17 18 #include "id_map.hpp" 19 #include "phase_fault.hpp" 20 #include "services.hpp" 21 22 #include <cstddef> // for size_t 23 #include <map> 24 #include <optional> 25 #include <set> 26 #include <stdexcept> 27 #include <string> 28 29 namespace phosphor::power::regulators 30 { 31 32 // Forward declarations to avoid circular dependencies 33 class Device; 34 class Rule; 35 36 /** 37 * @class ActionEnvironment 38 * 39 * The current environment when executing actions. 40 * 41 * The ActionEnvironment contains the following information: 42 * - current device ID 43 * - current volts value (if any) 44 * - mapping from device and rule IDs to the corresponding objects 45 * - rule call stack depth (to detect infinite recursion) 46 * - reference to system services 47 * - faults detected by actions (if any) 48 * - additional error data captured by actions (if any) 49 */ 50 class ActionEnvironment 51 { 52 public: 53 // Specify which compiler-generated methods we want 54 ActionEnvironment() = delete; 55 ActionEnvironment(const ActionEnvironment&) = delete; 56 ActionEnvironment(ActionEnvironment&&) = delete; 57 ActionEnvironment& operator=(const ActionEnvironment&) = delete; 58 ActionEnvironment& operator=(ActionEnvironment&&) = delete; 59 ~ActionEnvironment() = default; 60 61 /** 62 * Maximum rule call stack depth. Used to detect infinite recursion. 63 */ 64 static constexpr size_t maxRuleDepth{30}; 65 66 /** 67 * Constructor. 68 * 69 * @param idMap mapping from IDs to the associated Device/Rule objects 70 * @param deviceID current device ID 71 * @param services system services like error logging and the journal 72 */ ActionEnvironment(const IDMap & idMap,const std::string & deviceID,Services & services)73 explicit ActionEnvironment(const IDMap& idMap, const std::string& deviceID, 74 Services& services) : 75 idMap{idMap}, deviceID{deviceID}, services{services} 76 {} 77 78 /** 79 * Adds the specified key/value pair to the map of additional error data 80 * that has been captured. 81 * 82 * This data provides more information about an error and will be stored in 83 * the error log. 84 * 85 * @param key key name 86 * @param value value expressed as a string 87 */ addAdditionalErrorData(const std::string & key,const std::string & value)88 void addAdditionalErrorData(const std::string& key, 89 const std::string& value) 90 { 91 additionalErrorData.emplace(key, value); 92 } 93 94 /** 95 * Adds the specified phase fault to the set of faults that have been 96 * detected. 97 * 98 * @param type phase fault type 99 */ addPhaseFault(PhaseFaultType type)100 void addPhaseFault(PhaseFaultType type) 101 { 102 phaseFaults.emplace(type); 103 } 104 105 /** 106 * Decrements the rule call stack depth by one. 107 * 108 * Should be used when a call to a rule returns. Does nothing if depth is 109 * already 0. 110 */ decrementRuleDepth()111 void decrementRuleDepth() 112 { 113 if (ruleDepth > 0) 114 { 115 --ruleDepth; 116 } 117 } 118 119 /** 120 * Returns the additional error data that has been captured (if any). 121 * 122 * @return additional error data 123 */ getAdditionalErrorData() const124 const std::map<std::string, std::string>& getAdditionalErrorData() const 125 { 126 return additionalErrorData; 127 } 128 129 /** 130 * Returns the device with the current device ID. 131 * 132 * Throws invalid_argument if no device is found with current ID. 133 * 134 * @return device with current device ID 135 */ getDevice() const136 Device& getDevice() const 137 { 138 return idMap.getDevice(deviceID); 139 } 140 141 /** 142 * Returns the current device ID. 143 * 144 * @return current device ID 145 */ getDeviceID() const146 const std::string& getDeviceID() const 147 { 148 return deviceID; 149 } 150 151 /** 152 * Returns the set of phase faults that have been detected (if any). 153 * 154 * @return phase faults detected 155 */ getPhaseFaults() const156 const std::set<PhaseFaultType>& getPhaseFaults() const 157 { 158 return phaseFaults; 159 } 160 161 /** 162 * Returns the rule with the specified ID. 163 * 164 * Throws invalid_argument if no rule is found with specified ID. 165 * 166 * @param id rule ID 167 * @return rule with specified ID 168 */ getRule(const std::string & id) const169 Rule& getRule(const std::string& id) const 170 { 171 return idMap.getRule(id); 172 } 173 174 /** 175 * Returns the current rule call stack depth. 176 * 177 * The depth is 0 if no rules have been called. 178 * 179 * @return rule call stack depth 180 */ getRuleDepth() const181 size_t getRuleDepth() const 182 { 183 return ruleDepth; 184 } 185 186 /** 187 * Returns the services in this action environment. 188 * 189 * @return system services 190 */ getServices() const191 Services& getServices() const 192 { 193 return services; 194 } 195 196 /** 197 * Returns the current volts value, if set. 198 * 199 * @return current volts value 200 */ getVolts() const201 std::optional<double> getVolts() const 202 { 203 return volts; 204 } 205 206 /** 207 * Increments the rule call stack depth by one. 208 * 209 * Should be used when a rule is called. 210 * 211 * Throws runtime_error if the new depth exceeds maxRuleDepth. This 212 * indicates that infinite recursion has probably occurred (rule A -> rule B 213 * -> rule A). 214 * 215 * @param ruleID ID of the rule that is being called 216 */ incrementRuleDepth(const std::string & ruleID)217 void incrementRuleDepth(const std::string& ruleID) 218 { 219 if (ruleDepth >= maxRuleDepth) 220 { 221 throw std::runtime_error( 222 "Maximum rule depth exceeded by rule " + ruleID + '.'); 223 } 224 ++ruleDepth; 225 } 226 227 /** 228 * Sets the current device ID. 229 * 230 * @param id device ID 231 */ setDeviceID(const std::string & id)232 void setDeviceID(const std::string& id) 233 { 234 deviceID = id; 235 } 236 237 /** 238 * Sets the current volts value. 239 * 240 * @param volts new volts value. 241 */ setVolts(double volts)242 void setVolts(double volts) 243 { 244 this->volts = volts; 245 } 246 247 private: 248 /** 249 * Mapping from string IDs to the associated Device and Rule objects. 250 */ 251 const IDMap& idMap; 252 253 /** 254 * Current device ID. 255 */ 256 std::string deviceID{}; 257 258 /** 259 * System services like error logging and the journal. 260 */ 261 Services& services; 262 263 /** 264 * Current volts value (if set). 265 */ 266 std::optional<double> volts{}; 267 268 /** 269 * Rule call stack depth. 270 */ 271 size_t ruleDepth{0}; 272 273 /** 274 * Redundant phase faults that have been detected. 275 */ 276 std::set<PhaseFaultType> phaseFaults{}; 277 278 /** 279 * Additional error data that has been captured. 280 */ 281 std::map<std::string, std::string> additionalErrorData{}; 282 }; 283 284 } // namespace phosphor::power::regulators 285