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 // File: MICmdInvoker.cpp
13 // Overview: CMICmdInvoker implementation.
15 // Environment: Compilers: Visual C++ 12.
16 // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
17 // Libraries: See MIReadmetxt.
23 #include "MICmdInvoker.h"
24 #include "MICmdBase.h"
27 #include "MICmnStreamStdout.h"
30 //++ ------------------------------------------------------------------------------------
31 // Details: CMICmdInvoker constructor.
37 CMICmdInvoker::CMICmdInvoker( void )
38 : m_rStreamOut( CMICmnStreamStdout::Instance() )
42 //++ ------------------------------------------------------------------------------------
43 // Details: CMICmdInvoker destructor.
49 CMICmdInvoker::~CMICmdInvoker( void )
54 //++ ------------------------------------------------------------------------------------
55 // Details: Initialize resources for *this Command Invoker.
58 // Return: MIstatus::success - Functional succeeded.
59 // MIstatus::failure - Functional failed.
62 bool CMICmdInvoker::Initialize( void )
64 m_clientUsageRefCnt++;
67 return MIstatus::success;
69 m_bInitialized = true;
71 return MIstatus::success;
74 //++ ------------------------------------------------------------------------------------
75 // Details: Release resources for *this Stdin stream.
78 // Return: MIstatus::success - Functional succeeded.
79 // MIstatus::failure - Functional failed.
82 bool CMICmdInvoker::Shutdown( void )
84 if( --m_clientUsageRefCnt > 0 )
85 return MIstatus::success;
88 return MIstatus::success;
92 m_bInitialized = false;
94 return MIstatus::success;
97 //++ ------------------------------------------------------------------------------------
98 // Details: Empty the map of invoked commands doing work. Command objects are deleted too.
104 void CMICmdInvoker::CmdDeleteAll( void )
106 CMICmdMgr & rMgr = CMICmdMgr::Instance();
107 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.begin();
108 while( it != m_mapCmdIdToCmd.end() )
110 const MIuint cmdId( (*it).first ); MIunused( cmdId );
111 CMICmdBase * pCmd = (*it).second;
112 const CMIUtilString & rCmdName( pCmd->GetCmdData().strMiCmd ); MIunused( rCmdName );
113 rMgr.CmdDelete( pCmd->GetCmdData() );
118 m_mapCmdIdToCmd.clear();
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.
125 // Args: vId - (R) Command object's unique ID.
126 // vbYesDeleteCmd - (R) True = Delete command object, false = delete via the Command Manager.
130 bool CMICmdInvoker::CmdDelete( const MIuint vId, const bool vbYesDeleteCmd /*= false*/ )
132 CMICmdMgr & rMgr = CMICmdMgr::Instance();
133 MapCmdIdToCmd_t::const_iterator it = m_mapCmdIdToCmd.find( vId );
134 if( it != m_mapCmdIdToCmd.end() )
136 CMICmdBase * pCmd = (*it).second;
139 // Via registered interest command manager callback *this object to delete the command
140 m_mapCmdIdToCmd.erase( it );
144 // Notify other interested object of this command's pending deletion
145 rMgr.CmdDelete( pCmd->GetCmdData() );
148 if( m_mapCmdIdToCmd.empty() )
149 rMgr.CmdUnregisterForDeleteNotification( *this );
151 return MIstatus::success;
154 //++ ------------------------------------------------------------------------------------
155 // Details: Add to the map of invoked commands doing work a command that is about to
158 // Args: vCmd - (R) Command object.
162 bool CMICmdInvoker::CmdAdd( const CMICmdBase & vCmd )
164 if( m_mapCmdIdToCmd.empty() )
166 CMICmdMgr & rMgr = CMICmdMgr::Instance();
167 rMgr.CmdRegisterForDeleteNotification( *this );
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;
175 MapPairCmdIdToCmd_t pr( cmdId, const_cast< CMICmdBase *>( &vCmd ));
176 m_mapCmdIdToCmd.insert( pr );
178 return MIstatus::success;
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.
187 // Args: vCmd - (RW) Command object.
188 // Return: MIstatus::success - Functionality succeeded.
189 // MIstatus::failure - Functionality failed.
192 bool CMICmdInvoker::CmdExecute( CMICmdBase & vCmd )
194 bool bOk = CmdAdd( vCmd );
196 if( bOk && !vCmd.ParseArgs() )
198 // Report command execution failed
199 const SMICmdData cmdData( vCmd.GetCmdData() );
200 CmdStdout( cmdData );
201 CmdCauseAppExit( vCmd );
202 CmdDelete( cmdData.id );
204 // Proceed to wait or execute next command
205 return MIstatus::success;
208 if( bOk && !vCmd.Execute() )
210 // Report command execution failed
211 const SMICmdData cmdData( vCmd.GetCmdData() );
212 CmdStdout( cmdData );
213 CmdCauseAppExit( vCmd );
214 CmdDelete( cmdData.id );
216 // Proceed to wait or execute next command
217 return MIstatus::success;
220 bOk = CmdExecuteFinished( vCmd );
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.
232 // Args: vCmd - (R) Command object.
233 // Return: MIstatus::success - Functionality succeeded.
234 // MIstatus::failure - Functionality failed.
237 bool CMICmdInvoker::CmdExecuteFinished( CMICmdBase & vCmd )
239 // Command finished now get the command to gather it's information and form the MI
241 if( !vCmd.Acknowledge() )
243 // Report command acknowledge functionality failed
244 const SMICmdData cmdData( vCmd.GetCmdData() );
245 CmdStdout( cmdData );
246 CmdCauseAppExit( vCmd );
247 CmdDelete( cmdData.id );
249 // Proceed to wait or execute next command
250 return MIstatus::success;
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() )
260 cmdData.bHasResultRecordExtra = true;
261 const CMIUtilString & rMIExtra( vCmd.GetMIResultRecordExtra() );
262 cmdData.strMiCmdResultRecordExtra = rMIExtra; // Precautionary copy as the command might forget to do this
265 // Send command's MI response to the client
266 bool bOk = CmdStdout( cmdData );
268 // Delete the command object as do not require anymore
269 bOk = bOk && CmdDelete( vCmd.GetCmdData().id );
274 //++ ------------------------------------------------------------------------------------
275 // 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.
283 void CMICmdInvoker::CmdCauseAppExit( const CMICmdBase & vCmd ) const
285 if( vCmd.GetExitAppOnCommandFailure() )
287 CMIDriver & rDriver( CMIDriver::Instance() );
288 if( rDriver.IsDriverDebuggingArgExecutable() )
290 rDriver.SetExitApplicationFlag( true );
295 //++ ------------------------------------------------------------------------------------
296 // 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.
303 bool CMICmdInvoker::CmdStdout( const SMICmdData & vCmdData ) const
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 )
310 bOk = m_rStreamOut.WriteMIResponse( vCmdData.strMiCmdResultRecordExtra );
312 bOk = bLock && m_rStreamOut.Unlock();
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
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.
326 // Args: vCmd - (RW) Command.
330 void CMICmdInvoker::Delete( SMICmdData & vCmd )
332 CmdDelete( vCmd.id, true );