core/builtins/undertaker.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // undertaker.cpp
       
     2 // 
       
     3 // Copyright (c) 2005 - 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include <fshell/iocli.h>
       
    14 #include "undertaker.h"
       
    15 
       
    16 TInt CCmdUndertaker::Queue()
       
    17 	{
       
    18 	TInt err = iUndertaker.Logon(iStatus, iDeadThreadHandle);
       
    19 	if (err == KErrNone)
       
    20 		{
       
    21 		SetActive();
       
    22 		}
       
    23 	return err;
       
    24 	}
       
    25 
       
    26 void CCmdUndertaker::DoCancel()
       
    27 	{
       
    28 	iUndertaker.LogonCancel();
       
    29 	}
       
    30 
       
    31 void CCmdUndertaker::RunL()
       
    32 	{
       
    33 	TInt handle = iDeadThreadHandle;
       
    34 	Queue(); // Queue early, to try and avoid missing notifications
       
    35 	// We don't use the RunL if we're in paranoid mode - the undertaker notifications are serviced directly in DoWork() without an active scheduler
       
    36 	ProcessHandle(handle);
       
    37 	}
       
    38 	
       
    39 void CCmdUndertaker::ProcessHandle(TInt aDeadThreadHandle)
       
    40 	{
       
    41 	RThread deadThread;
       
    42 	deadThread.SetHandle(aDeadThreadHandle);
       
    43 	TFullName name(deadThread.FullName());
       
    44 	TExitType type = deadThread.ExitType();
       
    45 	if (type != EExitKill || deadThread.ExitReason() != 0 || iAll)
       
    46 		{
       
    47 		Write(_L("Thread "));
       
    48 		Write(name);
       
    49 		Printf(_L(" (tid=%d) "), (TUint)deadThread.Id());
       
    50 		}
       
    51 
       
    52 	if (type == EExitPanic)
       
    53 		{
       
    54 		TExitCategoryName cat = deadThread.ExitCategory();
       
    55 		Printf(_L("panicked with %S %d\r\n"), &cat, deadThread.ExitReason());
       
    56 		}
       
    57 	else if (type == EExitTerminate)
       
    58 		{
       
    59 		Printf(_L("terminated with reason %d\r\n"), deadThread.ExitReason());
       
    60 		}
       
    61 	else if (deadThread.ExitReason() != 0)
       
    62 		{
       
    63 		// We'll consider a kill with non-zero exit code as counting as abnormal
       
    64 		Printf(_L("killed with reason %d\r\n"), deadThread.ExitReason());
       
    65 		}
       
    66 	else if (iAll)
       
    67 		{
       
    68 		Printf(_L("exited cleanly\r\n"));
       
    69 		}
       
    70 		
       
    71 	if (!iLeakThreads)
       
    72 		{
       
    73 		deadThread.Close();
       
    74 		}
       
    75 	}
       
    76 
       
    77 CCommandBase* CCmdUndertaker::NewLC()
       
    78 	{
       
    79 	CCmdUndertaker* self = new(ELeave) CCmdUndertaker();
       
    80 	CleanupStack::PushL(self);
       
    81 	self->ConstructL();
       
    82 	return self;
       
    83 	}
       
    84 
       
    85 CCmdUndertaker::~CCmdUndertaker()
       
    86 	{
       
    87 	Cancel();
       
    88 	if (iWorkerThread.Id() != RThread().Id()) iWorkerThread.Kill(KErrAbort);
       
    89 	iHandles.Close();
       
    90 	CloseProcessOwnedHandles();
       
    91 	}
       
    92 
       
    93 CCmdUndertaker::CCmdUndertaker()
       
    94 	: CMemoryAccessCommandBase(EManualComplete)
       
    95 	{
       
    96 	}
       
    97 
       
    98 void CCmdUndertaker::ConstructL()
       
    99 	{
       
   100 	BaseConstructL();
       
   101 	}
       
   102 
       
   103 const TDesC& CCmdUndertaker::Name() const
       
   104 	{
       
   105 	_LIT(KName, "undertaker");
       
   106 	return KName;
       
   107 	}
       
   108 
       
   109 void CCmdUndertaker::DoRunL()
       
   110 	{	
       
   111 	User::LeaveIfError(iUndertaker.Create());
       
   112 
       
   113 	if (iParanoid)
       
   114 		{
       
   115 		User::LeaveIfError(iMainThread.Open(RThread().Id()));
       
   116 		User::LeaveIfError(iLock.CreateLocal());
       
   117 		iHandles.ReserveL(10);
       
   118 		TFullName threadName(RThread().Name());
       
   119 		threadName.Append(_L("_worker"));
       
   120 		LeaveIfErr(iWorkerThread.Create(threadName, &WorkerThreadFn, 8192, NULL, this), _L("Couldn't create worker thread"));
       
   121 #ifdef FSHELL_MEMORY_ACCESS_SUPPORT
       
   122 		LoadMemoryAccessL();
       
   123 		LeaveIfErr(iMemAccess.SetThreadPriority(iWorkerThread, 31), _L("Couldn't set worker thread priority with memoryaccess"));
       
   124 #else
       
   125 		iWorkerThread.SetPriority(EPriorityMuchMore); // Best we can do
       
   126 #endif
       
   127 		iWorkerThread.Resume();
       
   128 		}
       
   129 	else
       
   130 		{
       
   131 		User::LeaveIfError(Queue());
       
   132 		}	
       
   133 		
       
   134 	if (Stdin().IsForeground() > 0)
       
   135 		{
       
   136 		Write(iAll ? _L("Waiting for any thread exit...\r\n") : _L("Waiting for panicked thread exit...\r\n"));
       
   137 		}
       
   138 		
       
   139 	if (iParanoid)
       
   140 		{
       
   141 		// We've spawned off our worker thread, which is the client of the RUndertaker. We now wait for it to signal us back again.
       
   142 		// It's easier to balance the requests if we don't go through the active scheduler (so long as nothing else signals this thread!)
       
   143 		for (;;)
       
   144 			{
       
   145 			User::WaitForRequest(iMainThreadStat);
       
   146 			if (iMainThreadStat.Int() != KErrNone) User::Leave(iMainThreadStat.Int());
       
   147 			iLock.Wait();
       
   148 			TInt handle = iHandles[0];
       
   149 			iHandles.Remove(0);
       
   150 			iLock.Signal();
       
   151 			ProcessHandle(handle);
       
   152 			}
       
   153 		}
       
   154 	}
       
   155 
       
   156 void CCmdUndertaker::OptionsL(RCommandOptionList& aOptions)
       
   157 	{
       
   158 	_LIT(KOptAll, "all");
       
   159 	_LIT(KOptNoClose, "noclose");
       
   160 	_LIT(KOptParanoid, "paranoid");
       
   161 	aOptions.AppendBoolL(iAll, KOptAll);
       
   162 	aOptions.AppendBoolL(iLeakThreads, KOptNoClose);
       
   163 	aOptions.AppendBoolL(iParanoid, KOptParanoid);
       
   164 	}
       
   165 
       
   166 TInt CCmdUndertaker::WorkerThreadFn(TAny* aSelf)
       
   167 	{
       
   168 	CCmdUndertaker* self = static_cast<CCmdUndertaker*>(aSelf);
       
   169 	return self->DoWork();
       
   170 	}
       
   171 	
       
   172 TInt CCmdUndertaker::DoWork()
       
   173 	{
       
   174 	TRequestStatus mainThreadDeadStat;
       
   175 	iMainThread.Logon(mainThreadDeadStat);
       
   176 	
       
   177 	TRequestStatus stat;
       
   178 	TInt deadThreadHandle;
       
   179 	TInt err = KErrNone;
       
   180 	for (;;)
       
   181 		{
       
   182 		err = iUndertaker.Logon(stat, deadThreadHandle);
       
   183 		TRequestStatus* s = &iMainThreadStat;
       
   184 		if (err)
       
   185 			{
       
   186 			iMainThread.RequestComplete(s, err);
       
   187 			break;
       
   188 			}
       
   189 		else
       
   190 			{
       
   191 			User::WaitForRequest(stat, mainThreadDeadStat);
       
   192 			if (mainThreadDeadStat.Int() != KRequestPending)
       
   193 				{
       
   194 				// We're dead
       
   195 				err = mainThreadDeadStat.Int();
       
   196 				// Have to clean up our process-owned handles here...
       
   197 				CloseProcessOwnedHandles();
       
   198 				break;
       
   199 				}
       
   200 			// Have to duplicate the thread handle so the main thread can see it. Can't seem to persuade RUndertaker to give us a process-owned handle in the first place
       
   201 			RThread origHandle;
       
   202 			origHandle.SetHandle(deadThreadHandle);
       
   203 			RThread newHandle(origHandle);
       
   204 			err = newHandle.Duplicate(RThread(), EOwnerProcess);
       
   205 			origHandle.Close();
       
   206 			if (!err)
       
   207 				{
       
   208 				iLock.Wait();
       
   209 				err = iHandles.Append(newHandle.Handle());
       
   210 				iLock.Signal();
       
   211 				}
       
   212 			iMainThread.RequestComplete(s, err);
       
   213 			}
       
   214 		}
       
   215 	return err;
       
   216 	}
       
   217 
       
   218 void CCmdUndertaker::CloseProcessOwnedHandles()
       
   219 	{
       
   220 	iMainThread.Close();
       
   221 	iWorkerThread.Close();
       
   222 	iUndertaker.Close();
       
   223 	iLock.Close();
       
   224 	}
       
   225 
       
   226 #ifdef EXE_BUILD
       
   227 EXE_BOILER_PLATE(CCmdUndertaker)
       
   228 #endif
       
   229