| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 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 | //++ | 
|  | 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 Panickal | d249928 | 2014-08-08 16:47:42 +0000 | [diff] [blame^] | 28 | #include "MIDriver.h" | 
| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 29 |  | 
|  | 30 | //++ ------------------------------------------------------------------------------------ | 
|  | 31 | // Details:	CMICmdInvoker constructor. | 
|  | 32 | // Type:	Method. | 
|  | 33 | // Args:	None. | 
|  | 34 | // Return:	None. | 
|  | 35 | // Throws:	None. | 
|  | 36 | //-- | 
|  | 37 | CMICmdInvoker::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 | //-- | 
|  | 49 | CMICmdInvoker::~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 | //-- | 
|  | 62 | bool 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 | //-- | 
|  | 82 | bool 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 | //-- | 
|  | 104 | void 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 Panickal | 877569c | 2014-06-24 16:35:50 +0000 | [diff] [blame] | 110 | const MIuint cmdId( (*it).first ); MIunused( cmdId ); | 
| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 111 | CMICmdBase * pCmd = (*it).second; | 
| Deepak Panickal | 877569c | 2014-06-24 16:35:50 +0000 | [diff] [blame] | 112 | const CMIUtilString & rCmdName( pCmd->GetCmdData().strMiCmd ); MIunused( rCmdName ); | 
| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 113 | 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 | //-- | 
|  | 130 | bool 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 | //-- | 
|  | 162 | bool 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 | //-- | 
|  | 192 | bool 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 Panickal | d249928 | 2014-08-08 16:47:42 +0000 | [diff] [blame^] | 201 | CmdCauseAppExit( vCmd ); | 
| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 202 | 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 Panickal | d249928 | 2014-08-08 16:47:42 +0000 | [diff] [blame^] | 213 | CmdCauseAppExit( vCmd ); | 
| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 214 | 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 | //-- | 
|  | 237 | bool 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 Panickal | d249928 | 2014-08-08 16:47:42 +0000 | [diff] [blame^] | 246 | CmdCauseAppExit( vCmd ); | 
| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 247 | 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 Panickal | 877569c | 2014-06-24 16:35:50 +0000 | [diff] [blame] | 265 | // Send command's MI response to the client | 
| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 266 | bool bOk = CmdStdout( cmdData ); | 
| Deepak Panickal | 877569c | 2014-06-24 16:35:50 +0000 | [diff] [blame] | 267 |  | 
|  | 268 | // Delete the command object as do not require anymore | 
| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 269 | bOk = bOk && CmdDelete( vCmd.GetCmdData().id ); | 
|  | 270 |  | 
|  | 271 | return bOk; | 
|  | 272 | } | 
|  | 273 |  | 
|  | 274 | //++ ------------------------------------------------------------------------------------ | 
| Deepak Panickal | d249928 | 2014-08-08 16:47:42 +0000 | [diff] [blame^] | 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. | 
|  | 279 | // Return:	None. | 
|  | 280 | // Return:	None. | 
|  | 281 | // Throws:	None. | 
|  | 282 | //-- | 
|  | 283 | void 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 Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 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. | 
|  | 300 | // Return:	None. | 
|  | 301 | // Throws:	None. | 
|  | 302 | //-- | 
|  | 303 | bool 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 Panickal | 877569c | 2014-06-24 16:35:50 +0000 | [diff] [blame] | 310 | bOk = m_rStreamOut.WriteMIResponse( vCmdData.strMiCmdResultRecordExtra ); | 
| Deepak Panickal | 6f9c468 | 2014-05-16 10:51:01 +0000 | [diff] [blame] | 311 | } | 
|  | 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 | //-- | 
|  | 330 | void CMICmdInvoker::Delete( SMICmdData & vCmd ) | 
|  | 331 | { | 
|  | 332 | CmdDelete( vCmd.id, true ); | 
|  | 333 | } |