1 //===-- MICmdInvoker.cpp ----------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "MICmdInvoker.h"
11 #include "MICmdBase.h"
14 #include "MICmnStreamStdout.h"
18 // Details: CMICmdInvoker constructor.
24 CMICmdInvoker::CMICmdInvoker() : m_rStreamOut(CMICmnStreamStdout::Instance()) {}
27 // Details: CMICmdInvoker destructor.
33 CMICmdInvoker::~CMICmdInvoker() { Shutdown(); }
36 // Details: Initialize resources for *this Command Invoker.
39 // Return: MIstatus::success - Functional succeeded.
40 // MIstatus::failure - Functional failed.
43 bool CMICmdInvoker::Initialize() {
44 m_clientUsageRefCnt++;
47 return MIstatus::success;
49 m_bInitialized = true;
51 return MIstatus::success;
55 // Details: Release resources for *this Stdin stream.
58 // Return: MIstatus::success - Functional succeeded.
59 // MIstatus::failure - Functional failed.
62 bool CMICmdInvoker::Shutdown() {
63 if (--m_clientUsageRefCnt > 0)
64 return MIstatus::success;
67 return MIstatus::success;
71 m_bInitialized = false;
73 return MIstatus::success;
77 // Details: Empty the map of invoked commands doing work. Command objects are
84 void CMICmdInvoker::CmdDeleteAll() {
85 CMICmdMgr &rMgr = CMICmdMgr::Instance();
86 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.begin();
87 while (it != m_mapCmdIdToCmd.end()) {
88 const MIuint cmdId((*it).first);
90 CMICmdBase *pCmd = (*it).second;
91 const CMIUtilString &rCmdName(pCmd->GetCmdData().strMiCmd);
93 rMgr.CmdDelete(pCmd->GetCmdData());
98 m_mapCmdIdToCmd.clear();
102 // Details: Remove from the map of invoked commands doing work a command that
104 // its work. The command object is deleted too.
106 // Args: vId - (R) Command object's unique ID.
107 // vbYesDeleteCmd - (R) True = Delete command object, false = delete
108 // via the Command Manager.
112 bool CMICmdInvoker::CmdDelete(const MIuint vId,
113 const bool vbYesDeleteCmd /*= false*/) {
114 CMICmdMgr &rMgr = CMICmdMgr::Instance();
115 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find(vId);
116 if (it != m_mapCmdIdToCmd.end()) {
117 CMICmdBase *pCmd = (*it).second;
118 if (vbYesDeleteCmd) {
119 // Via registered interest command manager callback *this object to delete
121 m_mapCmdIdToCmd.erase(it);
124 // Notify other interested object of this command's pending deletion
125 rMgr.CmdDelete(pCmd->GetCmdData());
128 if (m_mapCmdIdToCmd.empty())
129 rMgr.CmdUnregisterForDeleteNotification(*this);
131 return MIstatus::success;
135 // Details: Add to the map of invoked commands doing work a command that is
139 // Args: vCmd - (R) Command object.
143 bool CMICmdInvoker::CmdAdd(const CMICmdBase &vCmd) {
144 if (m_mapCmdIdToCmd.empty()) {
145 CMICmdMgr &rMgr = CMICmdMgr::Instance();
146 rMgr.CmdRegisterForDeleteNotification(*this);
149 const MIuint &cmdId(vCmd.GetCmdData().id);
150 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find(cmdId);
151 if (it != m_mapCmdIdToCmd.end())
152 return MIstatus::success;
154 MapPairCmdIdToCmd_t pr(cmdId, const_cast<CMICmdBase *>(&vCmd));
155 m_mapCmdIdToCmd.insert(pr);
157 return MIstatus::success;
161 // Details: Having previously had the potential command validated and found
163 // get the command executed.
164 // If the Functionality returns MIstatus::failure call
165 // GetErrorDescription().
166 // This function is used by the application's main thread.
168 // Args: vCmd - (RW) Command object.
169 // Return: MIstatus::success - Functionality succeeded.
170 // MIstatus::failure - Functionality failed.
173 bool CMICmdInvoker::CmdExecute(CMICmdBase &vCmd) {
174 bool bOk = CmdAdd(vCmd);
177 vCmd.AddCommonArgs();
178 if (!vCmd.ParseArgs()) {
179 // Report command execution failed
180 const SMICmdData cmdData(vCmd.GetCmdData());
182 CmdCauseAppExit(vCmd);
183 CmdDelete(cmdData.id);
185 // Proceed to wait or execute next command
186 return MIstatus::success;
190 if (bOk && !vCmd.Execute()) {
191 // Report command execution failed
192 const SMICmdData cmdData(vCmd.GetCmdData());
194 CmdCauseAppExit(vCmd);
195 CmdDelete(cmdData.id);
197 // Proceed to wait or execute next command
198 return MIstatus::success;
201 bOk = CmdExecuteFinished(vCmd);
207 // Details: Called when a command has finished its Execution() work either
209 // because the command executed was the type a non event type or
211 // via the command's callback (because of an SB Listener event). Needs
213 // so that *this invoker call do some house keeping and then proceed to
215 // the command's Acknowledge() function.
217 // Args: vCmd - (R) Command object.
218 // Return: MIstatus::success - Functionality succeeded.
219 // MIstatus::failure - Functionality failed.
222 bool CMICmdInvoker::CmdExecuteFinished(CMICmdBase &vCmd) {
223 // Command finished now get the command to gather it's information and form
226 if (!vCmd.Acknowledge()) {
227 // Report command acknowledge functionality failed
228 const SMICmdData cmdData(vCmd.GetCmdData());
230 CmdCauseAppExit(vCmd);
231 CmdDelete(cmdData.id);
233 // Proceed to wait or execute next command
234 return MIstatus::success;
237 // Retrieve the command's latest data/information. Needed for commands of the
238 // event type so have
239 // a record of commands pending finishing execution.
240 const CMIUtilString &rMIResultRecord(vCmd.GetMIResultRecord());
242 vCmd.GetCmdData()); // Make a copy as the command will be deleted soon
243 cmdData.strMiCmdResultRecord = rMIResultRecord; // Precautionary copy as the
244 // command might forget to do
246 if (vCmd.HasMIResultRecordExtra()) {
247 cmdData.bHasResultRecordExtra = true;
248 const CMIUtilString &rMIExtra(vCmd.GetMIResultRecordExtra());
249 cmdData.strMiCmdResultRecordExtra =
250 rMIExtra; // Precautionary copy as the command might forget to do this
253 // Send command's MI response to the client
254 bool bOk = CmdStdout(cmdData);
256 // Delete the command object as do not require anymore
257 bOk = bOk && CmdDelete(vCmd.GetCmdData().id);
263 // Details: If the MI Driver is not operating via a client i.e. Eclipse check
265 // on failure suggests the application exits. A command can be such
267 // failure cannot the allow the application to continue operating.
268 // Args: vCmd - (R) Command object.
273 void CMICmdInvoker::CmdCauseAppExit(const CMICmdBase &vCmd) const {
274 if (vCmd.GetExitAppOnCommandFailure()) {
275 CMIDriver &rDriver(CMIDriver::Instance());
276 if (rDriver.IsDriverDebuggingArgExecutable()) {
277 rDriver.SetExitApplicationFlag(true);
283 // Details: Write to stdout and the Log file the command's MI formatted result.
284 // Type: vCmdData - (R) A command's information.
285 // Return: MIstatus::success - Functionality succeeded.
286 // MIstatus::failure - Functionality failed.
290 bool CMICmdInvoker::CmdStdout(const SMICmdData &vCmdData) const {
291 bool bOk = m_pLog->WriteLog(vCmdData.strMiCmdAll);
292 const bool bLock = bOk && m_rStreamOut.Lock();
293 bOk = bOk && bLock &&
294 m_rStreamOut.WriteMIResponse(vCmdData.strMiCmdResultRecord);
295 if (bOk && vCmdData.bHasResultRecordExtra) {
296 bOk = m_rStreamOut.WriteMIResponse(vCmdData.strMiCmdResultRecordExtra);
298 bOk = bLock && m_rStreamOut.Unlock();
304 // Details: Required by the CMICmdMgr::ICmdDeleteCallback. *this object is
306 // with the Command Manager to receive callbacks when a command is
308 // An object, *this invoker, does not delete a command object itself
310 // the Command Manager to delete a command object. This function is the
313 // The Invoker owns the command objects and so can delete them but must
315 // via the manager so other objects can be notified of the deletion.
317 // Args: vCmd - (RW) Command.
321 void CMICmdInvoker::Delete(SMICmdData &vCmd) { CmdDelete(vCmd.id, true); }