diff -r 000000000000 -r ba25891c3a9e installationservices/swi/source/sislauncher/server/threadmonitor.cpp --- /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 +#ifndef SWI_TEXTSHELL_ROM +#include +#include +#include +#include +#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(); + } + } + } +