158b2b53eSCheng C Yang /*
258b2b53eSCheng C Yang // Copyright (c) 2019 Intel Corporation
358b2b53eSCheng C Yang //
458b2b53eSCheng C Yang // Licensed under the Apache License, Version 2.0 (the "License");
558b2b53eSCheng C Yang // you may not use this file except in compliance with the License.
658b2b53eSCheng C Yang // You may obtain a copy of the License at
758b2b53eSCheng C Yang //
858b2b53eSCheng C Yang // http://www.apache.org/licenses/LICENSE-2.0
958b2b53eSCheng C Yang //
1058b2b53eSCheng C Yang // Unless required by applicable law or agreed to in writing, software
1158b2b53eSCheng C Yang // distributed under the License is distributed on an "AS IS" BASIS,
1258b2b53eSCheng C Yang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1358b2b53eSCheng C Yang // See the License for the specific language governing permissions and
1458b2b53eSCheng C Yang // limitations under the License.
1558b2b53eSCheng C Yang */
1658b2b53eSCheng C Yang
17e73bd0a1SAndrew Jeffery #include "PSUEvent.hpp"
18e73bd0a1SAndrew Jeffery
19e73bd0a1SAndrew Jeffery #include "SensorPaths.hpp"
20eacbfdd1SEd Tanous #include "Utils.hpp"
21e73bd0a1SAndrew Jeffery
22eacbfdd1SEd Tanous #include <boost/asio/buffer.hpp>
23eacbfdd1SEd Tanous #include <boost/asio/error.hpp>
241f978631SEd Tanous #include <boost/asio/io_context.hpp>
25eacbfdd1SEd Tanous #include <boost/asio/random_access_file.hpp>
2696e97db7SPatrick Venture #include <boost/container/flat_map.hpp>
270c42f40eSPatrick Williams #include <phosphor-logging/lg2.hpp>
2858b2b53eSCheng C Yang #include <sdbusplus/asio/connection.hpp>
2958b2b53eSCheng C Yang #include <sdbusplus/asio/object_server.hpp>
3038fb5983SJames Feist
31eacbfdd1SEd Tanous #include <array>
32eacbfdd1SEd Tanous #include <chrono>
33eacbfdd1SEd Tanous #include <cstddef>
3438fb5983SJames Feist #include <iostream>
3538fb5983SJames Feist #include <memory>
36eacbfdd1SEd Tanous #include <set>
3796e97db7SPatrick Venture #include <stdexcept>
3896e97db7SPatrick Venture #include <string>
3996e97db7SPatrick Venture #include <utility>
4096e97db7SPatrick Venture #include <vector>
4158b2b53eSCheng C Yang
PSUCombineEvent(sdbusplus::asio::object_server & objectServer,std::shared_ptr<sdbusplus::asio::connection> & conn,boost::asio::io_context & io,const std::string & psuName,const PowerState & powerState,EventPathList & eventPathList,GroupEventPathList & groupEventPathList,const std::string & combineEventName,double pollRate)4258b2b53eSCheng C Yang PSUCombineEvent::PSUCombineEvent(
433046a024SYong Li sdbusplus::asio::object_server& objectServer,
443046a024SYong Li std::shared_ptr<sdbusplus::asio::connection>& conn,
451f978631SEd Tanous boost::asio::io_context& io, const std::string& psuName,
465b3542eaSGeorge Liu const PowerState& powerState, EventPathList& eventPathList,
475b3542eaSGeorge Liu GroupEventPathList& groupEventPathList, const std::string& combineEventName,
48*2aaf7175SPatrick Williams double pollRate) : objServer(objectServer)
4958b2b53eSCheng C Yang {
506cb732a3SEd Tanous std::string psuNameEscaped = sensor_paths::escapePathForDbus(psuName);
5158b2b53eSCheng C Yang eventInterface = objServer.add_interface(
526cb732a3SEd Tanous "/xyz/openbmc_project/State/Decorator/" + psuNameEscaped + "_" +
5358b2b53eSCheng C Yang combineEventName,
5458b2b53eSCheng C Yang "xyz.openbmc_project.State.Decorator.OperationalStatus");
55b6c0b914SJames Feist eventInterface->register_property("functional", true);
5658b2b53eSCheng C Yang
5758b2b53eSCheng C Yang if (!eventInterface->initialize())
5858b2b53eSCheng C Yang {
5958b2b53eSCheng C Yang std::cerr << "error initializing event interface\n";
6058b2b53eSCheng C Yang }
6158b2b53eSCheng C Yang
6258b2b53eSCheng C Yang std::shared_ptr<std::set<std::string>> combineEvent =
6358b2b53eSCheng C Yang std::make_shared<std::set<std::string>>();
64b85145cfSZev Weiss for (const auto& [eventName, paths] : eventPathList)
6558b2b53eSCheng C Yang {
66591b1e42SYong Li std::shared_ptr<std::set<std::string>> assert =
67591b1e42SYong Li std::make_shared<std::set<std::string>>();
68202a1ff0SCheng C Yang std::shared_ptr<bool> state = std::make_shared<bool>(false);
69591b1e42SYong Li
7058b2b53eSCheng C Yang std::string eventPSUName = eventName + psuName;
71b85145cfSZev Weiss for (const auto& path : paths)
7258b2b53eSCheng C Yang {
73bf8b1dadSYong Li auto p = std::make_shared<PSUSubEvent>(
74c7a1ae6bSKonstantin Aladyshev eventInterface, path, conn, io, powerState, eventName,
75c7a1ae6bSKonstantin Aladyshev eventName, assert, combineEvent, state, psuName, pollRate);
76bf8b1dadSYong Li p->setupRead();
77bf8b1dadSYong Li
78bf8b1dadSYong Li events[eventPSUName].emplace_back(p);
7958b2b53eSCheng C Yang asserts.emplace_back(assert);
8058b2b53eSCheng C Yang states.emplace_back(state);
8158b2b53eSCheng C Yang }
8258b2b53eSCheng C Yang }
83202a1ff0SCheng C Yang
84b85145cfSZev Weiss for (const auto& [eventName, groupEvents] : groupEventPathList)
85202a1ff0SCheng C Yang {
86b85145cfSZev Weiss for (const auto& [groupEventName, paths] : groupEvents)
87202a1ff0SCheng C Yang {
88202a1ff0SCheng C Yang std::shared_ptr<std::set<std::string>> assert =
89202a1ff0SCheng C Yang std::make_shared<std::set<std::string>>();
90202a1ff0SCheng C Yang std::shared_ptr<bool> state = std::make_shared<bool>(false);
91202a1ff0SCheng C Yang
92202a1ff0SCheng C Yang std::string eventPSUName = groupEventName + psuName;
93b85145cfSZev Weiss for (const auto& path : paths)
94202a1ff0SCheng C Yang {
95bf8b1dadSYong Li auto p = std::make_shared<PSUSubEvent>(
96c7a1ae6bSKonstantin Aladyshev eventInterface, path, conn, io, powerState, groupEventName,
97b85145cfSZev Weiss eventName, assert, combineEvent, state, psuName, pollRate);
98bf8b1dadSYong Li p->setupRead();
99bf8b1dadSYong Li events[eventPSUName].emplace_back(p);
100bf8b1dadSYong Li
101202a1ff0SCheng C Yang asserts.emplace_back(assert);
102202a1ff0SCheng C Yang states.emplace_back(state);
103202a1ff0SCheng C Yang }
104202a1ff0SCheng C Yang }
105202a1ff0SCheng C Yang }
10658b2b53eSCheng C Yang }
10758b2b53eSCheng C Yang
~PSUCombineEvent()10858b2b53eSCheng C Yang PSUCombineEvent::~PSUCombineEvent()
10958b2b53eSCheng C Yang {
110202a1ff0SCheng C Yang // Clear unique_ptr first
111b85145cfSZev Weiss for (auto& [psuName, subEvents] : events)
112202a1ff0SCheng C Yang {
113b85145cfSZev Weiss for (auto& subEventPtr : subEvents)
114202a1ff0SCheng C Yang {
115202a1ff0SCheng C Yang subEventPtr.reset();
116202a1ff0SCheng C Yang }
117202a1ff0SCheng C Yang }
11858b2b53eSCheng C Yang events.clear();
11958b2b53eSCheng C Yang objServer.remove_interface(eventInterface);
12058b2b53eSCheng C Yang }
12158b2b53eSCheng C Yang
1229b53a628SCheng C Yang static boost::container::flat_map<std::string,
1239b53a628SCheng C Yang std::pair<std::string, std::string>>
1249b53a628SCheng C Yang logID = {
1259b53a628SCheng C Yang {"PredictiveFailure",
1269b53a628SCheng C Yang {"OpenBMC.0.1.PowerSupplyFailurePredicted",
1279b53a628SCheng C Yang "OpenBMC.0.1.PowerSupplyPredictedFailureRecovered"}},
1289b53a628SCheng C Yang {"Failure",
1299b53a628SCheng C Yang {"OpenBMC.0.1.PowerSupplyFailed", "OpenBMC.0.1.PowerSupplyRecovered"}},
1309b53a628SCheng C Yang {"ACLost",
131bb732ef8SCheng C Yang {"OpenBMC.0.1.PowerSupplyPowerLost",
132bb732ef8SCheng C Yang "OpenBMC.0.1.PowerSupplyPowerRestored"}},
1339b53a628SCheng C Yang {"FanFault",
1349b53a628SCheng C Yang {"OpenBMC.0.1.PowerSupplyFanFailed",
1359b53a628SCheng C Yang "OpenBMC.0.1.PowerSupplyFanRecovered"}},
136d12f23ecSjayaprakash Mutyala {"ConfigureError",
137d12f23ecSjayaprakash Mutyala {"OpenBMC.0.1.PowerSupplyConfigurationError",
138d12f23ecSjayaprakash Mutyala "OpenBMC.0.1.PowerSupplyConfigurationErrorRecovered"}}};
1395665db2bSCheng C Yang
PSUSubEvent(std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,const std::string & path,std::shared_ptr<sdbusplus::asio::connection> & conn,boost::asio::io_context & io,const PowerState & powerState,const std::string & groupEventName,const std::string & eventName,std::shared_ptr<std::set<std::string>> asserts,std::shared_ptr<std::set<std::string>> combineEvent,std::shared_ptr<bool> state,const std::string & psuName,double pollRate)14058b2b53eSCheng C Yang PSUSubEvent::PSUSubEvent(
14158b2b53eSCheng C Yang std::shared_ptr<sdbusplus::asio::dbus_interface> eventInterface,
1423046a024SYong Li const std::string& path, std::shared_ptr<sdbusplus::asio::connection>& conn,
1431f978631SEd Tanous boost::asio::io_context& io, const PowerState& powerState,
144c7a1ae6bSKonstantin Aladyshev const std::string& groupEventName, const std::string& eventName,
14558b2b53eSCheng C Yang std::shared_ptr<std::set<std::string>> asserts,
14658b2b53eSCheng C Yang std::shared_ptr<std::set<std::string>> combineEvent,
1477170a235SLei YU std::shared_ptr<bool> state, const std::string& psuName, double pollRate) :
148*2aaf7175SPatrick Williams eventInterface(std::move(eventInterface)), asserts(std::move(asserts)),
149*2aaf7175SPatrick Williams combineEvent(std::move(combineEvent)), assertState(std::move(state)),
150*2aaf7175SPatrick Williams path(path), eventName(eventName), readState(powerState), waitTimer(io),
15116966b55SEd Tanous
15216966b55SEd Tanous inputDev(io, path, boost::asio::random_access_file::read_only),
15316966b55SEd Tanous psuName(psuName), groupEventName(groupEventName), systemBus(conn)
15458b2b53eSCheng C Yang {
15516966b55SEd Tanous buffer = std::make_shared<std::array<char, 128>>();
1567170a235SLei YU if (pollRate > 0.0)
1577170a235SLei YU {
1587170a235SLei YU eventPollMs = static_cast<unsigned int>(pollRate * 1000);
1597170a235SLei YU }
16099c4409aSEd Tanous
1615665db2bSCheng C Yang auto found = logID.find(eventName);
1625665db2bSCheng C Yang if (found == logID.end())
1635665db2bSCheng C Yang {
1649b53a628SCheng C Yang assertMessage.clear();
1659b53a628SCheng C Yang deassertMessage.clear();
1665665db2bSCheng C Yang }
1675665db2bSCheng C Yang else
1685665db2bSCheng C Yang {
1699b53a628SCheng C Yang assertMessage = found->second.first;
1709b53a628SCheng C Yang deassertMessage = found->second.second;
1715665db2bSCheng C Yang }
1725665db2bSCheng C Yang
1735665db2bSCheng C Yang auto fanPos = path.find("fan");
1745665db2bSCheng C Yang if (fanPos != std::string::npos)
1755665db2bSCheng C Yang {
1765665db2bSCheng C Yang fanName = path.substr(fanPos);
1778a57ec09SEd Tanous auto fanNamePos = fanName.find('_');
1789b53a628SCheng C Yang if (fanNamePos != std::string::npos)
1799b53a628SCheng C Yang {
1809b53a628SCheng C Yang fanName = fanName.substr(0, fanNamePos);
1819b53a628SCheng C Yang }
1825665db2bSCheng C Yang }
18358b2b53eSCheng C Yang }
18458b2b53eSCheng C Yang
~PSUSubEvent()185c7a1ae6bSKonstantin Aladyshev PSUSubEvent::~PSUSubEvent()
186c7a1ae6bSKonstantin Aladyshev {
187c7a1ae6bSKonstantin Aladyshev waitTimer.cancel();
188c7a1ae6bSKonstantin Aladyshev inputDev.close();
189c7a1ae6bSKonstantin Aladyshev }
190c7a1ae6bSKonstantin Aladyshev
setupRead()191201a1015SEd Tanous void PSUSubEvent::setupRead()
19258b2b53eSCheng C Yang {
193c7a1ae6bSKonstantin Aladyshev if (!readingStateGood(readState))
194c7a1ae6bSKonstantin Aladyshev {
195c7a1ae6bSKonstantin Aladyshev // Deassert the event
196c7a1ae6bSKonstantin Aladyshev updateValue(0);
197c7a1ae6bSKonstantin Aladyshev restartRead();
198c7a1ae6bSKonstantin Aladyshev return;
199c7a1ae6bSKonstantin Aladyshev }
20016966b55SEd Tanous if (!buffer)
20116966b55SEd Tanous {
20216966b55SEd Tanous std::cerr << "Buffer was invalid?";
20316966b55SEd Tanous return;
20416966b55SEd Tanous }
205c7a1ae6bSKonstantin Aladyshev
206bf8b1dadSYong Li std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
20716966b55SEd Tanous inputDev.async_read_some_at(
20816966b55SEd Tanous 0, boost::asio::buffer(buffer->data(), buffer->size() - 1),
20916966b55SEd Tanous [weakRef, buffer{buffer}](const boost::system::error_code& ec,
21016966b55SEd Tanous std::size_t bytesTransferred) {
211bf8b1dadSYong Li std::shared_ptr<PSUSubEvent> self = weakRef.lock();
212bf8b1dadSYong Li if (self)
213bf8b1dadSYong Li {
21416966b55SEd Tanous self->handleResponse(ec, bytesTransferred);
215bf8b1dadSYong Li }
216bf8b1dadSYong Li });
21758b2b53eSCheng C Yang }
21858b2b53eSCheng C Yang
restartRead()219c7a1ae6bSKonstantin Aladyshev void PSUSubEvent::restartRead()
22058b2b53eSCheng C Yang {
221c7a1ae6bSKonstantin Aladyshev std::weak_ptr<PSUSubEvent> weakRef = weak_from_this();
22283db50caSEd Tanous waitTimer.expires_after(std::chrono::milliseconds(eventPollMs));
223c7a1ae6bSKonstantin Aladyshev waitTimer.async_wait([weakRef](const boost::system::error_code& ec) {
224c7a1ae6bSKonstantin Aladyshev if (ec == boost::asio::error::operation_aborted)
225c7a1ae6bSKonstantin Aladyshev {
226c7a1ae6bSKonstantin Aladyshev return;
227c7a1ae6bSKonstantin Aladyshev }
228c7a1ae6bSKonstantin Aladyshev std::shared_ptr<PSUSubEvent> self = weakRef.lock();
229c7a1ae6bSKonstantin Aladyshev if (self)
230c7a1ae6bSKonstantin Aladyshev {
231c7a1ae6bSKonstantin Aladyshev self->setupRead();
232c7a1ae6bSKonstantin Aladyshev }
233c7a1ae6bSKonstantin Aladyshev });
23458b2b53eSCheng C Yang }
23558b2b53eSCheng C Yang
handleResponse(const boost::system::error_code & err,size_t bytesTransferred)23616966b55SEd Tanous void PSUSubEvent::handleResponse(const boost::system::error_code& err,
23716966b55SEd Tanous size_t bytesTransferred)
23858b2b53eSCheng C Yang {
23916966b55SEd Tanous if (err == boost::asio::error::operation_aborted)
24016966b55SEd Tanous {
24116966b55SEd Tanous return;
24216966b55SEd Tanous }
24316966b55SEd Tanous
244bf8b1dadSYong Li if ((err == boost::system::errc::bad_file_descriptor) ||
245bf8b1dadSYong Li (err == boost::asio::error::misc_errors::not_found))
24658b2b53eSCheng C Yang {
24758b2b53eSCheng C Yang return;
24858b2b53eSCheng C Yang }
24916966b55SEd Tanous if (!buffer)
25016966b55SEd Tanous {
25116966b55SEd Tanous std::cerr << "Buffer was invalid?";
25216966b55SEd Tanous return;
25316966b55SEd Tanous }
25416966b55SEd Tanous // null terminate the string so we don't walk off the end
25516966b55SEd Tanous std::array<char, 128>& bufferRef = *buffer;
25616966b55SEd Tanous bufferRef[bytesTransferred] = '\0';
25716966b55SEd Tanous
25858b2b53eSCheng C Yang if (!err)
25958b2b53eSCheng C Yang {
26058b2b53eSCheng C Yang try
26158b2b53eSCheng C Yang {
26216966b55SEd Tanous int nvalue = std::stoi(bufferRef.data());
26358b2b53eSCheng C Yang updateValue(nvalue);
26458b2b53eSCheng C Yang errCount = 0;
26558b2b53eSCheng C Yang }
26658b2b53eSCheng C Yang catch (const std::invalid_argument&)
26758b2b53eSCheng C Yang {
26858b2b53eSCheng C Yang errCount++;
26958b2b53eSCheng C Yang }
27058b2b53eSCheng C Yang }
27158b2b53eSCheng C Yang else
27258b2b53eSCheng C Yang {
27358b2b53eSCheng C Yang errCount++;
27458b2b53eSCheng C Yang }
27558b2b53eSCheng C Yang if (errCount >= warnAfterErrorCount)
27658b2b53eSCheng C Yang {
27758b2b53eSCheng C Yang if (errCount == warnAfterErrorCount)
27858b2b53eSCheng C Yang {
27958b2b53eSCheng C Yang std::cerr << "Failure to read event at " << path << "\n";
28058b2b53eSCheng C Yang }
28158b2b53eSCheng C Yang updateValue(0);
28258b2b53eSCheng C Yang errCount++;
28358b2b53eSCheng C Yang }
284c7a1ae6bSKonstantin Aladyshev restartRead();
28558b2b53eSCheng C Yang }
28658b2b53eSCheng C Yang
28758b2b53eSCheng C Yang // Any of the sub events of one event is asserted, then the event will be
28858b2b53eSCheng C Yang // asserted. Only if none of the sub events are asserted, the event will be
28958b2b53eSCheng C Yang // deasserted.
updateValue(const int & newValue)29058b2b53eSCheng C Yang void PSUSubEvent::updateValue(const int& newValue)
29158b2b53eSCheng C Yang {
292833661aeSJosh Lehan // Take no action if value already equal
293833661aeSJosh Lehan // Same semantics as Sensor::updateValue(const double&)
294833661aeSJosh Lehan if (newValue == value)
295833661aeSJosh Lehan {
296833661aeSJosh Lehan return;
297833661aeSJosh Lehan }
298833661aeSJosh Lehan
29958b2b53eSCheng C Yang if (newValue == 0)
30058b2b53eSCheng C Yang {
301591b1e42SYong Li // log deassert only after all asserts are gone
302591b1e42SYong Li if (!(*asserts).empty())
303591b1e42SYong Li {
30458b2b53eSCheng C Yang auto found = (*asserts).find(path);
30558b2b53eSCheng C Yang if (found == (*asserts).end())
30658b2b53eSCheng C Yang {
30758b2b53eSCheng C Yang return;
30858b2b53eSCheng C Yang }
3099b53a628SCheng C Yang (*asserts).erase(path);
31058b2b53eSCheng C Yang
31158b2b53eSCheng C Yang return;
31258b2b53eSCheng C Yang }
3132049bd26SEd Tanous if (*assertState)
31458b2b53eSCheng C Yang {
31558b2b53eSCheng C Yang *assertState = false;
316202a1ff0SCheng C Yang auto foundCombine = (*combineEvent).find(groupEventName);
3179b53a628SCheng C Yang if (foundCombine == (*combineEvent).end())
31858b2b53eSCheng C Yang {
31958b2b53eSCheng C Yang return;
32058b2b53eSCheng C Yang }
321202a1ff0SCheng C Yang (*combineEvent).erase(groupEventName);
3229b53a628SCheng C Yang if (!deassertMessage.empty())
3239b53a628SCheng C Yang {
3249b53a628SCheng C Yang // Fan Failed has two args
3259b53a628SCheng C Yang if (deassertMessage == "OpenBMC.0.1.PowerSupplyFanRecovered")
3269b53a628SCheng C Yang {
3270c42f40eSPatrick Williams lg2::info("{EVENT} deassert", "EVENT", eventName,
3280c42f40eSPatrick Williams "REDFISH_MESSAGE_ID", deassertMessage,
3290c42f40eSPatrick Williams "REDFISH_MESSAGE_ARGS",
3300c42f40eSPatrick Williams (psuName + ',' + fanName));
3319b53a628SCheng C Yang }
3329b53a628SCheng C Yang else
3339b53a628SCheng C Yang {
3340c42f40eSPatrick Williams lg2::info("{EVENT} deassert", "EVENT", eventName,
3350c42f40eSPatrick Williams "REDFISH_MESSAGE_ID", deassertMessage,
3360c42f40eSPatrick Williams "REDFISH_MESSAGE_ARGS", psuName);
3379b53a628SCheng C Yang }
3389b53a628SCheng C Yang }
3399b53a628SCheng C Yang
34058b2b53eSCheng C Yang if ((*combineEvent).empty())
34158b2b53eSCheng C Yang {
34258b2b53eSCheng C Yang eventInterface->set_property("functional", true);
34358b2b53eSCheng C Yang }
34458b2b53eSCheng C Yang }
34558b2b53eSCheng C Yang }
34658b2b53eSCheng C Yang else
34758b2b53eSCheng C Yang {
3483453354bSPaul Fertser std::cerr << "PSUSubEvent asserted by " << path << "\n";
3493453354bSPaul Fertser
3502049bd26SEd Tanous if ((!*assertState) && ((*asserts).empty()))
35158b2b53eSCheng C Yang {
35258b2b53eSCheng C Yang *assertState = true;
3539b53a628SCheng C Yang if (!assertMessage.empty())
3545665db2bSCheng C Yang {
3555665db2bSCheng C Yang // Fan Failed has two args
3569b53a628SCheng C Yang if (assertMessage == "OpenBMC.0.1.PowerSupplyFanFailed")
3575665db2bSCheng C Yang {
3580c42f40eSPatrick Williams lg2::warning("{EVENT} assert", "EVENT", eventName,
3590c42f40eSPatrick Williams "REDFISH_MESSAGE_ID", assertMessage,
3600c42f40eSPatrick Williams "REDFISH_MESSAGE_ARGS",
3610c42f40eSPatrick Williams (psuName + ',' + fanName));
3625665db2bSCheng C Yang }
3635665db2bSCheng C Yang else
3645665db2bSCheng C Yang {
3650c42f40eSPatrick Williams lg2::warning("{EVENT} assert", "EVENT", eventName,
3660c42f40eSPatrick Williams "REDFISH_MESSAGE_ID", assertMessage,
3670c42f40eSPatrick Williams "REDFISH_MESSAGE_ARGS", psuName);
3685665db2bSCheng C Yang }
3695665db2bSCheng C Yang }
37058b2b53eSCheng C Yang if ((*combineEvent).empty())
37158b2b53eSCheng C Yang {
37258b2b53eSCheng C Yang eventInterface->set_property("functional", false);
37358b2b53eSCheng C Yang }
374202a1ff0SCheng C Yang (*combineEvent).emplace(groupEventName);
37558b2b53eSCheng C Yang }
376591b1e42SYong Li (*asserts).emplace(path);
37758b2b53eSCheng C Yang }
37858b2b53eSCheng C Yang value = newValue;
37958b2b53eSCheng C Yang }
380