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"
18 //++ ------------------------------------------------------------------------------------
19 // Details: CMICmdInvoker constructor.
25 CMICmdInvoker::CMICmdInvoker(void)
26 : m_rStreamOut(CMICmnStreamStdout::Instance())
30 //++ ------------------------------------------------------------------------------------
31 // Details: CMICmdInvoker destructor.
37 CMICmdInvoker::~CMICmdInvoker(void)
42 //++ ------------------------------------------------------------------------------------
43 // Details: Initialize resources for *this Command Invoker.
46 // Return: MIstatus::success - Functional succeeded.
47 // MIstatus::failure - Functional failed.
51 CMICmdInvoker::Initialize(void)
53 m_clientUsageRefCnt++;
56 return MIstatus::success;
58 m_bInitialized = true;
60 return MIstatus::success;
63 //++ ------------------------------------------------------------------------------------
64 // Details: Release resources for *this Stdin stream.
67 // Return: MIstatus::success - Functional succeeded.
68 // MIstatus::failure - Functional failed.
72 CMICmdInvoker::Shutdown(void)
74 if (--m_clientUsageRefCnt > 0)
75 return MIstatus::success;
78 return MIstatus::success;
82 m_bInitialized = false;
84 return MIstatus::success;
87 //++ ------------------------------------------------------------------------------------
88 // Details: Empty the map of invoked commands doing work. Command objects are deleted too.
95 CMICmdInvoker::CmdDeleteAll(void)
97 CMICmdMgr &rMgr = CMICmdMgr::Instance();
98 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.begin();
99 while (it != m_mapCmdIdToCmd.end())
101 const MIuint cmdId((*it).first);
103 CMICmdBase *pCmd = (*it).second;
104 const CMIUtilString &rCmdName(pCmd->GetCmdData().strMiCmd);
106 rMgr.CmdDelete(pCmd->GetCmdData());
111 m_mapCmdIdToCmd.clear();
114 //++ ------------------------------------------------------------------------------------
115 // Details: Remove from the map of invoked commands doing work a command that has finished
116 // its work. The command object is deleted too.
118 // Args: vId - (R) Command object's unique ID.
119 // vbYesDeleteCmd - (R) True = Delete command object, false = delete via the Command Manager.
124 CMICmdInvoker::CmdDelete(const MIuint vId, const bool vbYesDeleteCmd /*= false*/)
126 CMICmdMgr &rMgr = CMICmdMgr::Instance();
127 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find(vId);
128 if (it != m_mapCmdIdToCmd.end())
130 CMICmdBase *pCmd = (*it).second;
133 // Via registered interest command manager callback *this object to delete the command
134 m_mapCmdIdToCmd.erase(it);
138 // Notify other interested object of this command's pending deletion
139 rMgr.CmdDelete(pCmd->GetCmdData());
142 if (m_mapCmdIdToCmd.empty())
143 rMgr.CmdUnregisterForDeleteNotification(*this);
145 return MIstatus::success;
148 //++ ------------------------------------------------------------------------------------
149 // Details: Add to the map of invoked commands doing work a command that is about to
152 // Args: vCmd - (R) Command object.
157 CMICmdInvoker::CmdAdd(const CMICmdBase &vCmd)
159 if (m_mapCmdIdToCmd.empty())
161 CMICmdMgr &rMgr = CMICmdMgr::Instance();
162 rMgr.CmdRegisterForDeleteNotification(*this);
165 const MIuint &cmdId(vCmd.GetCmdData().id);
166 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find(cmdId);
167 if (it != m_mapCmdIdToCmd.end())
168 return MIstatus::success;
170 MapPairCmdIdToCmd_t pr(cmdId, const_cast<CMICmdBase *>(&vCmd));
171 m_mapCmdIdToCmd.insert(pr);
173 return MIstatus::success;
176 //++ ------------------------------------------------------------------------------------
177 // Details: Having previously had the potential command validated and found valid now
178 // get the command executed.
179 // If the Functionality returns MIstatus::failure call GetErrorDescription().
180 // This function is used by the application's main thread.
182 // Args: vCmd - (RW) Command object.
183 // Return: MIstatus::success - Functionality succeeded.
184 // MIstatus::failure - Functionality failed.
188 CMICmdInvoker::CmdExecute(CMICmdBase &vCmd)
190 bool bOk = CmdAdd(vCmd);
192 if (bOk && !vCmd.ParseArgs())
194 // Report command execution failed
195 const SMICmdData cmdData(vCmd.GetCmdData());
197 CmdCauseAppExit(vCmd);
198 CmdDelete(cmdData.id);
200 // Proceed to wait or execute next command
201 return MIstatus::success;
204 if (bOk && !vCmd.Execute())
206 // Report command execution failed
207 const SMICmdData cmdData(vCmd.GetCmdData());
209 CmdCauseAppExit(vCmd);
210 CmdDelete(cmdData.id);
212 // Proceed to wait or execute next command
213 return MIstatus::success;
216 bOk = CmdExecuteFinished(vCmd);
221 //++ ------------------------------------------------------------------------------------
222 // Details: Called when a command has finished its Execution() work either synchronously
223 // because the command executed was the type a non event type or asynchronously
224 // via the command's callback (because of an SB Listener event). Needs to be called
225 // so that *this invoker call do some house keeping and then proceed to call
226 // the command's Acknowledge() function.
228 // Args: vCmd - (R) Command object.
229 // Return: MIstatus::success - Functionality succeeded.
230 // MIstatus::failure - Functionality failed.
234 CMICmdInvoker::CmdExecuteFinished(CMICmdBase &vCmd)
236 // Command finished now get the command to gather it's information and form the MI
238 if (!vCmd.Acknowledge())
240 // Report command acknowledge functionality failed
241 const SMICmdData cmdData(vCmd.GetCmdData());
243 CmdCauseAppExit(vCmd);
244 CmdDelete(cmdData.id);
246 // Proceed to wait or execute next command
247 return MIstatus::success;
250 // Retrieve the command's latest data/information. Needed for commands of the event type so have
251 // a record of commands pending finishing execution.
252 const CMIUtilString &rMIResultRecord(vCmd.GetMIResultRecord());
253 SMICmdData cmdData(vCmd.GetCmdData()); // Make a copy as the command will be deleted soon
254 cmdData.strMiCmdResultRecord = rMIResultRecord; // Precautionary copy as the command might forget to do this
255 if (vCmd.HasMIResultRecordExtra())
257 cmdData.bHasResultRecordExtra = true;
258 const CMIUtilString &rMIExtra(vCmd.GetMIResultRecordExtra());
259 cmdData.strMiCmdResultRecordExtra = rMIExtra; // Precautionary copy as the command might forget to do this
262 // Send command's MI response to the client
263 bool bOk = CmdStdout(cmdData);
265 // Delete the command object as do not require anymore
266 bOk = bOk && CmdDelete(vCmd.GetCmdData().id);
271 //++ ------------------------------------------------------------------------------------
272 // Details: If the MI Driver is not operating via a client i.e. Eclipse check the command
273 // on failure suggests the application exits. A command can be such that a
274 // failure cannot the allow the application to continue operating.
275 // Args: vCmd - (R) Command object.
281 CMICmdInvoker::CmdCauseAppExit(const CMICmdBase &vCmd) const
283 if (vCmd.GetExitAppOnCommandFailure())
285 CMIDriver &rDriver(CMIDriver::Instance());
286 if (rDriver.IsDriverDebuggingArgExecutable())
288 rDriver.SetExitApplicationFlag(true);
293 //++ ------------------------------------------------------------------------------------
294 // Details: Write to stdout and the Log file the command's MI formatted result.
295 // Type: vCmdData - (R) A command's information.
296 // Return: MIstatus::success - Functionality succeeded.
297 // MIstatus::failure - Functionality failed.
302 CMICmdInvoker::CmdStdout(const SMICmdData &vCmdData) const
304 bool bOk = m_pLog->WriteLog(vCmdData.strMiCmdAll);
305 const bool bLock = bOk && m_rStreamOut.Lock();
306 bOk = bOk && bLock && m_rStreamOut.WriteMIResponse(vCmdData.strMiCmdResultRecord);
307 if (bOk && vCmdData.bHasResultRecordExtra)
309 bOk = m_rStreamOut.WriteMIResponse(vCmdData.strMiCmdResultRecordExtra);
311 bOk = bLock && m_rStreamOut.Unlock();
316 //++ ------------------------------------------------------------------------------------
317 // Details: Required by the CMICmdMgr::ICmdDeleteCallback. *this object is registered
318 // with the Command Manager to receive callbacks when a command is being deleted.
319 // An object, *this invoker, does not delete a command object itself but calls
320 // the Command Manager to delete a command object. This function is the Invoker's
322 // The Invoker owns the command objects and so can delete them but must do it
323 // via the manager so other objects can be notified of the deletion.
325 // Args: vCmd - (RW) Command.
330 CMICmdInvoker::Delete(SMICmdData &vCmd)
332 CmdDelete(vCmd.id, true);