]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/tools/lldb-mi/MICmdInvoker.cpp
MFV r337223:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / tools / lldb-mi / MICmdInvoker.cpp
1 //===-- MICmdInvoker.cpp ----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // In-house headers:
11 #include "MICmdInvoker.h"
12 #include "MICmdBase.h"
13 #include "MICmdMgr.h"
14 #include "MICmnLog.h"
15 #include "MICmnStreamStdout.h"
16 #include "MIDriver.h"
17
18 //++
19 //------------------------------------------------------------------------------------
20 // Details: CMICmdInvoker constructor.
21 // Type:    Method.
22 // Args:    None.
23 // Return:  None.
24 // Throws:  None.
25 //--
26 CMICmdInvoker::CMICmdInvoker() : m_rStreamOut(CMICmnStreamStdout::Instance()) {}
27
28 //++
29 //------------------------------------------------------------------------------------
30 // Details: CMICmdInvoker destructor.
31 // Type:    Overridable.
32 // Args:    None.
33 // Return:  None.
34 // Throws:  None.
35 //--
36 CMICmdInvoker::~CMICmdInvoker() { Shutdown(); }
37
38 //++
39 //------------------------------------------------------------------------------------
40 // Details: Initialize resources for *this Command Invoker.
41 // Type:    Method.
42 // Args:    None.
43 // Return:  MIstatus::success - Functional succeeded.
44 //          MIstatus::failure - Functional failed.
45 // Throws:  None.
46 //--
47 bool CMICmdInvoker::Initialize() {
48   m_clientUsageRefCnt++;
49
50   if (m_bInitialized)
51     return MIstatus::success;
52
53   m_bInitialized = true;
54
55   return MIstatus::success;
56 }
57
58 //++
59 //------------------------------------------------------------------------------------
60 // Details: Release resources for *this Stdin stream.
61 // Type:    Method.
62 // Args:    None.
63 // Return:  MIstatus::success - Functional succeeded.
64 //          MIstatus::failure - Functional failed.
65 // Throws:  None.
66 //--
67 bool CMICmdInvoker::Shutdown() {
68   if (--m_clientUsageRefCnt > 0)
69     return MIstatus::success;
70
71   if (!m_bInitialized)
72     return MIstatus::success;
73
74   CmdDeleteAll();
75
76   m_bInitialized = false;
77
78   return MIstatus::success;
79 }
80
81 //++
82 //------------------------------------------------------------------------------------
83 // Details: Empty the map of invoked commands doing work. Command objects are
84 // deleted too.
85 // Type:    Method.
86 // Args:    None.
87 // Return:  None.
88 // Throws:  None.
89 //--
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);
95     MIunused(cmdId);
96     CMICmdBase *pCmd = (*it).second;
97     const CMIUtilString &rCmdName(pCmd->GetCmdData().strMiCmd);
98     MIunused(rCmdName);
99     rMgr.CmdDelete(pCmd->GetCmdData());
100
101     // Next
102     ++it;
103   }
104   m_mapCmdIdToCmd.clear();
105 }
106
107 //++
108 //------------------------------------------------------------------------------------
109 // Details: Remove from the map of invoked commands doing work a command that
110 // has finished
111 //          its work. The command object is deleted too.
112 // Type:    Method.
113 // Args:    vId             - (R) Command object's unique ID.
114 //          vbYesDeleteCmd  - (R) True = Delete command object, false = delete
115 //          via the Command Manager.
116 // Return:  None.
117 // Throws:  None.
118 //--
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
127       // the command
128       m_mapCmdIdToCmd.erase(it);
129       delete pCmd;
130     } else
131       // Notify other interested object of this command's pending deletion
132       rMgr.CmdDelete(pCmd->GetCmdData());
133   }
134
135   if (m_mapCmdIdToCmd.empty())
136     rMgr.CmdUnregisterForDeleteNotification(*this);
137
138   return MIstatus::success;
139 }
140
141 //++
142 //------------------------------------------------------------------------------------
143 // Details: Add to the map of invoked commands doing work a command that is
144 // about to
145 //          start to do work.
146 // Type:    Method.
147 // Args:    vCmd    - (R) Command object.
148 // Return:  None.
149 // Throws:  None.
150 //--
151 bool CMICmdInvoker::CmdAdd(const CMICmdBase &vCmd) {
152   if (m_mapCmdIdToCmd.empty()) {
153     CMICmdMgr &rMgr = CMICmdMgr::Instance();
154     rMgr.CmdRegisterForDeleteNotification(*this);
155   }
156
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;
161
162   MapPairCmdIdToCmd_t pr(cmdId, const_cast<CMICmdBase *>(&vCmd));
163   m_mapCmdIdToCmd.insert(pr);
164
165   return MIstatus::success;
166 }
167
168 //++
169 //------------------------------------------------------------------------------------
170 // Details: Having previously had the potential command validated and found
171 // valid now
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.
176 // Type:    Method.
177 // Args:    vCmd    - (RW) Command object.
178 // Return:  MIstatus::success - Functionality succeeded.
179 //          MIstatus::failure - Functionality failed.
180 // Throws:  None.
181 //--
182 bool CMICmdInvoker::CmdExecute(CMICmdBase &vCmd) {
183   bool bOk = CmdAdd(vCmd);
184
185   if (bOk) {
186     vCmd.AddCommonArgs();
187     if (!vCmd.ParseArgs()) {
188       // Report command execution failed
189       const SMICmdData cmdData(vCmd.GetCmdData());
190       CmdStdout(cmdData);
191       CmdCauseAppExit(vCmd);
192       CmdDelete(cmdData.id);
193
194       // Proceed to wait or execute next command
195       return MIstatus::success;
196     }
197   }
198
199   if (bOk && !vCmd.Execute()) {
200     // Report command execution failed
201     const SMICmdData cmdData(vCmd.GetCmdData());
202     CmdStdout(cmdData);
203     CmdCauseAppExit(vCmd);
204     CmdDelete(cmdData.id);
205
206     // Proceed to wait or execute next command
207     return MIstatus::success;
208   }
209
210   bOk = CmdExecuteFinished(vCmd);
211
212   return bOk;
213 }
214
215 //++
216 //------------------------------------------------------------------------------------
217 // Details: Called when a command has finished its Execution() work either
218 // synchronously
219 //          because the command executed was the type a non event type or
220 //          asynchronously
221 //          via the command's callback (because of an SB Listener event). Needs
222 //          to be called
223 //          so that *this invoker call do some house keeping and then proceed to
224 //          call
225 //          the command's Acknowledge() function.
226 // Type:    Method.
227 // Args:    vCmd    - (R) Command object.
228 // Return:  MIstatus::success - Functionality succeeded.
229 //          MIstatus::failure - Functionality failed.
230 // Throws:  None.
231 //--
232 bool CMICmdInvoker::CmdExecuteFinished(CMICmdBase &vCmd) {
233   // Command finished now get the command to gather it's information and form
234   // the MI
235   // Result record
236   if (!vCmd.Acknowledge()) {
237     // Report command acknowledge functionality failed
238     const SMICmdData cmdData(vCmd.GetCmdData());
239     CmdStdout(cmdData);
240     CmdCauseAppExit(vCmd);
241     CmdDelete(cmdData.id);
242
243     // Proceed to wait or execute next command
244     return MIstatus::success;
245   }
246
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());
251   SMICmdData cmdData(
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
255                                                   // this
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
261   }
262
263   // Send command's MI response to the client
264   bool bOk = CmdStdout(cmdData);
265
266   // Delete the command object as do not require anymore
267   bOk = bOk && CmdDelete(vCmd.GetCmdData().id);
268
269   return bOk;
270 }
271
272 //++
273 //------------------------------------------------------------------------------------
274 // Details: If the MI Driver is not operating via a client i.e. Eclipse check
275 // the command
276 //          on failure suggests the application exits. A command can be such
277 //          that a
278 //          failure cannot the allow the application to continue operating.
279 // Args:    vCmd    - (R) Command object.
280 // Return:  None.
281 // Return:  None.
282 // Throws:  None.
283 //--
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);
289     }
290   }
291 }
292
293 //++
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.
299 // Return:  None.
300 // Throws:  None.
301 //--
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);
309   }
310   bOk = bLock && m_rStreamOut.Unlock();
311
312   return bOk;
313 }
314
315 //++
316 //------------------------------------------------------------------------------------
317 // Details: Required by the CMICmdMgr::ICmdDeleteCallback. *this object is
318 // registered
319 //          with the Command Manager to receive callbacks when a command is
320 //          being deleted.
321 //          An object, *this invoker, does not delete a command object itself
322 //          but calls
323 //          the Command Manager to delete a command object. This function is the
324 //          Invoker's
325 //          called.
326 //          The Invoker owns the command objects and so can delete them but must
327 //          do it
328 //          via the manager so other objects can be notified of the deletion.
329 // Type:    Method.
330 // Args:    vCmd    - (RW) Command.
331 // Return:  None.
332 // Throws:  None.
333 //--
334 void CMICmdInvoker::Delete(SMICmdData &vCmd) { CmdDelete(vCmd.id, true); }