installationservices/swi/source/sislauncher/server/threadmonitor.cpp
changeset 0 ba25891c3a9e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/installationservices/swi/source/sislauncher/server/threadmonitor.cpp	Thu Dec 17 08:51:10 2009 +0200
@@ -0,0 +1,179 @@
+/*
+* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+* ThreadMonitor - closes started threads after a specified timeout
+*
+*/
+
+
+/**
+ @file 
+ @released
+ @internalComponent
+*/
+
+#include <e32std.h>
+#ifndef SWI_TEXTSHELL_ROM
+#include <eikenv.h>
+#include <apgwgnam.h>
+#include <apgtask.h>
+#include <w32std.h>
+#endif
+#include "threadmonitor.h"
+#include "log.h"
+
+using namespace Swi;
+
+CThreadMonitor* CThreadMonitor::NewL(TThreadId aTThreadId, RWsSession* aWsSession)
+    {
+	CThreadMonitor* self = CThreadMonitor::NewLC(aTThreadId, aWsSession);
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+CThreadMonitor* CThreadMonitor::NewLC(TThreadId aTThreadId, RWsSession* aWsSession)
+    {
+	CThreadMonitor* self = new (ELeave) CThreadMonitor(aTThreadId, aWsSession);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+    return self;
+    }
+
+CThreadMonitor::CThreadMonitor(TThreadId aTThreadId, RWsSession* aWsSession)
+				: iTThreadId(aTThreadId), iWsSession(aWsSession)
+     {
+     }
+
+CThreadMonitor::~CThreadMonitor()
+    {
+    iThread.Close();
+    }
+
+void CThreadMonitor::ConstructL()
+	{
+	TInt err = iThread.Open(iTThreadId);
+	if(err == KErrNone)
+		{
+		iThreadAlreadyClosed = EFalse;
+		}
+	else if (err == KErrNotFound)
+		{
+		iThreadAlreadyClosed = ETrue;
+		}
+	else
+		{
+		User::Leave(err);
+		}
+	}
+
+
+void CThreadMonitor::SyncShutdownL(TInt aDelay, TBool aKillOnTimeout, TInt aApplicationShutdownTimeout)
+    {
+    DEBUG_PRINTF(_L8("Sis Launcher Server - Waiting for application to terminate."));
+    
+    if(!iThreadAlreadyClosed)
+    	{
+		// make the timing loop 'time' dependent (see PDEF107100)
+		TTime startTime;
+		startTime.UniversalTime();
+		TTime currentTime = startTime;
+
+		// If swipolicy.ini has -1 set for RunWaitTimeoutSeconds
+		// aDelay will be -1000000.  In this case we wait as long
+		// as it takes for the thread to exit.
+		TBool noTimeout = (aDelay == -1000000) ? ETrue : EFalse;
+		while ((iThread.ExitType() == EExitPending) && 
+		((currentTime.MicroSecondsFrom(startTime) < aDelay) || noTimeout))
+			{
+			User::After(1000000); // 1 second
+			currentTime.UniversalTime();
+			} 
+
+		// We may need to shut down or kill the app/process.
+		if (iThread.ExitType() == EExitPending && aKillOnTimeout)
+			{
+			#ifdef SWI_TEXTSHELL_ROM
+				(void) aApplicationShutdownTimeout;
+				DEBUG_PRINTF(_L8("Sis Launcher Server - Application still running after timeout. graceful shutdown skipped."));
+			#else
+			// iWsSession will be NULL if running textshell in emulator.
+			// Here no graceful shutdown will be tried.
+			if(NULL != iWsSession)
+				{
+				DEBUG_PRINTF(_L8("Sis Launcher Server - Application still running after timeout. Attempting graceful shutdown."));
+
+				// Attempt graceful shutdown first if this is an app which handles
+				// shutdown events.
+				CApaWindowGroupName* wgName = CApaWindowGroupName::NewL(*iWsSession);
+				CleanupStack::PushL(wgName);
+
+				TInt wgId = iWsSession->FindWindowGroupIdentifier(0, iThread.Id());
+				if (wgId != KErrNotFound)
+					{
+					wgName->ConstructFromWgIdL(wgId);
+					if(wgName->RespondsToShutdownEvent())
+						{
+						
+						TRequestStatus threadStatus;
+						iThread.Logon(threadStatus);
+
+						TApaTask task(*iWsSession);
+						task.SetWgId(wgId);
+						task.SendSystemEvent(EApaSystemEventShutdown);
+
+						RTimer timer;
+						CleanupClosePushL(timer);
+						TRequestStatus timerStatus;
+						User::LeaveIfError(timer.CreateLocal());
+						timer.After(timerStatus, aApplicationShutdownTimeout);
+
+						User::WaitForRequest(threadStatus,timerStatus);
+
+						if (threadStatus==KRequestPending)
+							{
+							// Timer completed, cancel rendezvous, process will
+							// be killed below.
+							iThread.LogonCancel(threadStatus);
+							}
+						else if (timerStatus==KRequestPending)
+							{
+							// Rendezvous completed so cancel timer
+							timer.Cancel();
+							}
+						
+						// Catch second request.
+						User::WaitForRequest(threadStatus,timerStatus);
+						CleanupStack::PopAndDestroy(&timer);
+						}
+
+					}
+				CleanupStack::PopAndDestroy(wgName);
+				}
+			#endif
+			}
+
+		// If we haven't managed to shut it down gracefully, we need to kill
+		// the process.
+		if (iThread.ExitType() == EExitPending) 
+			{
+			DEBUG_PRINTF(_L8("Sis Launcher Server - Application still running. Killing it."));
+			
+			RProcess process;
+			User::LeaveIfError(iThread.Process(process));
+			process.Kill(KErrNone);
+			process.Close();
+			}
+    	}
+    }
+