core/src/command_wrappers.cpp
changeset 36 99de8c43cede
parent 0 7f656887cf89
child 76 b9edfff731fb
equal deleted inserted replaced
10:ba0a96c1cc51 36:99de8c43cede
     9 // Initial Contributors:
     9 // Initial Contributors:
    10 // Accenture - Initial contribution
    10 // Accenture - Initial contribution
    11 //
    11 //
    12 
    12 
    13 #include "command_wrappers.h"
    13 #include "command_wrappers.h"
    14 
    14 #include "worker_thread.h"
    15 
       
    16 //
       
    17 // Constants.
       
    18 //
       
    19 
       
    20 const TInt KMaxHeapSize = KMinHeapSize * 1024;
       
    21 
       
    22 
    15 
    23 //
    16 //
    24 // CCommandWrapperBase.
    17 // CCommandWrapperBase.
    25 //
    18 //
    26 
    19 
    27 CCommandWrapperBase::CCommandWrapperBase()
    20 CCommandWrapperBase::CCommandWrapperBase()
       
    21 	: CActive(CActive::EPriorityStandard)
    28 	{
    22 	{
    29 	}
    23 	}
    30 
    24 
    31 CCommandWrapperBase::~CCommandWrapperBase()
    25 CCommandWrapperBase::~CCommandWrapperBase()
    32 	{
    26 	{
    94 void CCommandWrapperBase::CmndRelease()
    88 void CCommandWrapperBase::CmndRelease()
    95 	{
    89 	{
    96 	delete this;
    90 	delete this;
    97 	}
    91 	}
    98 
    92 
       
    93 void CCommandWrapperBase::RunL()
       
    94 	{
       
    95 	// Optionally for use by subclasses
       
    96 	}
       
    97 
       
    98 void CCommandWrapperBase::DoCancel()
       
    99 	{
       
   100 	// Optionally for use by subclasses
       
   101 	}
    99 
   102 
   100 //
   103 //
   101 // CThreadCommand.
   104 // CThreadCommand.
   102 //
   105 //
   103 
   106 
   104 CThreadCommand* CThreadCommand::NewL(const TDesC& aName, TCommandConstructor aCommandConstructor, TUint aFlags)
   107 CThreadCommand* CThreadCommand::NewL(const TDesC& aName, TCommandConstructor aCommandConstructor, TUint aFlags, MTaskRunner* aTaskRunner)
   105 	{
   108 	{
   106 	CThreadCommand* self = new(ELeave) CThreadCommand(aCommandConstructor, aFlags);
   109 	CThreadCommand* self = new(ELeave) CThreadCommand(aCommandConstructor, aFlags, aTaskRunner);
   107 	CleanupStack::PushL(self);
   110 	CleanupStack::PushL(self);
   108 	self->ConstructL(aName);
   111 	self->ConstructL(aName);
   109 	CleanupStack::Pop(self);
   112 	CleanupStack::Pop(self);
   110 	return self;
   113 	return self;
   111 	}
   114 	}
   112 
   115 
   113 CThreadCommand::~CThreadCommand()
   116 CThreadCommand::~CThreadCommand()
   114 	{
   117 	{
   115 	delete iWatcher;
   118 	Cancel();
   116 	delete iArgs;
   119 	delete iCommandLine;
   117 	iThread.Close();
   120 	iThread.Close();
   118 	}
   121 	}
   119 
   122 
   120 CThreadCommand::CThreadCommand(TCommandConstructor aCommandConstructor, TUint aFlags)
   123 CThreadCommand::CThreadCommand(TCommandConstructor aCommandConstructor, TUint aFlags, MTaskRunner* aTaskRunner)
   121 	: iFlags(aFlags), iCommandConstructor(aCommandConstructor)
   124 	: iFlags(aFlags), iCommandConstructor(aCommandConstructor), iTaskRunner(aTaskRunner)
   122 	{
   125 	{
       
   126 	CActiveScheduler::Add(this);
   123 	iThread.SetHandle(0); // By default RThread refers to the current thread. This results in fshell's thread exiting if this object gets killed before it has managed to open a real thread handle.
   127 	iThread.SetHandle(0); // By default RThread refers to the current thread. This results in fshell's thread exiting if this object gets killed before it has managed to open a real thread handle.
   124 	if (iFlags & EUpdateEnvironment) iFlags |= ESharedHeap; // Update environment implies a shared heap, ever since we did away with the explict SwitchAllocator
   128 	if (iFlags & EUpdateEnvironment) iFlags |= ESharedHeap; // Update environment implies a shared heap, ever since we did away with the explict SwitchAllocator
   125 	}
   129 	}
   126 
   130 
   127 void CThreadCommand::ConstructL(const TDesC& aName)
   131 void CThreadCommand::ConstructL(const TDesC& aName)
   128 	{
   132 	{
   129 	BaseConstructL(aName);
   133 	BaseConstructL(aName);
   130 	iWatcher = CThreadWatcher::NewL();
   134 	}
   131 	}
   135 
   132 
   136 void CThreadCommand::DoCommandThreadStartL(TAny* aSelf)
   133 void CommandThreadStartL(CThreadCommand::TArgs& aArgs)
   137 	{
   134 	{
   138 	CThreadCommand* self = static_cast<CThreadCommand*>(aSelf);
   135 	if (aArgs.iFlags & CThreadCommand::ESharedHeap)
       
   136 		{
       
   137 		// If we're sharing the main fshell heap, we have to play by the rules and not crash
       
   138 		User::SetCritical(User::EProcessCritical);
       
   139 		}
       
   140 
       
   141 	CActiveScheduler* scheduler = new(ELeave) CActiveScheduler;
       
   142 	CleanupStack::PushL(scheduler);
       
   143 	CActiveScheduler::Install(scheduler);
       
   144 
       
   145 	HBufC* commandLine = aArgs.iCommandLine.AllocLC();
       
   146 
   139 
   147 	IoUtils::CEnvironment* env;
   140 	IoUtils::CEnvironment* env;
   148 	if (aArgs.iFlags & CThreadCommand::EUpdateEnvironment)
   141 	if (self->iFlags & CThreadCommand::EUpdateEnvironment)
   149 		{
   142 		{
   150 		env = aArgs.iEnv.CreateSharedEnvironmentL();
   143 		env = self->iSuppliedEnv->CreateSharedEnvironmentL();
   151 		}
   144 		}
   152 	else
   145 	else
   153 		{
   146 		{
   154 		// A straight-forward copy
   147 		// A straight-forward copy
   155 		env = IoUtils::CEnvironment::NewL(aArgs.iEnv);
   148 		env = IoUtils::CEnvironment::NewL(*self->iSuppliedEnv);
   156 		}
   149 		}
   157 	CleanupStack::PushL(env);
   150 	CleanupStack::PushL(env);
   158 
   151 
   159 	CCommandBase* command = (*aArgs.iCommandConstructor)();
   152 	CCommandBase* command = (*self->iCommandConstructor)();
   160 	RThread parentThread;
   153 	//RDebug::Print(_L("5. DoCommandThreadStartL rendezvousing for %S %S"), &self->CmndName(), self->iCommandLine);
   161 	User::LeaveIfError(parentThread.Open(aArgs.iParentThreadId));
   154 	RThread::Rendezvous(KErrNone);
   162 	parentThread.RequestComplete(aArgs.iParentStatus, KErrNone);
   155 	command->RunCommandL(self->iCommandLine, env);
   163 	parentThread.Close();
   156 	CleanupStack::PopAndDestroy(2, env); // command, env
   164 
   157 	}
   165 	command->RunCommandL(commandLine, env);
   158 
   166 	CleanupStack::PopAndDestroy(4, scheduler); // env, command, commandline, scheduler
       
   167 	}
       
   168 
       
   169 TInt CommandThreadStart(TAny* aPtr)
       
   170 	{
       
   171 	CThreadCommand::TArgs args = *(CThreadCommand::TArgs*)aPtr;
       
   172 	TBool sharedHeap = (args.iFlags & CThreadCommand::ESharedHeap);
       
   173 	if (!sharedHeap)
       
   174 		{
       
   175 		__UHEAP_MARK;
       
   176 		}
       
   177 	TInt err = KErrNoMemory;
       
   178 	CTrapCleanup* cleanup = CTrapCleanup::New();
       
   179 	if (cleanup)
       
   180 		{
       
   181 		TRAP(err, CommandThreadStartL(args));
       
   182 		delete cleanup;
       
   183 		}
       
   184 	if (!sharedHeap)
       
   185 		{
       
   186 		__UHEAP_MARKEND;
       
   187 		}
       
   188 	return err;
       
   189 	}
       
   190 
   159 
   191 void SetHandleOwnersL(TThreadId aThreadId, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr)
   160 void SetHandleOwnersL(TThreadId aThreadId, RIoReadHandle& aStdin, RIoWriteHandle& aStdout, RIoWriteHandle& aStderr)
   192 	{
   161 	{
   193 	User::LeaveIfError(aStdin.SetOwner(aThreadId));
   162 	User::LeaveIfError(aStdin.SetOwner(aThreadId));
   194 	User::LeaveIfError(aStdout.SetOwner(aThreadId));
   163 	User::LeaveIfError(aStdout.SetOwner(aThreadId));
   197 
   166 
   198 TInt CThreadCommand::CmndRun(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver, RIoSession&)
   167 TInt CThreadCommand::CmndRun(const TDesC& aCommandLine, IoUtils::CEnvironment& aEnv, MCommandObserver& aObserver, RIoSession&)
   199 	{
   168 	{
   200 	ASSERT(iObserver == NULL);
   169 	ASSERT(iObserver == NULL);
   201 
   170 
   202 	TRequestStatus status(KRequestPending);
   171 	MThreadedTask* thread = NULL;
   203 	iArgs = new TArgs(iFlags, aEnv, iCommandConstructor, aCommandLine, status);
   172 	TRAPD(err, thread = iTaskRunner->NewTaskInSeparateThreadL(CmndName(), iFlags & ESharedHeap, &DoCommandThreadStartL, this));
   204 	if (iArgs == NULL)
   173 	if (err) return err;
   205 		{
   174 
   206 		return KErrNoMemory;
   175 	TRAP(err, SetHandleOwnersL(thread->GetThreadId(), CmndStdin(), CmndStdout(), CmndStderr()));
   207 		}
   176 
   208 
   177 	if (!err)
   209 	TInt i = 0;
   178 		{
   210 	TName threadName;
   179 		iCommandLine = aCommandLine.Alloc();
   211 	TInt err = KErrNone;
   180 		if (!iCommandLine) err = KErrNoMemory;
   212 	do
   181 		}
   213 		{
   182 
   214 		const TDesC& name = CmndName();
   183 	if (!err)
   215 		threadName.Format(_L("%S_%02d"), &name, i++);
   184 		{
   216 		if (iFlags & ESharedHeap)
   185 		err = iThread.Open(thread->GetThreadId());
   217 			{
   186 		}
   218 			err = iThread.Create(threadName, CommandThreadStart, KDefaultStackSize, NULL, iArgs);
   187 
   219 			}
   188 	if (!err)
   220 		else
   189 		{
   221 			{
   190 		iSuppliedEnv = &aEnv;
   222 			err = iThread.Create(threadName, CommandThreadStart, KDefaultStackSize, KMinHeapSize, KMaxHeapSize, iArgs);
   191 		iObserver = &aObserver;
   223 			}
   192 		thread->ExecuteTask(iStatus);
   224 		}
   193 		SetActive();
   225 		while (err == KErrAlreadyExists);
   194 		}
   226 
   195 	else
   227 	if (err)
   196 		{
   228 		{
   197 		thread->AbortTask();
   229 		return err;
   198 		}
   230 		}
   199 
   231 
   200 	return err;
   232 	err = iWatcher->Logon(*this, iThread, aObserver);
       
   233 	if (err)
       
   234 		{
       
   235 		iThread.Kill(0);
       
   236 		iThread.Close();
       
   237 		return err;
       
   238 		}
       
   239 
       
   240 	TThreadId threadId = iThread.Id();
       
   241 	TRAP(err, SetHandleOwnersL(threadId, CmndStdin(), CmndStdout(), CmndStderr()));
       
   242 	if (err)
       
   243 		{
       
   244 		iThread.Kill(0);
       
   245 		iThread.Close();
       
   246 		return err;
       
   247 		}
       
   248 
       
   249 	iThread.Resume();
       
   250 	User::WaitForRequest(status, iWatcher->iStatus);
       
   251 	if (status == KRequestPending)
       
   252 		{
       
   253 		iThread.Close();
       
   254 		return iWatcher->iStatus.Int();
       
   255 		}
       
   256 
       
   257 	iWatcher->SetActive();
       
   258 	iObserver = &aObserver;
       
   259 	return KErrNone;
       
   260 	}
   201 	}
   261 
   202 
   262 void CThreadCommand::CmndForeground()
   203 void CThreadCommand::CmndForeground()
   263 	{
   204 	{
   264 	iThread.SetPriority(EPriorityAbsoluteForeground);
   205 	iThread.SetPriority(EPriorityAbsoluteForeground);
   298 TExitCategoryName CThreadCommand::CmndExitCategory() const
   239 TExitCategoryName CThreadCommand::CmndExitCategory() const
   299 	{
   240 	{
   300 	return iThread.ExitCategory();
   241 	return iThread.ExitCategory();
   301 	}
   242 	}
   302 
   243 
   303 
   244 void CThreadCommand::RunL()
   304 //
   245 	{
   305 // CThreadCommand::TArgs.
   246 	iObserver->HandleCommandComplete(*this, iStatus.Int());
   306 //
   247 	}
   307 
   248 
   308 CThreadCommand::TArgs::TArgs(TUint aFlags, IoUtils::CEnvironment& aEnv, TCommandConstructor aCommandConstructor, const TDesC& aCommandLine, TRequestStatus& aParentStatus)
   249 void CThreadCommand::DoCancel()
   309 	: iFlags(aFlags), iEnv(aEnv), iCommandConstructor(aCommandConstructor), iCommandLine(aCommandLine), iParentStatus(&aParentStatus), iParentThreadId(RThread().Id())
   250 	{
   310 	{
   251 	CmndKill(); // This is a bit drastic, but effective...
   311 	}
       
   312 
       
   313 
       
   314 //
       
   315 // CThreadCommand::CThreadWatcher.
       
   316 //
       
   317 
       
   318 CThreadCommand::CThreadWatcher* CThreadCommand::CThreadWatcher::NewL()
       
   319 	{
       
   320 	return new(ELeave) CThreadWatcher();
       
   321 	}
       
   322 
       
   323 CThreadCommand::CThreadWatcher::~CThreadWatcher()
       
   324 	{
       
   325 	Cancel();
       
   326 	}
       
   327 
       
   328 CThreadCommand::CThreadWatcher::CThreadWatcher()
       
   329 	: CActive(CActive::EPriorityStandard)
       
   330 	{
       
   331 	CActiveScheduler::Add(this);
       
   332 	}
       
   333 
       
   334 TInt CThreadCommand::CThreadWatcher::Logon(CThreadCommand& aCommand, RThread& aThread, MCommandObserver& aObserver)
       
   335 	{
       
   336 	TInt ret = KErrNone;
       
   337 	aThread.Logon(iStatus);
       
   338 	if (iStatus != KRequestPending)
       
   339 		{
       
   340 		User::WaitForRequest(iStatus);
       
   341 		ret = iStatus.Int();
       
   342 		}
       
   343 	else
       
   344 		{
       
   345 		iCommand = &aCommand;
       
   346 		iThread = &aThread;
       
   347 		iObserver = &aObserver;
       
   348 		}
       
   349 	return ret;
       
   350 	}
       
   351 
       
   352 void CThreadCommand::CThreadWatcher::SetActive()
       
   353 	{
       
   354 	CActive::SetActive();
       
   355 	}
       
   356 
       
   357 void CThreadCommand::CThreadWatcher::RunL()
       
   358 	{
       
   359 	iObserver->HandleCommandComplete(*iCommand, iStatus.Int());
       
   360 	}
       
   361 
       
   362 void CThreadCommand::CThreadWatcher::DoCancel()
       
   363 	{
       
   364 	if (iThread)
       
   365 		{
       
   366 		iThread->LogonCancel(iStatus);
       
   367 		}
       
   368 	}
   252 	}
   369 
   253 
   370 
   254 
   371 //
   255 //
   372 // CProcessCommand.
   256 // CProcessCommand.