blob: 41f9f77542a36181d5b7bed2697b68629abdfd87 [file] [log] [blame]
Deepak Panickal6f9c4682014-05-16 10:51:01 +00001//===-- 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//++
11// File: MICmdInvoker.cpp
12//
13// Overview: CMICmdInvoker implementation.
14//
15// Environment: Compilers: Visual C++ 12.
16// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
17// Libraries: See MIReadmetxt.
18//
19// Copyright: None.
20//--
21
22// In-house headers:
23#include "MICmdInvoker.h"
24#include "MICmdBase.h"
25#include "MICmdMgr.h"
26#include "MICmnLog.h"
27#include "MICmnStreamStdout.h"
Deepak Panickald2499282014-08-08 16:47:42 +000028#include "MIDriver.h"
Deepak Panickal6f9c4682014-05-16 10:51:01 +000029
30//++ ------------------------------------------------------------------------------------
31// Details: CMICmdInvoker constructor.
32// Type: Method.
33// Args: None.
34// Return: None.
35// Throws: None.
36//--
37CMICmdInvoker::CMICmdInvoker( void )
38: m_rStreamOut( CMICmnStreamStdout::Instance() )
39{
40}
41
42//++ ------------------------------------------------------------------------------------
43// Details: CMICmdInvoker destructor.
44// Type: Overridable.
45// Args: None.
46// Return: None.
47// Throws: None.
48//--
49CMICmdInvoker::~CMICmdInvoker( void )
50{
51 Shutdown();
52}
53
54//++ ------------------------------------------------------------------------------------
55// Details: Initialize resources for *this Command Invoker.
56// Type: Method.
57// Args: None.
58// Return: MIstatus::success - Functional succeeded.
59// MIstatus::failure - Functional failed.
60// Throws: None.
61//--
62bool CMICmdInvoker::Initialize( void )
63{
64 m_clientUsageRefCnt++;
65
66 if( m_bInitialized )
67 return MIstatus::success;
68
69 m_bInitialized = true;
70
71 return MIstatus::success;
72}
73
74//++ ------------------------------------------------------------------------------------
75// Details: Release resources for *this Stdin stream.
76// Type: Method.
77// Args: None.
78// Return: MIstatus::success - Functional succeeded.
79// MIstatus::failure - Functional failed.
80// Throws: None.
81//--
82bool CMICmdInvoker::Shutdown( void )
83{
84 if( --m_clientUsageRefCnt > 0 )
85 return MIstatus::success;
86
87 if( !m_bInitialized )
88 return MIstatus::success;
89
90 CmdDeleteAll();
91
92 m_bInitialized = false;
93
94 return MIstatus::success;
95}
96
97//++ ------------------------------------------------------------------------------------
98// Details: Empty the map of invoked commands doing work. Command objects are deleted too.
99// Type: Method.
100// Args: None.
101// Return: None.
102// Throws: None.
103//--
104void CMICmdInvoker::CmdDeleteAll( void )
105{
106 CMICmdMgr & rMgr = CMICmdMgr::Instance();
107 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.begin();
108 while( it != m_mapCmdIdToCmd.end() )
109 {
Deepak Panickal877569c2014-06-24 16:35:50 +0000110 const MIuint cmdId( (*it).first ); MIunused( cmdId );
Deepak Panickal6f9c4682014-05-16 10:51:01 +0000111 CMICmdBase * pCmd = (*it).second;
Deepak Panickal877569c2014-06-24 16:35:50 +0000112 const CMIUtilString & rCmdName( pCmd->GetCmdData().strMiCmd ); MIunused( rCmdName );
Deepak Panickal6f9c4682014-05-16 10:51:01 +0000113 rMgr.CmdDelete( pCmd->GetCmdData() );
114
115 // Next
116 ++it;
117 }
118 m_mapCmdIdToCmd.clear();
119}
120
121//++ ------------------------------------------------------------------------------------
122// Details: Remove from the map of invoked commands doing work a command that has finished
123// its work. The command object is deleted too.
124// Type: Method.
125// Args: vId - (R) Command object's unique ID.
126// vbYesDeleteCmd - (R) True = Delete command object, false = delete via the Command Manager.
127// Return: None.
128// Throws: None.
129//--
130bool CMICmdInvoker::CmdDelete( const MIuint vId, const bool vbYesDeleteCmd /*= false*/ )
131{
132 CMICmdMgr & rMgr = CMICmdMgr::Instance();
133 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find( vId );
134 if( it != m_mapCmdIdToCmd.end() )
135 {
136 CMICmdBase * pCmd = (*it).second;
137 if( vbYesDeleteCmd )
138 {
139 // Via registered interest command manager callback *this object to delete the command
140 m_mapCmdIdToCmd.erase( it );
141 delete pCmd;
142 }
143 else
144 // Notify other interested object of this command's pending deletion
145 rMgr.CmdDelete( pCmd->GetCmdData() );
146 }
147
148 if( m_mapCmdIdToCmd.empty() )
149 rMgr.CmdUnregisterForDeleteNotification( *this );
150
151 return MIstatus::success;
152}
153
154//++ ------------------------------------------------------------------------------------
155// Details: Add to the map of invoked commands doing work a command that is about to
156// start to do work.
157// Type: Method.
158// Args: vCmd - (R) Command object.
159// Return: None.
160// Throws: None.
161//--
162bool CMICmdInvoker::CmdAdd( const CMICmdBase & vCmd )
163{
164 if( m_mapCmdIdToCmd.empty() )
165 {
166 CMICmdMgr & rMgr = CMICmdMgr::Instance();
167 rMgr.CmdRegisterForDeleteNotification( *this );
168 }
169
170 const MIuint & cmdId( vCmd.GetCmdData().id );
171 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find( cmdId );
172 if( it != m_mapCmdIdToCmd.end() )
173 return MIstatus::success;
174
175 MapPairCmdIdToCmd_t pr( cmdId, const_cast< CMICmdBase *>( &vCmd ));
176 m_mapCmdIdToCmd.insert( pr );
177
178 return MIstatus::success;
179}
180
181//++ ------------------------------------------------------------------------------------
182// Details: Having previously had the potential command validated and found valid now
183// get the command executed.
184// If the Functionalityity returns MIstatus::failure call GetErrorDescription().
185// This function is used by the application's main thread.
186// Type: Method.
187// Args: vCmd - (RW) Command object.
188// Return: MIstatus::success - Functionality succeeded.
189// MIstatus::failure - Functionality failed.
190// Throws: None.
191//--
192bool CMICmdInvoker::CmdExecute( CMICmdBase & vCmd )
193{
194 bool bOk = CmdAdd( vCmd );
195
196 if( bOk && !vCmd.ParseArgs() )
197 {
198 // Report command execution failed
199 const SMICmdData cmdData( vCmd.GetCmdData() );
200 CmdStdout( cmdData );
Deepak Panickald2499282014-08-08 16:47:42 +0000201 CmdCauseAppExit( vCmd );
Deepak Panickal6f9c4682014-05-16 10:51:01 +0000202 CmdDelete( cmdData.id );
203
204 // Proceed to wait or execute next command
205 return MIstatus::success;
206 }
207
208 if( bOk && !vCmd.Execute() )
209 {
210 // Report command execution failed
211 const SMICmdData cmdData( vCmd.GetCmdData() );
212 CmdStdout( cmdData );
Deepak Panickald2499282014-08-08 16:47:42 +0000213 CmdCauseAppExit( vCmd );
Deepak Panickal6f9c4682014-05-16 10:51:01 +0000214 CmdDelete( cmdData.id );
215
216 // Proceed to wait or execute next command
217 return MIstatus::success;
218 }
219
220 bOk = CmdExecuteFinished( vCmd );
221
222 return bOk;
223}
224
225//++ ------------------------------------------------------------------------------------
226// Details: Called when a command has finished its Execution() work either synchronously
227// because the command executed was the type a non event type or asynchronoulsy
228// via the command's callback (because of an SB Listener event). Needs to be called
229// so that *this invoker call do some house keeping and then proceed to call
230// the command's Acknowledge() function.
231// Type: Method.
232// Args: vCmd - (R) Command object.
233// Return: MIstatus::success - Functionality succeeded.
234// MIstatus::failure - Functionality failed.
235// Throws: None.
236//--
237bool CMICmdInvoker::CmdExecuteFinished( CMICmdBase & vCmd )
238{
239 // Command finished now get the command to gather it's information and form the MI
240 // Result record
241 if( !vCmd.Acknowledge() )
242 {
243 // Report command acknowledge functionality failed
244 const SMICmdData cmdData( vCmd.GetCmdData() );
245 CmdStdout( cmdData );
Deepak Panickald2499282014-08-08 16:47:42 +0000246 CmdCauseAppExit( vCmd );
Deepak Panickal6f9c4682014-05-16 10:51:01 +0000247 CmdDelete( cmdData.id );
248
249 // Proceed to wait or execute next command
250 return MIstatus::success;
251 }
252
253 // Retrieve the command's latest data/information. Needed for commands of the event type so have
254 // a record of commands pending finishing execution.
255 const CMIUtilString & rMIResultRecord( vCmd.GetMIResultRecord() );
256 SMICmdData cmdData( vCmd.GetCmdData() ); // Make a copy as the command will be deleted soon
257 cmdData.strMiCmdResultRecord = rMIResultRecord; // Precautionary copy as the command might forget to do this
258 if( vCmd.HasMIResultRecordExtra() )
259 {
260 cmdData.bHasResultRecordExtra = true;
261 const CMIUtilString & rMIExtra( vCmd.GetMIResultRecordExtra() );
262 cmdData.strMiCmdResultRecordExtra = rMIExtra; // Precautionary copy as the command might forget to do this
263 }
264
Deepak Panickal877569c2014-06-24 16:35:50 +0000265 // Send command's MI response to the client
Deepak Panickal6f9c4682014-05-16 10:51:01 +0000266 bool bOk = CmdStdout( cmdData );
Deepak Panickal877569c2014-06-24 16:35:50 +0000267
268 // Delete the command object as do not require anymore
Deepak Panickal6f9c4682014-05-16 10:51:01 +0000269 bOk = bOk && CmdDelete( vCmd.GetCmdData().id );
270
271 return bOk;
272}
273
274//++ ------------------------------------------------------------------------------------
Deepak Panickald2499282014-08-08 16:47:42 +0000275// Details: If the MI Driver is not operating via a client i.e. Eclipse check the command
276// on failure suggests the application exits. A command can be such that a
277// failure cannot the allow the application to continue operating.
278// Args: vCmd - (R) Command object.
279// Return: None.
280// Return: None.
281// Throws: None.
282//--
283void CMICmdInvoker::CmdCauseAppExit( const CMICmdBase & vCmd ) const
284{
285 if( vCmd.GetExitAppOnCommandFailure() )
286 {
287 CMIDriver & rDriver( CMIDriver::Instance() );
288 if( rDriver.IsDriverDebuggingArgExecutable() )
289 {
290 rDriver.SetExitApplicationFlag( true );
291 }
292 }
293}
294
295//++ ------------------------------------------------------------------------------------
Deepak Panickal6f9c4682014-05-16 10:51:01 +0000296// Details: Write to stdout and the Log file the command's MI formatted result.
297// Type: vCmdData - (R) A command's information.
298// Return: MIstatus::success - Functionality succeeded.
299// MIstatus::failure - Functionality failed.
300// Return: None.
301// Throws: None.
302//--
303bool CMICmdInvoker::CmdStdout( const SMICmdData & vCmdData ) const
304{
305 bool bOk = m_pLog->WriteLog( vCmdData.strMiCmdAll );
306 const bool bLock = bOk && m_rStreamOut.Lock();
307 bOk = bOk && bLock && m_rStreamOut.WriteMIResponse( vCmdData.strMiCmdResultRecord );
308 if( bOk && vCmdData.bHasResultRecordExtra )
309 {
Deepak Panickal877569c2014-06-24 16:35:50 +0000310 bOk = m_rStreamOut.WriteMIResponse( vCmdData.strMiCmdResultRecordExtra );
Deepak Panickal6f9c4682014-05-16 10:51:01 +0000311 }
312 bOk = bLock && m_rStreamOut.Unlock();
313
314 return bOk;
315}
316
317//++ ------------------------------------------------------------------------------------
318// Details: Required by the CMICmdMgr::ICmdDeleteCallback. *this object is registered
319// with the Command Manager to receive callbacks when a command is being deleted.
320// An object, *this invoker, does not delete a command object itself but calls
321// the Command Manager to delete a command object. This function is the Invoker's
322// called.
323// The Invoker owns the command objects and so can delete them but must do it
324// via the manager so other objects can be notified of the deletion.
325// Type: Method.
326// Args: vCmd - (RW) Command.
327// Return: None.
328// Throws: None.
329//--
330void CMICmdInvoker::Delete( SMICmdData & vCmd )
331{
332 CmdDelete( vCmd.id, true );
333}