diff -r 000000000000 -r 7f656887cf89 libraries/clogger/src/SensibleClient.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libraries/clogger/src/SensibleClient.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,494 @@ +// SensibleClient.cpp +// +// Copyright (c) 2006 - 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 "SensibleClient.h" +#include "SensibleClient_internals.h" +#include "cliserv.h" +#include "SensibleCompat.h" + +_LIT(KClientPanic, "SensibleClient"); +#define DebugPanic() User::Panic(KClientPanic, - __LINE__) +#define AssertPanic(x) User::Panic(KClientPanic, x) +enum TPanic + { + EReadOffEndOfCallback, // A call to TCallbackParser::Next when there's nothing more in the callback buffer + EBadType, // A call to TCallbackParser::NextX where X doesn't match the type of the next thing in the buffer + }; + +#ifdef EKA2 + +static TInt StartServer() +// +// Start the server process. Simultaneous launching +// of two such processes should be detected when the second one attempts to +// create the server object, failing with KErrAlreadyExists. +// + { + const TUidType serverUid(KNullUid,KNullUid,KServerUid3); + RProcess server; + TInt r=server.Create(KMyServerImg,KNullDesC,serverUid); + if (r!=KErrNone) + return r; + TRequestStatus stat; + server.Rendezvous(stat); + if (stat!=KRequestPending) + server.Kill(0); // abort startup + else + server.Resume(); // logon OK - start the server + User::WaitForRequest(stat); // wait for start or death + // we are expected to return a negative error code from this function so if the server died + // with a positive (or zero) code, map it to KErrServerTerminated + r = (server.ExitType() != EExitPending && stat.Int() >= 0) ? KErrServerTerminated : stat.Int(); + server.Close(); + return r; + } + + + +#else + +#include + +inline TServerStart::TServerStart(TRequestStatus& aStatus) + :iId(RThread().Id()),iStatus(&aStatus) + {aStatus=KRequestPending;} +inline TPtrC TServerStart::AsCommand() const + {return TPtrC(reinterpret_cast(this),sizeof(TServerStart)/sizeof(TText));} + +static TInt StartServer() +// +// Start the server process/thread which lives in an EPOCEXE object +// + { + TRequestStatus started; + TServerStart start(started); + + const TUidType serverUid(KNullUid,KNullUid,KServerUid3); + +#ifdef __WINS__ + // + // In WINS the server is a DLL, the exported entrypoint returns a TInt + // which represents the real entry-point for the server thread + // + RLibrary lib; + TInt r=lib.Load(KMyServerImg,serverUid); + if (r!=KErrNone) + return r; + TLibraryFunction ordinal1=lib.Lookup(1); + TThreadFunction serverFunc=reinterpret_cast(ordinal1()); + // + // To deal with the unique thread (+semaphore!) naming in EPOC, and that we may + // be trying to restart a server that has just exited we attempt to create a + // unique thread name for the server. + // This uses Math::Random() to generate a 32-bit random number for the name + // + TName name(KMyServerName); + name.AppendNum(Math::Random(),EHex); + RThread server; + r=server.Create(name,serverFunc, + KMyServerStackSize, + &start,&lib,NULL, + KMyServerInitHeapSize,KMyServerMaxHeapSize,EOwnerProcess); + lib.Close(); // if successful, server thread has handle to library now +#else + // + // EPOC is easy, we just create a new server process. Simultaneous launching + // of two such processes should be detected when the second one attempts to + // create the server object, failing with KErrAlreadyExists. + // + RProcess server; + TInt r=server.Create(KMyServerImg,start.AsCommand(),serverUid); +#endif + if (r!=KErrNone) + return r; + TRequestStatus died; + server.Logon(died); + if (died!=KRequestPending) + { + // logon failed - server is not yet running, so cannot have terminated + User::WaitForRequest(died); // eat signal + server.Kill(0); // abort startup + server.Close(); + return died.Int(); + } + // + // logon OK - start the server + server.Resume(); + User::WaitForRequest(started,died); // wait for start or death + if (started==KRequestPending) + { + // server has died, never made it to the startup signal + server.Close(); + return died.Int(); + } + // + // server started (at last). Cancel and consume the death-notification + // before reporting success + server.LogonCancel(died); + server.Close(); + User::WaitForRequest(died); // eat the signal (from the cancel) + return KErrNone; + } + +TInt E32Dll(TDllReason) + { + return 0; + } + + +#endif + +RSensibleSessionBody::RSensibleSessionBody() + : iDispatcher(NULL) + {} + +TInt RSensibleSessionBody::Connect(TInt aMessageSlots, TBool aStartCallbackDispatcher) +// +// Connect to the server, attempting to start it if necessary +// + { + TInt r = KErrNone; + TInt retry=2; + for (;;) + { + r=DoCreateSession(KMyServerName, TVersion(0,0,0), aMessageSlots); + if (r!=KErrNotFound && r!=KErrServerTerminated) + break; + if (--retry==0) + break; + r=StartServer(); + if (r!=KErrNone && r!=KErrAlreadyExists) + break; + } + if (r == KErrNone && aStartCallbackDispatcher) + { + if (StartCallbackDispatcher() != KErrNone) + { + Close(); + return KErrNoMemory; + } + } + return r; + } + +TInt RSensibleSessionBody::StartCallbackDispatcher() + { + if (!iDispatcher) + { + iDispatcher = new CServerCallbackDispatcher(*this); + } + else if (!iDispatcher->IsActive()) + { + iDispatcher->Register(); + } + return iDispatcher == NULL ? KErrNoMemory : KErrNone; + } + +void RSensibleSessionBody::StopCallbackDispatcher() + { + if (iDispatcher) iDispatcher->Cancel(); + } + +void RSensibleSessionBody::DispatchCallbackL(TServerCallback& /*aCallback*/, TCallbackParser& /*aParser*/) + { + // Implemented by subclass + } + +void RSensibleSessionBody::ServerDiedL() + { + // Implemented by subclass + } + +void RSensibleSessionBody::Close() + { + delete iDispatcher; + iDispatcher = NULL; + } + +// Not happy this actually works or is worth it +/* +void CCleanupAndComplete::RunL() + { + if (iClientStatus) + { + // We use this class with a null pointer to allow non-asynchronous (ie blind) APIs to still have the ability to cleanup resource when they are completed + User::RequestComplete(iClientStatus, iStatus.Int()); + } + delete this; + } + +void CCleanupAndComplete::DoCancel() + { + //TODO what? Probably delete this in some way + //delete this; + } + +CCleanupAndComplete::CCleanupAndComplete(TRequestStatus* aClientStatus) + : CActive(EPriorityStandard), iClientStatus(aClientStatus) + { + CActiveScheduler::Add(this); + if (iClientStatus) + { + *iClientStatus = KRequestPending; + } + } + +CCleanupAndComplete* CCleanupAndComplete::NewLC(TRequestStatus* aClientStatus) + { + CCleanupAndComplete* self = new(ELeave) CCleanupAndComplete(aClientStatus); + CleanupStack::PushL(self); + return self; + } + +TInt CCleanupAndComplete::Create(TRequestStatus*& aStatus, const TDesC8& aDes, TInt& aIpcArg) + { + CCleanupAndComplete* self = new CCleanupAndComplete(aStatus); + TInt err = KErrNone; + if (!self) err = KErrNoMemory; + HBufC8* buf = NULL; + if (!err) + { + buf = aDes.Alloc(); + } + if (!buf) err = KErrNoMemory; + if (!err) + { + err = self->iWithoutDestructor.Append(buf); + } + if (err) + { + delete buf; + delete self; + return KErrNoMemory; + } + aIpcArg = (TInt)buf; + aStatus = &self->iStatus; + self->SetActive(); + return KErrNone; + } + +TInt CCleanupAndComplete::Create(TRequestStatus*& aStatus, const TDesC16& aDes, TInt& aIpcArg) + { + CCleanupAndComplete* self = new CCleanupAndComplete(aStatus); + TInt err = KErrNone; + if (!self) err = KErrNoMemory; + HBufC16* buf = NULL; + if (!err) + { + buf = aDes.Alloc(); + } + if (!buf) err = KErrNoMemory; + if (!err) + { + err = self->iWithoutDestructor.Append(buf); + } + if (err) + { + delete buf; + delete self; + return KErrNoMemory; + } + aIpcArg = (TInt)buf; + aStatus = &self->iStatus; + self->SetActive(); + return KErrNone; + } + +void CCleanupAndComplete::AddL(CBase* aWithDestructor) + { + User::LeaveIfError(iWithDestructor.Append(aWithDestructor)); + } + +void CCleanupAndComplete::AddL(TAny* aWithoutDestructor) + { + User::LeaveIfError(iWithoutDestructor.Append(aWithoutDestructor)); + } + +CCleanupAndComplete::~CCleanupAndComplete() + { + Cancel(); + iWithDestructor.ResetAndDestroy(); + for (TInt i = 0; i < iWithoutDestructor.Count(); i++) + { + delete iWithoutDestructor[i]; + } + } + +void CCleanupAndComplete::SetActive() + { + CActive::SetActive(); + } + +*/ + +CServerCallbackDispatcher::CServerCallbackDispatcher(RSensibleSessionBody& aSession) + : CActive(EPriorityStandard), iSession(aSession), iContextPtr(NULL, 0) + { + CActiveScheduler::Add(this); + Register(); + } + +void CServerCallbackDispatcher::Register() + { + iState = EWaitingForCallback; + IPC(args, &iNextCallback, 0,0,0); + iSession.DoSendReceive(ERegisterCallbackNotifier, args, iStatus); + SetActive(); + } + +void CServerCallbackDispatcher::RunL() + { + DISOWN(iCachedCallbackResult8); + DISOWN(iCachedCallbackResult16); + + if (iStatus == KErrServerTerminated) + { + iSession.ServerDiedL(); + return; + } + else if (iStatus != KErrNone) + { + //TODO Do something... + __DEBUGGER(); + return; + } + + TServerCallback cb = iNextCallback(); + TCallbackParser p(cb); + + if (iState == EWaitingForCallback && cb.iContextLength != 0) + { + iState = EWaitingForContext; + DISOWN(iContext); + iContext = HBufC8::NewL(cb.iContextLength); + iContextPtr = iContext->Des(); + IPC(args, &iContextPtr, 0,0,0); + iSession.DoSendReceive(EGetCallbackContext, args, iStatus); + SetActive(); + return; + } + + if (iState == EWaitingForContext) + { + p.SetContext(*iContext); + } + + Register(); + iSession.DispatchCallbackL(cb, p); + } + +void CServerCallbackDispatcher::DoCancel() + { + IPC(args, 0,0,0,0); + iSession.DoSendReceive(ECancelCallbackNotifier, args); + } + +CServerCallbackDispatcher::~CServerCallbackDispatcher() + { + Cancel(); + DISOWN(iCachedCallbackResult8); + DISOWN(iCachedCallbackResult16); + DISOWN(iContext); + } + + +TCallbackParser::TCallbackParser(const TServerCallback& aCallback) + : iCallback(aCallback), iContext(NULL), iNextPtr(aCallback.iData.Ptr()), iInContext(EFalse) + {} + +void TCallbackParser::SetContext(TDesC8& aContext) + { + iContext = &aContext; + } + +#define DOGET(T, type, name) T name; TAny* res = Next(sizeof(T), #type); Mem::Copy(&name, res, sizeof(T)); +#define GET(T, type) DOGET(T, type, __result); return __result; + +TInt TCallbackParser::NextInt() + { + GET(TInt, i); + } + +TUint TCallbackParser::NextUint() + { + GET(TUint, u); + } + +TPoint TCallbackParser::NextPoint() + { + GET(TPoint, P); + } + +TSize TCallbackParser::NextSize() + { + GET(TSize, S); + } + +TRgb TCallbackParser::NextRgb() + { + GET(TRgb, G); + } + +TRect TCallbackParser::NextRect() + { + GET(TRect, R); + } + +TPtrC TCallbackParser::NextDesC() + { + DOGET(TInt, i, len); + const TUint16* ptr = reinterpret_cast(Next(len*2, "D")); + if (TUint(ptr)&1) + { + // Need to allow for padding + ptr = (TUint16*)(((TUint8*)ptr)+1); + iNextPtr++; // And also move iNextPtr to the right place for the next read + } + return TPtrC(ptr, len); + } + +TPtrC8 TCallbackParser::NextDesC8() + { + DOGET(TInt, i, len); + const TUint8* ptr = reinterpret_cast(Next(len, "8")); + return TPtrC8(ptr, len); + } + +void* TCallbackParser::Next(TInt aSize, char* aType) + { + const TUint8* endPtr = iInContext ? iContext->Ptr() + iContext->Size() : iCallback.iData.Ptr() + iCallback.iData.Size(); + + if (iNextPtr + aSize + 1 > endPtr) + { + // No room for arg and type + if (!iInContext && iContext) + { + // try moving to context + iNextPtr = (TUint8*)iContext->Ptr(); + iInContext = ETrue; + } + else + { + // Either there's no context, or we're already in it and reading off the end + AssertPanic(EReadOffEndOfCallback); + } + } + + TUint8 nextType = *iNextPtr; //iInContext ? iCallback.iContextTypes[iIdx] : iCallback.iDataTypes[iIdx]; + iNextPtr++; + void* result = (void*)iNextPtr; + + __ASSERT_ALWAYS(nextType == *aType, AssertPanic(EBadType)); // Types must match + + iNextPtr = iNextPtr + aSize; + return result; + }