// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "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:
// watcher.cpp
//

#include <basched.h>
#include <watcher.h>
#include "watcherdef.h"
#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS 
#include "cwatcher.h"
#endif

#include "cwatcherssastartupmgr.h"

#pragma warning	(disable : 4702)

_LIT(KThreadName1, "WatcherMainThread%d");
_LIT(KThreadName2, "WatcherThread");
const TInt KMinWatcherHeapSize = 0x8000;
const TInt KMaxWatcherHeapSize = 0x200000;


void DoLaunchWatchersL()
	{
	// Create scheduler
	CBaActiveScheduler* scheduler = new(ELeave)CBaActiveScheduler;
	CleanupStack::PushL(scheduler);

	// Install scheduler
	CActiveScheduler::Install(scheduler);

	// Launch the start-up manager that will launch the watchers in the 
 	// correct start-up state
	CWatcherSSAStartupMgr* startupMgr = CWatcherSSAStartupMgr::NewL();

	// The System Starter is waiting for us (start_method = EWaitForStart)
	// so we rendez-vous so it can start the next process in the SSC
	RProcess::Rendezvous(KErrNone);

	// We start the scheduler even if there are no watchers (vs previous
	// behaviour) as the SSA manager is also an active object
	CActiveScheduler::Start();
	
	// Tidy up
	CleanupStack::PopAndDestroy(scheduler);
	}

static TInt DoLaunchThread(TAny*)
	{
	CTrapCleanup* cleanup = CTrapCleanup::New();
	__ASSERT_ALWAYS(cleanup, Panic(ENoCleanup));
	TRAP_IGNORE(DoLaunchWatchersL());		
	delete cleanup;
	return 0;
	}

//**********************************
// CWatcher
//**********************************

EXPORT_C CWatcher* CWatcher::NewL(TInt aPriority)
	{
	return new(ELeave)CWatcher(aPriority);
	}

EXPORT_C CWatcher::~CWatcher()
	{
	Cancel();
	}

EXPORT_C void CWatcher::Start(TRequestStatus& aStatus)
	{
	// Try and create the watcher thread
	iStatus = KRequestPending;

	// Make sure the watching thread has a unique name
	TName threadName;
	threadName.Format(KThreadName1, iLaunchCount++);

#ifdef __X86GCC__
	// Some watchers overflow their stack on this platform when using KDefaultStackSize
	TInt error = iThread.Create(threadName, DoLaunchThread, 2*KDefaultStackSize, KMinWatcherHeapSize, KMaxWatcherHeapSize, NULL, EOwnerThread);
#else	
	TInt error = iThread.Create(threadName, DoLaunchThread, KDefaultStackSize, KMinWatcherHeapSize, KMaxWatcherHeapSize, NULL, EOwnerThread);
#endif // __X86GCC__
	if (!error)
		{
		// Complete the request when the thread dies
		iThread.Logon(iStatus);
		iThread.Resume();
		}
	else
		{
		// Complete ourselves with the error
		TRequestStatus* status = &iStatus;
		User::RequestComplete(status, error);
		}

	aStatus = KRequestPending;
	iObserver = &aStatus;
	SetActive();
	}

CWatcher::CWatcher(TInt aPriority)
: CActive(aPriority)
	{
	CActiveScheduler::Add(this);
	}

void CWatcher::DoCancel()
	{
	// Kill off the thread
	iThread.Kill(KErrCancel);
	iThread.Close();

	User::RequestComplete(iObserver, KErrCancel);
	}

void CWatcher::RunL()
	{
	iThread.Close();

	// Wait a bit
	User::After(KWatcherDelay);
	User::RequestComplete(iObserver, iStatus.Int());
	}

//**********************************
// Watcher Exe
//**********************************

LOCAL_C void DoStartL()
	{
	User::LeaveIfError(User::RenameThread(KThreadName2));

	CActiveScheduler::Install(new(ELeave)CActiveScheduler);
	CleanupStack::PushL(CActiveScheduler::Current());
	CWatcherWait* wait = CWatcherWait::NewLC();

	// The watchers should always be running
	CWatcher* watcher = CWatcher::NewL(CActive::EPriorityStandard);
	FOREVER
		{
		wait->Start();
		watcher->Start(wait->iStatus);
		CActiveScheduler::Start();
		}

	// The following statements are never going to execute due to the endless loop above.
	// They have been commented out to keep the compiler happy.
	//delete watcher;
	//CleanupStack::PopAndDestroy(4); // wait, CActiveScheduler, library, semaphore
	}

GLDEF_C TInt E32Main()
	{       
	__UHEAP_MARK;
	CTrapCleanup* cleanup=CTrapCleanup::New();
	TRAP_IGNORE(DoStartL());          
	delete cleanup;      
	__UHEAP_MARKEND;
	return(KErrNone);
	}

EXPORT_C TInt WinsMain()
	{
	return KErrNone;
	}


#pragma warning	(default : 4702)
