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 "services.hpp" 20 21 #include <cstddef> // for size_t 22 #include <optional> 23 #include <stdexcept> 24 #include <string> 25 26 namespace phosphor::power::regulators 27 { 28 29 // Forward declarations to avoid circular dependencies 30 class Device; 31 class Rule; 32 33 /** 34 * @class ActionEnvironment 35 * 36 * The current environment when executing actions. 37 * 38 * The ActionEnvironment contains the following information: 39 * - current device ID 40 * - current volts value (if any) 41 * - mapping from device and rule IDs to the corresponding objects 42 * - rule call stack depth (to detect infinite recursion) 43 */ 44 class ActionEnvironment 45 { 46 public: 47 // Specify which compiler-generated methods we want 48 ActionEnvironment() = delete; 49 ActionEnvironment(const ActionEnvironment&) = delete; 50 ActionEnvironment(ActionEnvironment&&) = delete; 51 ActionEnvironment& operator=(const ActionEnvironment&) = delete; 52 ActionEnvironment& operator=(ActionEnvironment&&) = delete; 53 ~ActionEnvironment() = default; 54 55 /** 56 * Maximum rule call stack depth. Used to detect infinite recursion. 57 */ 58 static constexpr size_t maxRuleDepth{30}; 59 60 /** 61 * Constructor. 62 * 63 * @param idMap mapping from IDs to the associated Device/Rule objects 64 * @param deviceID current device ID 65 * @param services system services like error logging and the journal 66 */ 67 explicit ActionEnvironment(const IDMap& idMap, const std::string& deviceID, 68 Services& services) : 69 idMap{idMap}, 70 deviceID{deviceID}, services{services} 71 { 72 } 73 74 /** 75 * Decrements the rule call stack depth by one. 76 * 77 * Should be used when a call to a rule returns. Does nothing if depth is 78 * already 0. 79 */ 80 void decrementRuleDepth() 81 { 82 if (ruleDepth > 0) 83 { 84 --ruleDepth; 85 } 86 } 87 88 /** 89 * Returns the device with the current device ID. 90 * 91 * Throws invalid_argument if no device is found with current ID. 92 * 93 * @return device with current device ID 94 */ 95 Device& getDevice() const 96 { 97 return idMap.getDevice(deviceID); 98 } 99 100 /** 101 * Returns the current device ID. 102 * 103 * @return current device ID 104 */ 105 const std::string& getDeviceID() const 106 { 107 return deviceID; 108 } 109 110 /** 111 * Returns the rule with the specified ID. 112 * 113 * Throws invalid_argument if no rule is found with specified ID. 114 * 115 * @param id rule ID 116 * @return rule with specified ID 117 */ 118 Rule& getRule(const std::string& id) const 119 { 120 return idMap.getRule(id); 121 } 122 123 /** 124 * Returns the current rule call stack depth. 125 * 126 * The depth is 0 if no rules have been called. 127 * 128 * @return rule call stack depth 129 */ 130 size_t getRuleDepth() const 131 { 132 return ruleDepth; 133 } 134 135 /** 136 * Returns the services in this action environment. 137 * 138 * @return system services 139 */ 140 Services& getServices() const 141 { 142 return services; 143 } 144 145 /** 146 * Returns the current volts value, if set. 147 * 148 * @return current volts value 149 */ 150 std::optional<double> getVolts() const 151 { 152 return volts; 153 } 154 155 /** 156 * Increments the rule call stack depth by one. 157 * 158 * Should be used when a rule is called. 159 * 160 * Throws runtime_error if the new depth exceeds maxRuleDepth. This 161 * indicates that infinite recursion has probably occurred (rule A -> rule B 162 * -> rule A). 163 * 164 * @param ruleID ID of the rule that is being called 165 */ 166 void incrementRuleDepth(const std::string& ruleID) 167 { 168 if (ruleDepth >= maxRuleDepth) 169 { 170 throw std::runtime_error("Maximum rule depth exceeded by rule " + 171 ruleID + '.'); 172 } 173 ++ruleDepth; 174 } 175 176 /** 177 * Sets the current device ID. 178 * 179 * @param id device ID 180 */ 181 void setDeviceID(const std::string& id) 182 { 183 deviceID = id; 184 } 185 186 /** 187 * Sets the current volts value. 188 * 189 * @param volts new volts value. 190 */ 191 void setVolts(double volts) 192 { 193 this->volts = volts; 194 } 195 196 private: 197 /** 198 * Mapping from string IDs to the associated Device and Rule objects. 199 */ 200 const IDMap& idMap; 201 202 /** 203 * Current device ID. 204 */ 205 std::string deviceID{}; 206 207 /** 208 * System services like error logging and the journal. 209 */ 210 Services& services; 211 212 /** 213 * Current volts value (if set). 214 */ 215 std::optional<double> volts{}; 216 217 /** 218 * Rule call stack depth. 219 */ 220 size_t ruleDepth{0}; 221 }; 222 223 } // namespace phosphor::power::regulators 224