1 //===-- MICmdInvoker.cpp ----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 #include "MICmdInvoker.h"
12 #include "MICmdBase.h"
15 #include "MICmnStreamStdout.h"
19 //------------------------------------------------------------------------------------
20 // Details: CMICmdInvoker constructor.
26 CMICmdInvoker::CMICmdInvoker() : m_rStreamOut(CMICmnStreamStdout::Instance()) {}
29 //------------------------------------------------------------------------------------
30 // Details: CMICmdInvoker destructor.
36 CMICmdInvoker::~CMICmdInvoker() { Shutdown(); }
39 //------------------------------------------------------------------------------------
40 // Details: Initialize resources for *this Command Invoker.
43 // Return: MIstatus::success - Functional succeeded.
44 // MIstatus::failure - Functional failed.
47 bool CMICmdInvoker::Initialize() {
48 m_clientUsageRefCnt++;
51 return MIstatus::success;
53 m_bInitialized = true;
55 return MIstatus::success;
59 //------------------------------------------------------------------------------------
60 // Details: Release resources for *this Stdin stream.
63 // Return: MIstatus::success - Functional succeeded.
64 // MIstatus::failure - Functional failed.
67 bool CMICmdInvoker::Shutdown() {
68 if (--m_clientUsageRefCnt > 0)
69 return MIstatus::success;
72 return MIstatus::success;
76 m_bInitialized = false;
78 return MIstatus::success;
82 //------------------------------------------------------------------------------------
83 // Details: Empty the map of invoked commands doing work. Command objects are
90 void CMICmdInvoker::CmdDeleteAll() {
91 CMICmdMgr &rMgr = CMICmdMgr::Instance();
92 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.begin();
93 while (it != m_mapCmdIdToCmd.end()) {
94 const MIuint cmdId((*it).first);
96 CMICmdBase *pCmd = (*it).second;
97 const CMIUtilString &rCmdName(pCmd->GetCmdData().strMiCmd);
99 rMgr.CmdDelete(pCmd->GetCmdData());
104 m_mapCmdIdToCmd.clear();
108 //------------------------------------------------------------------------------------
109 // Details: Remove from the map of invoked commands doing work a command that
111 // its work. The command object is deleted too.
113 // Args: vId - (R) Command object's unique ID.
114 // vbYesDeleteCmd - (R) True = Delete command object, false = delete
115 // via the Command Manager.
119 bool CMICmdInvoker::CmdDelete(const MIuint vId,
120 const bool vbYesDeleteCmd /*= false*/) {
121 CMICmdMgr &rMgr = CMICmdMgr::Instance();
122 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find(vId);
123 if (it != m_mapCmdIdToCmd.end()) {
124 CMICmdBase *pCmd = (*it).second;
125 if (vbYesDeleteCmd) {
126 // Via registered interest command manager callback *this object to delete
128 m_mapCmdIdToCmd.erase(it);
131 // Notify other interested object of this command's pending deletion
132 rMgr.CmdDelete(pCmd->GetCmdData());
135 if (m_mapCmdIdToCmd.empty())
136 rMgr.CmdUnregisterForDeleteNotification(*this);
138 return MIstatus::success;
142 //------------------------------------------------------------------------------------
143 // Details: Add to the map of invoked commands doing work a command that is
147 // Args: vCmd - (R) Command object.
151 bool CMICmdInvoker::CmdAdd(const CMICmdBase &vCmd) {
152 if (m_mapCmdIdToCmd.empty()) {
153 CMICmdMgr &rMgr = CMICmdMgr::Instance();
154 rMgr.CmdRegisterForDeleteNotification(*this);
157 const MIuint &cmdId(vCmd.GetCmdData().id);
158 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find(cmdId);
159 if (it != m_mapCmdIdToCmd.end())
160 return MIstatus::success;
162 MapPairCmdIdToCmd_t pr(cmdId, const_cast<CMICmdBase *>(&vCmd));
163 m_mapCmdIdToCmd.insert(pr);
165 return MIstatus::success;
169 //------------------------------------------------------------------------------------
170 // Details: Having previously had the potential command validated and found
172 // get the command executed.
173 // If the Functionality returns MIstatus::failure call
174 // GetErrorDescription().
175 // This function is used by the application's main thread.
177 // Args: vCmd - (RW) Command object.
178 // Return: MIstatus::success - Functionality succeeded.
179 // MIstatus::failure - Functionality failed.
182 bool CMICmdInvoker::CmdExecute(CMICmdBase &vCmd) {
183 bool bOk = CmdAdd(vCmd);
186 vCmd.AddCommonArgs();
187 if (!vCmd.ParseArgs()) {
188 // Report command execution failed
189 const SMICmdData cmdData(vCmd.GetCmdData());
191 CmdCauseAppExit(vCmd);
192 CmdDelete(cmdData.id);
194 // Proceed to wait or execute next command
195 return MIstatus::success;
199 if (bOk && !vCmd.Execute()) {
200 // Report command execution failed
201 const SMICmdData cmdData(vCmd.GetCmdData());
203 CmdCauseAppExit(vCmd);
204 CmdDelete(cmdData.id);
206 // Proceed to wait or execute next command
207 return MIstatus::success;
210 bOk = CmdExecuteFinished(vCmd);
216 //------------------------------------------------------------------------------------
217 // Details: Called when a command has finished its Execution() work either
219 // because the command executed was the type a non event type or
221 // via the command's callback (because of an SB Listener event). Needs
223 // so that *this invoker call do some house keeping and then proceed to
225 // the command's Acknowledge() function.
227 // Args: vCmd - (R) Command object.
228 // Return: MIstatus::success - Functionality succeeded.
229 // MIstatus::failure - Functionality failed.
232 bool CMICmdInvoker::CmdExecuteFinished(CMICmdBase &vCmd) {
233 // Command finished now get the command to gather it's information and form
236 if (!vCmd.Acknowledge()) {
237 // Report command acknowledge functionality failed
238 const SMICmdData cmdData(vCmd.GetCmdData());
240 CmdCauseAppExit(vCmd);
241 CmdDelete(cmdData.id);
243 // Proceed to wait or execute next command
244 return MIstatus::success;
247 // Retrieve the command's latest data/information. Needed for commands of the
248 // event type so have
249 // a record of commands pending finishing execution.
250 const CMIUtilString &rMIResultRecord(vCmd.GetMIResultRecord());
252 vCmd.GetCmdData()); // Make a copy as the command will be deleted soon
253 cmdData.strMiCmdResultRecord = rMIResultRecord; // Precautionary copy as the
254 // command might forget to do
256 if (vCmd.HasMIResultRecordExtra()) {
257 cmdData.bHasResultRecordExtra = true;
258 const CMIUtilString &rMIExtra(vCmd.GetMIResultRecordExtra());
259 cmdData.strMiCmdResultRecordExtra =
260 rMIExtra; // Precautionary copy as the command might forget to do this
263 // Send command's MI response to the client
264 bool bOk = CmdStdout(cmdData);
266 // Delete the command object as do not require anymore
267 bOk = bOk && CmdDelete(vCmd.GetCmdData().id);
273 //------------------------------------------------------------------------------------
274 // Details: If the MI Driver is not operating via a client i.e. Eclipse check
276 // on failure suggests the application exits. A command can be such
278 // failure cannot the allow the application to continue operating.
279 // Args: vCmd - (R) Command object.
284 void CMICmdInvoker::CmdCauseAppExit(const CMICmdBase &vCmd) const {
285 if (vCmd.GetExitAppOnCommandFailure()) {
286 CMIDriver &rDriver(CMIDriver::Instance());
287 if (rDriver.IsDriverDebuggingArgExecutable()) {
288 rDriver.SetExitApplicationFlag(true);
294 //------------------------------------------------------------------------------------
295 // Details: Write to stdout and the Log file the command's MI formatted result.
296 // Type: vCmdData - (R) A command's information.
297 // Return: MIstatus::success - Functionality succeeded.
298 // MIstatus::failure - Functionality failed.
302 bool CMICmdInvoker::CmdStdout(const SMICmdData &vCmdData) const {
303 bool bOk = m_pLog->WriteLog(vCmdData.strMiCmdAll);
304 const bool bLock = bOk && m_rStreamOut.Lock();
305 bOk = bOk && bLock &&
306 m_rStreamOut.WriteMIResponse(vCmdData.strMiCmdResultRecord);
307 if (bOk && vCmdData.bHasResultRecordExtra) {
308 bOk = m_rStreamOut.WriteMIResponse(vCmdData.strMiCmdResultRecordExtra);
310 bOk = bLock && m_rStreamOut.Unlock();
316 //------------------------------------------------------------------------------------
317 // Details: Required by the CMICmdMgr::ICmdDeleteCallback. *this object is
319 // with the Command Manager to receive callbacks when a command is
321 // An object, *this invoker, does not delete a command object itself
323 // the Command Manager to delete a command object. This function is the
326 // The Invoker owns the command objects and so can delete them but must
328 // via the manager so other objects can be notified of the deletion.
330 // Args: vCmd - (RW) Command.
334 void CMICmdInvoker::Delete(SMICmdData &vCmd) { CmdDelete(vCmd.id, true); }