Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase.
Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.
// wsp_session.cpp
//
// Copyright (c) 2002 - 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "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:
// Accenture - Initial contribution
//
#include "wsp_session.h"
#include "wsp_factory.h"
#include "wsp_request.h"
#include "wsp_panic.h"
#include "wsp_log.h"
//
// Constants.
//
_LIT(KWspThreadName, "WinSockPrtThread");
_LIT(KWspThreadNameWhilstWaitingForDeath, "WinSockPrtThread_WaitingForDeath_%Ld");
_LIT(KWspThreadStartSemaphoreName, "WinSockPrtThreadStartSemaphore");
const TInt KWspThreadStackSize = KDefaultStackSize;
const TInt KWspThreadMinHeapSize = 0x4000; // 16 kb
const TInt KWspThreadMaxHeapSize = 0x40000; // 256 kb
//
// RWin32Session.
//
TInt RWin32Session::Open()
{
return CreateThread();
}
void RWin32Session::Close()
{
if (iThread.Handle())
{
iWin32Message.Set(CWin32Session::EClose);
iRequest.MakeRequest(iWin32Message);
iThread.Close();
}
}
TInt RWin32Session::MakeRequest(TWin32Message& aMessage)
{
return iRequest.MakeRequest(aMessage);
}
TInt RWin32Session::CreateThread()
{
WSP_LOG(WspLog::Write(_L("RWin32Session::CreateThread")));
#ifdef _DEBUG
TFindThread findThread(KWspThreadName);
TFullName name;
__ASSERT_DEBUG(findThread.Next(name)==KErrNotFound, Panic(EWinSockPrtThreadAlreadyExists));
#endif
RSemaphore threadStartSemaphore;
TInt err = threadStartSemaphore.CreateGlobal(KWspThreadStartSemaphoreName, 0, EOwnerThread);
if (err)
{
return err;
}
err = iThread.Create(KWspThreadName, WinSockPrtThreadStart, KWspThreadStackSize, KWspThreadMinHeapSize, KWspThreadMaxHeapSize, &iRequest, EOwnerThread);
if (err == KErrNone)
{
err = iRequest.DuplicateParentThreadHandle(iThread);
if (err)
{
iThread.Close();
threadStartSemaphore.Close();
return err;
}
//iThread.SetPriority(EPriorityAbsoluteVeryLow); // Hack to prevent the thread from blocking all threads lower than the default priority. Should really be using a raw Win32 thread rather than a Symbian one.
iThread.Resume();
threadStartSemaphore.Wait();
threadStartSemaphore.Close();
}
else
{
threadStartSemaphore.Close();
}
return err;
}
//
// Thread start functions.
//
GLDEF_C TInt WinSockPrtThreadStart(TAny* aPtr)
{
__UHEAP_MARK;
CTrapCleanup* trapCleanup = CTrapCleanup::New();
if (trapCleanup == NULL)
{
return KErrNoMemory;
}
TRAPD(err, InitialiseAndRunThreadL(aPtr));
WSP_LOG(WspLog::Close());
delete trapCleanup;
__UHEAP_MARKEND;
return err;
}
GLDEF_C void InitialiseAndRunThreadL(TAny* aPtr)
{
WSP_LOG(User::LeaveIfError(WspLog::Open()));
CWin32Scheduler* win32Scheduler = CWin32Scheduler::NewL();
CleanupStack::PushL(win32Scheduler);
TWin32Request* request = static_cast<TWin32Request*>(aPtr);
CWin32Factory* win32Factory = CWin32Factory::NewL(*request, *win32Scheduler);
CleanupStack::PushL(win32Factory);
RSemaphore threadStartSemaphore;
User::LeaveIfError(threadStartSemaphore.OpenGlobal(KWspThreadStartSemaphoreName, EOwnerThread));
threadStartSemaphore.Signal();
threadStartSemaphore.Close();
win32Scheduler->Start();
CleanupStack::PopAndDestroy(2, win32Scheduler);
}
//
// CWin32Session.
//
void CWin32Session::AddSubSessionL(CWin32SubSession* aSubSession)
{
TInt subSessionHandle = reinterpret_cast<TInt>(aSubSession);
TPckg<TInt> subSessionHandlePckg(subSessionHandle);
iRequest.Message().WriteBuffer().Copy(subSessionHandlePckg);
CleanupStack::PushL(aSubSession);
User::LeaveIfError(iSubSessions.Append(aSubSession));
CleanupStack::Pop(aSubSession);
}
CWin32Session::~CWin32Session()
{
__ASSERT_DEBUG(iSubSessions.Count() == 0, Panic(EWinSockPrtSubSessionListNotEmpty));
iSubSessions.Close();
}
CWin32Session::CWin32Session(TWin32Request& aRequest, CWin32Scheduler& aScheduler)
: CWin32ActiveObject(aScheduler), iRequest(aRequest)
{
}
void CWin32Session::ConstructL()
{
CWin32ActiveObject::ConstructL();
iRequest.SetEventHandle(iEvent);
}
void CWin32Session::Run()
{
TInt err = KErrNone;
CWin32SubSession* subSession = reinterpret_cast<CWin32SubSession*>(iRequest.SubSession());
TWin32Message& message = iRequest.Message();
if (subSession == NULL)
{
switch (message.OppCode())
{
case EClose:
{
Close();
break;
}
case ECloseSubSession:
{
CloseSubSession();
break;
}
default:
{
// Pass on to sub-class.
TRAP(err, ServiceL(message));
}
}
}
else
{
TRAP(err, subSession->ServiceL(message));
}
iRequest.Requested(err);
}
void CWin32Session::Close()
{
// This thread could take a while to die, so give it a different name so that subsequent client attempt to create another one don't fail with KErrInUse.
TTime time;
time.UniversalTime();
const TInt64& int64 = time.Int64();
TBuf<64> newThreadName;
newThreadName.Format(KWspThreadNameWhilstWaitingForDeath(), int64);
User::RenameThread(newThreadName); // Throw away error code.
iScheduler.Stop();
}
void CWin32Session::CloseSubSession()
{
TInt handle;
TPckg<TInt> handlePckg(handle);
handlePckg.Copy(iRequest.Message().ReadBuffer());
CWin32SubSession* subSessionToClose = reinterpret_cast<CWin32SubSession*>(handle);
TInt pos = iSubSessions.Find(subSessionToClose);
__ASSERT_DEBUG(pos >= 0, Panic(EWinSockPrtUnableToFindSubSession));
delete subSessionToClose;
iSubSessions.Remove(pos);
}