diff -r 000000000000 -r 63b37f68c1ce connectivitylayer/isce/isirouter_dll/src/isiuserchannel.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/connectivitylayer/isce/isirouter_dll/src/isiuserchannel.cpp Fri Nov 06 17:28:23 2009 +0000 @@ -0,0 +1,594 @@ +/* +* Copyright (c) 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: +* +*/ + + + +#include // For DMutex +#include "isiuserchannel.h" // For DISIUserChanneel +#include "isiroutertrace.h" // For C_TRACE, ASSERT_RESET.. and fault codes +#include "misichannelrouterif.h" // For MISIChannelRouterIf +#include "memapi.h" // For MemApi +#include "isimsgqueue.h" // For DISIMsgQueue + +const TInt KFirstParam( 0 ); +const TInt KSecondParam( 1 ); +const TInt KThirdParam( 2 ); +const TInt KNoParams( 0 ); +const TInt KOneParam( 1 ); +const TInt KTwoParams( 2 ); +const TInt KThreeParams( 3 ); +const TInt KFirstRequest( 0 ); +const TInt KDestStartOffset( 0 ); + +enum TISIUserChannelFaults + { + EISIUserChannelMemAllocFail = 0x01, + EISIUserChannelMemAllocFail1, + EISIUserChannelMemAllocFail2, + EISIUserChannelMemAllocFail3, + EISIUserChannelWrongRequest, + EISIUserChannelWrongRequest1, + EISIUserChannelWrongRequest2, + EISIUserChannelWrongRequest3, + EISIUserChannelWrongRequest4, + EISIUserChannelWrongRequest5, + EISIUserChannelWrongRequest6, + EISIUserChannelReqOverTheLimits, + EISIUserChannelDesWriteFailed, + EISIUserChannelSameRequest, + EISIUserChannelNullParam, + EISIUserChannelNullParam2, + EISIUserChannelDesReadFailed, + EISIUserChannelfNotThreadContext, + EISIUserChannelfNotThreadContext2, + EISIUserChannelfNotThreadContext3, + EISIUserChannelfNotThreadContext4, + EISIUserChannelfNotThreadContext5, + }; + +const TInt KISILddEmptyRxQueuePriori( 1 ); +const TInt KISILddCompleteRequestPriori( 1 ); + + +// user<> kernel interaction() done in LDD DFC thread +// +// kernel<>kernel interaction() done in Extension DFC thread +// +// DEMAND_PAGING +// Receive (write k>u) is done only in LDD thread context to allow Extension thread to continue when dp swaps. +// Send ((write u>k) is not done at the moment in LDD thread context only. Check is it possible to happend (not to be in usable memory after send (unlikely?)). + +DISIUserChannel::DISIUserChannel( + // None + ) : iThread( &Kern::CurrentThread()), + iObjId( KNotInitializedId ), + iUID( KNotInitializedUID ) + { + C_TRACE( ( _T( "DISIUserChannel::DISIUserChannel>" ) ) ); + iRouterIf = MISIChannelRouterIf::GetIf(); + ASSERT_RESET_ALWAYS( iRouterIf, ( EISIUserChannelMemAllocFail | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + iCompletionThread = iRouterIf->GetDfcThread( MISIChannelRouterIf::EISIUserRequestCompletionThread ); + iEmptyRxQueueDfc = new TDfc( EmptyRxQueueDfc, this, iCompletionThread, KISILddEmptyRxQueuePriori ); + ASSERT_RESET_ALWAYS( iEmptyRxQueueDfc, ( EISIUserChannelMemAllocFail2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + iCompleteChannelRequestDfc = new TDfc( CompleteChannelRequestDfc, this, iCompletionThread, KISILddCompleteRequestPriori ); + ASSERT_RESET_ALWAYS( iCompleteChannelRequestDfc, ( EISIUserChannelMemAllocFail3 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + iRequests = new DISIUserAsyncRequests( EISILastAsyncRequest ); + C_TRACE( ( _T( "DISIUserChannel::DISIUserChannel<" ) ) ); + } + +DISIUserChannel::~DISIUserChannel( + // None + ) + { + C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x>" ), this ) ); + // owned starts + if( iEmptyRxQueueDfc ) + { + C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iEmptyRxQueueDfc 0x%x" ), this, iObjId, iEmptyRxQueueDfc ) ); + iEmptyRxQueueDfc->Cancel(); + delete iEmptyRxQueueDfc; + iEmptyRxQueueDfc = NULL; + } + if( iCompleteChannelRequestDfc ) + { + C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iCompleteChannelRequestDfc 0x%x" ), this, iObjId, iCompleteChannelRequestDfc ) ); + iCompleteChannelRequestDfc->Cancel(); + delete iCompleteChannelRequestDfc; + iCompleteChannelRequestDfc = NULL; + } + if( iRx ) + { + C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iRx 0x%x" ), this, iObjId, iRx ) ); + delete iRx; + iRx = NULL; + } + if( iReceiveBufPtr ) + { + C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x 0x%x iReceiveBufPtr 0x%x" ), this, iObjId, iReceiveBufPtr ) ); + iReceiveBufPtr = NULL; + } + if( iRequests ) + { + delete iRequests; + iRequests = NULL; + } + // owned ends + iRouterIf = NULL; + Kern::SafeClose( reinterpret_cast(iThread), NULL ); + C_TRACE( ( _T( "DISIUserChannel::~DISIUserChannel 0x%x<" ), this ) ); + } + +/* +* Executed in user thread context thread inside CS, cannot be pre-empted. +* Channel can not be used before creation, so no need to synch if congesting only btw the creating user thread and one thread. +*/ +TInt DISIUserChannel::DoCreate( + TInt, //aUnit, // Not used at the moment + const TDesC8*, //anInfo, // Not used at the moment. + const TVersion& // aVer // Not used at the moment. + ) + { + C_TRACE( ( _T( "DISIUserChannel::DoCreate 0x%x 0x%x>" ), this, iObjId ) ); + if( !Kern::CurrentThreadHasCapability( ECapabilityCommDD, __PLATSEC_DIAGNOSTIC_STRING( "Check by: ISI Router" ) ) ) return KErrPermissionDenied; + iRx = new DISIMsgQueue( KISILddRxQueueSize ); + ASSERT_RESET_ALWAYS( iRx, ( EISIUserChannelMemAllocFail1 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + // Other DFC functions handling user<>kernel copying done in ldd DFC. Ldd DFC function priority is 1. + iMainThread = iRouterIf->GetDfcThread( MISIChannelRouterIf::EISIUserMainThread ); + SetDfcQ( iMainThread ); + iMsgQ.Receive(); + DObject* thread = reinterpret_cast( iThread ); + // Open is needed to increase ref count to calling thread that is decreased in Kern::SafeClose + // Possible returns KErrNone ? KErrGeneral + TInt threadOpen( thread->Open() ); + TRACE_ASSERT_INFO( threadOpen == KErrNone, iObjId ); + C_TRACE( ( _T( "DISIUserChannel::DoCreate 0x%x 0x%x<" ), this, iObjId ) ); + return threadOpen; + } + +void DISIUserChannel::HandleMsg( + TMessageBase* aMsg + ) + { + C_TRACE( ( _T( "DISIUserChannel::HandleMsg 0x%x 0x%x 0x%x>" ), this, aMsg, iObjId ) ); + TThreadMessage& m= *( static_cast< TThreadMessage* >( aMsg ) ); + TInt id( m.iValue ); + if( static_cast( ECloseMsg ) == id ) + { + C_TRACE( ( _T( "DISIUserChannel::HandleMsg ECloseMsg 0x%x 0x%x" ), this, aMsg ) ); + m.Complete( HandleSyncRequest( EISIDisconnect, NULL ), EFalse ); + } + else if( KMaxTInt == id ) + { + C_TRACE( ( _T( "DISIUserChannel::HandleMsg cancel 0x%x 0x%x" ), this, aMsg ) ); + DoCancel( id, m.Int0() ); + m.Complete( KErrNone, ETrue ); + } + else + { + ASSERT_RESET_ALWAYS( ( KErrNotFound < id ), ( EISIUserChannelWrongRequest | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + C_TRACE( ( _T( "DISIUserChannel::HandleMsg request 0x%x %d 0x%x" ), this, id, aMsg ) ); + TInt completeValue( KErrNone ); + TInt ulen( KErrNotFound ); + switch ( id ) + { + case EISIDisconnect: + { + ulen = KNoParams; + break; + } + case EISISend: + { + ulen = KOneParam; + break; + } + case EISIConnect: + { + ulen = KTwoParams; + break; + } + case EISIAsyncReceive: + { + ulen = KThreeParams; + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest1 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + break; + } + } + TUint32* table[ KThreeParams ]; + completeValue = Kern::ThreadRawRead( iThread, m.Ptr0(), table, ulen * sizeof( TAny* ) ); + + if( completeValue == KErrNone ) + { + switch( id ) + { + // All asynchronous requests. + case EISIAsyncReceive: + { + // No need to check return value in async functions, completed to user + HandleAsyncRequest( id, table ); + break; + } + case EISIDisconnect: + case EISIConnect: + case EISISend: + { + completeValue = HandleSyncRequest( id, table ); + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + break; + } + } + } + m.Complete( completeValue, ETrue ); + } + C_TRACE( ( _T( "DISIUserChannel::HandleMsg 0x%x 0x%x 0x%x<" ), this, aMsg, iObjId ) ); + } + +TInt DISIUserChannel::Request( + TInt aReqNo, + TAny* a1, + TAny* //a2 + ) + { + C_TRACE( ( _T( "DISIUserChannel::Request 0x%x %d 0x%x 0x%x>" ), this, aReqNo, a1, iObjId ) ); + // Programmer errors. + ASSERT_RESET_ALWAYS( aReqNo >= ( TInt ) EMinRequestId, ( EISIUserChannelWrongRequest3 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + ASSERT_RESET_ALWAYS( ( aReqNo <= EISILastAsyncRequest || aReqNo == KMaxTInt ), ( EISIUserChannelWrongRequest4 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + // Wrong API usage e.g. called function when interface is not open so panic the client thread. + TInt result( KErrNotFound ); + // All request go in kernel context and with ::DoControl call. + TThreadMessage& m=Kern::Message(); + m.iValue = aReqNo; + m.iArg[ KFirstParam ] = a1; + m.iArg[ KSecondParam ] = NULL; + result = m.SendReceive( &iMsgQ ); + C_TRACE( ( _T( "DISIUserChannel::Request 0x%x %d 0x%x<" ), this, aReqNo, a1, iObjId ) ); + return result; + } + +TInt DISIUserChannel::HandleSyncRequest( + TInt aRequest, + TAny* a1 + ) + { + C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x %d 0x%x 0x%x>" ), this, aRequest, a1, iObjId ) ); + ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext5 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + TInt error( KErrNotSupported ); + switch( aRequest ) + { + case EISIDisconnect: + { + C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x EISIDisconnect" ), this ) ); + Disconnect(); + error = KErrNone; + break; + } + case EISISend: + { + C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x EISISend" ), this ) ); + TUint32* tablePtr = reinterpret_cast( a1 ); + TAny* firstParam = reinterpret_cast( tablePtr[ KFirstParam ] ); + TRACE_ASSERT_INFO( firstParam, ( iObjId << KObjIdShift | ( EISIUserChannelNullParam2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ) ); + TInt msgLength( Kern::ThreadGetDesLength( iThread, firstParam ) ); + C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x EISISend 0x%x %d" ), this, firstParam, msgLength ) ); + if( msgLength > 0 && msgLength < KMaxISIMsgSize ) + { + TDes8& sendBlock = MemApi::AllocBlock( msgLength ); + ASSERT_RESET_ALWAYS( KErrNone == Kern::ThreadDesRead( iThread, firstParam, sendBlock, 0, KChunkShiftBy0 ), ( EISIUserChannelDesReadFailed | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + TRACE_ASSERT_INFO( sendBlock.Length() == msgLength, iObjId << KObjIdShift ); + C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest EISISend 0x%x 0x%x" ), this, &sendBlock ) ); + error = iRouterIf->Send( sendBlock, iObjId ); + } + else + { + error = ( msgLength > KMaxISIMsgSize ) ? KErrNoMemory : KErrBadDescriptor; + TRACE_ASSERT_INFO( 0, iObjId << KObjIdShift | (TUint16)msgLength ); + } + break; + } + case EISIConnect: + { + TUint32* tablePtr = reinterpret_cast( a1 ); + iUID = tablePtr[ KFirstParam ]; + TUint8* objIdPtr = reinterpret_cast( tablePtr[ KSecondParam ] ); + C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest EISIConnect 0x%x 0x%x 0x%x" ), this, iUID, objIdPtr ) ); + iRouterIf->Connect( iUID, iObjId, this ); + C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest received iObjId is 0x%x" ), iObjId ) ); + ASSERT_RESET_ALWAYS( KErrNone == Kern::ThreadRawWrite( iThread, objIdPtr, &iObjId, sizeof(TUint8), iThread ), + EISIUserChannelDesWriteFailed | iObjId << KObjIdShift | EDISIUserChannelTraceId << KClassIdentifierShift ); + error = KErrNone; + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest5 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + break; + } + } + C_TRACE( ( _T( "DISIUserChannel::HandleSyncRequest 0x%x %d 0x%x 0x%x<" ), this, aRequest, a1, iObjId ) ); + return error; + } + +void DISIUserChannel::HandleAsyncRequest( + TInt aRequest, + TAny* a1 + ) + { + C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x %d 0x%x 0x%x>" ), this, aRequest, a1, iObjId ) ); + + ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext4 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + TUint32* tablePtr = reinterpret_cast( a1 ); + TRACE_ASSERT_INFO( tablePtr[ KFirstParam ], (TUint16)aRequest ); + TRequestStatus* requestStatus = reinterpret_cast( tablePtr[ KFirstParam ] ); + if( iRequests->IsPending( aRequest ) ) + { + C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest existing 0x%x request 0x%x" ), this, aRequest ) ); + // Should not give same request object twice before completing the first one. + ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelSameRequest | iObjId << KObjIdShift | static_cast( aRequest ) << KExtraInfoShift ) ); + } + else + { + C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x handling %d" ), this, aRequest ) ); + iRequests->SetPending( aRequest, requestStatus ); + switch( aRequest ) + { + case EISIAsyncReceive: + { + iReceiveBufPtr = reinterpret_cast( tablePtr[ KSecondParam ] ); + iNeededBufLen = reinterpret_cast( tablePtr[ KThirdParam ] ); + C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x EISIAsyncReceive 0x%x" ), this, iReceiveBufPtr ) ); + iEmptyRxQueueDfc->Enque(); + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + break; + } + } + } + C_TRACE( ( _T( "DISIUserChannel::HandleAsyncRequest 0x%x %d 0x%x 0x%x<" ), this, aRequest, a1, iObjId ) ); + } + + +void DISIUserChannel::DoCancel( + TInt aRequest, + TInt aMask ) + { + C_TRACE( ( _T( "DISIUserChannel::DoCancel 0x%x %d 0x%x 0x%x>" ), this, aRequest, aMask, iObjId ) ); + switch( aMask&aRequest ) + { + case EISIAsyncReceive: + { + C_TRACE( ( _T( "DISIUserChannel::DoCancel 0x%x EISIAsyncReceive 0x%x " ), this, iReceiveBufPtr ) ); + iReceiveBufPtr = NULL; + break; + } + default: + { + ASSERT_RESET_ALWAYS( 0, ( EISIUserChannelWrongRequest6 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + break; + } + } + EnqueChannelRequestCompleteDfc( aMask&aRequest, KErrCancel ); + C_TRACE( ( _T( "DISIUserChannel::DoCancel 0x%x %d 0x%x 0x%x<" ), this, aRequest, aMask, iObjId ) ); + } + + +void DISIUserChannel::Disconnect( + // None + ) + { + C_TRACE( ( _T( "DISIUserChannel::Disconnect 0x%x 0x%x>" ), this, iObjId ) ); + ResetQueues(); + for( TInt i( 0 ); i < iRequests->iRequestCompletedList.Count(); ++i ) + { + C_TRACE( ( _T( "DISIUserChannel::CancelRequests req to cancel %d" ), i ) ); + DoCancel( KMaxTInt, i ); + } + iRouterIf->Disconnect( iObjId ); + iRouterIf->FreeDfcThread( iMainThread ); + iRouterIf->FreeDfcThread( iCompletionThread ); + C_TRACE( ( _T( "DISIUserChannel::Disconnect 0x%x 0x%x<" ), this, iObjId ) ); + } + +void DISIUserChannel::ResetQueues( + // None + ) + { + C_TRACE( ( _T( "DISIUserChannel::ResetQueues 0x%x 0x%x>" ), this, iObjId ) ); + if( iRx ) + { + C_TRACE( ( _T( "DISIUserChannel::ResetQueues 0x%x iRx 0x%x" ), this, iRx ) ); + while( iRx->Count() ) + { + MemApi::DeallocBlock( iRx->Get() ); + } + } + C_TRACE( ( _T( "DISIUserChannel::ResetQueues 0x%x 0x%x<" ), this, iObjId ) ); + } + +// This is called in 1...N thread contextes +void DISIUserChannel::ReceiveMsg( + const TDesC8& aMessage + ) + { + C_TRACE( ( _T( "DISIUserChannel::ReceiveMsg 0x%x 0x%x 0x%x>" ), this, &aMessage, iObjId ) ); + // Can only be called from thread context. + ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext3 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + iRx->Add( aMessage ); + iEmptyRxQueueDfc->Enque(); + C_TRACE( ( _T( "DISIUserChannel::ReceiveMsg 0x%x 0x%x 0x%x<" ), this, &aMessage, iObjId ) ); + } + +DISIUserChannel::DISIUserAsyncRequests::DISIUserAsyncRequests( + const TInt aSize + ) + { + C_TRACE( ( _T( "DISIUserAsyncRequests::DISIUserAsyncRequests size %d>" ), aSize ) ); + iRequestLock = new NFastMutex(); + C_TRACE( ( _T( "DISIUserAsyncRequests::DISIUserAsyncRequests<" ) ) ); + } + +DISIUserChannel::DISIUserAsyncRequests::~DISIUserAsyncRequests() + { + + C_TRACE( ( _T( "DISIUserAsyncRequests::~DISIUserAsyncRequests>" ) ) ); + iRequestCompletedList.Close(); + delete iRequestLock; + C_TRACE( ( _T( "DISIUserAsyncRequests::~DISIUserAsyncRequests<" ) ) ); + + } + +TBool DISIUserChannel::DISIUserAsyncRequests::IsPending( + const TUint aRequest + ) + { + C_TRACE( ( _T( "DISIUserAsyncRequests::IsPending %d>" ), aRequest ) ); + ASSERT_RESET_ALWAYS( ( EISILastAsyncRequest > aRequest && EISIAsyncReceive <= aRequest ), ( EISIUserChannelReqOverTheLimits | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + TBool ret( EFalse ); + NKern::FMWait( iRequestLock ); + ret = ( iRequestStatusList[ aRequest ] ) ? ETrue : EFalse; + NKern::FMSignal( iRequestLock ); + C_TRACE( ( _T( "DISIUserAsyncRequests::IsPending %d %d<" ), aRequest, ret ) ); + return ret; + } + +void DISIUserChannel::DISIUserAsyncRequests::SetPending( + const TUint aRequest, + TRequestStatus* aStatus + ) + { + C_TRACE( ( _T( "DISIUserAsyncRequests::SetPending %d 0x%x>" ), aRequest, aStatus ) ); + ASSERT_RESET_ALWAYS( aRequest, ( EISIUserChannelNullParam | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + ASSERT_RESET_ALWAYS( aStatus, ( EISIUserChannelNullParam | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + ASSERT_RESET_ALWAYS( ( EISILastAsyncRequest > aRequest && EISIAsyncReceive <= aRequest ), ( EISIUserChannelReqOverTheLimits | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + // Note asserts must be done before holding the lock. + NKern::FMWait( iRequestLock ); + iRequestStatusList[ aRequest ] = aStatus; + NKern::FMSignal( iRequestLock ); + C_TRACE( ( _T( "DISIUserAsyncRequests::SetPending %d 0x%x<" ), aRequest, aStatus ) ); + } + +void DISIUserChannel::EmptyRxQueueDfc( + TAny* aPtr // Pointer to self + ) + { + C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc>" ) ) ); + DISIUserChannel& chTmp = *reinterpret_cast( aPtr ); + C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc 0x%x 0x%x>" ), &chTmp, chTmp.iObjId ) ); + if( chTmp.iRequests->IsPending( EISIAsyncReceive ) && ( chTmp.iRx->Count() > 0 ) ) + { + TDes8& tmpDes = chTmp.iRx->Get(); + TInt desMaxLen( Kern::ThreadGetDesMaxLength( chTmp.iThread, chTmp.iReceiveBufPtr ) ); + // If user descriptor legth is enough and length get not failed. + if( desMaxLen >= tmpDes.Length() ) + { + // Write to user address space (iReceiveBufPtr) the content of tmpDes starting from zero offset as 8bit descriptor data. + TInt writeError( Kern::ThreadDesWrite( chTmp.iThread, chTmp.iReceiveBufPtr, tmpDes, KDestStartOffset, KChunkShiftBy0, chTmp.iThread ) ); + if( writeError == KErrNone ) + { + C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc write 0x%x k->u 0x%x ok" ), &tmpDes, chTmp.iReceiveBufPtr ) ); + chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, writeError ); + MemApi::DeallocBlock( tmpDes ); + } + // Write unsuccesfull don't deallocate the block. + else + { + C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc write 0x%x k->u 0x%x NOK, reason %d" ), &tmpDes, chTmp.iReceiveBufPtr, writeError ) ); + TRACE_ASSERT_INFO( 0, chTmp.iObjId << KObjIdShift | (TUint16)writeError ); + // Roll the message back to que. + chTmp.iRx->RollBack( tmpDes ); + chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, writeError ); + } + } + // If descriptor invalid. + else + { + TRACE_WARNING( 0, chTmp.iObjId << KObjIdShift | (TUint16)tmpDes.Length() ); + // Roll the message back to que. + chTmp.iRx->RollBack( tmpDes ); + // If invalid content. + if( KErrBadDescriptor == desMaxLen ) + { + TRACE_ASSERT_INFO( 0, chTmp.iObjId << KObjIdShift | (TUint16)desMaxLen ); + C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc invalid descriptor 0x%x" ), chTmp.iObjId ) ); + chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, KErrBadDescriptor ); + } + // If length too small (if other assert). + else + { + TUint16 neededLength( tmpDes.Length() ); + TRACE_WARNING( 0, chTmp.iObjId << KObjIdShift | (TUint16)desMaxLen ); + C_TRACE( ( _T( "DISAUserChannel::EmptyRxQueueDfc descriptor length too small length %d needed %d" ), desMaxLen, neededLength ) ); + ASSERT_RESET_ALWAYS( KErrNone == Kern::ThreadRawWrite( chTmp.iThread, chTmp.iNeededBufLen, &neededLength, sizeof(TUint16), chTmp.iThread ), + EISIUserChannelDesWriteFailed | chTmp.iObjId << KObjIdShift | EDISIUserChannelTraceId << KClassIdentifierShift ); + chTmp.EnqueChannelRequestCompleteDfc( EISIAsyncReceive, KErrOverflow ); + } + } + } + else + { + C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc no receive active or no message" ) ) ); + } + C_TRACE( ( _T( "DISIUserChannel::EmptyRxQueueDfc 0x%x<" ), chTmp.iObjId ) ); + } + +// called in router ext context +void DISIUserChannel::EnqueChannelRequestCompleteDfc( + TInt aRequest, + TInt aStatusToComplete + ) + { + C_TRACE( ( _T( "DISIUserChannel::EnqueChannelRequestCompleteDfc 0x%x %d %d 0x%x>" ), this, aRequest, aStatusToComplete, iObjId ) ); + ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + //TODO check the error code + iRequests->iRequestCompletedList.Append( aRequest ); + iRequests->iRequestCompletionValueList[ aRequest ] = aStatusToComplete; + iCompleteChannelRequestDfc->Enque(); + C_TRACE( ( _T( "DISIUserChannel::EnqueChannelRequestCompleteDfc 0x%x %d %d 0x%x<" ), this, aRequest, aStatusToComplete, iObjId ) ); + } + +// Run in ISI user channel kernel thread context. +void DISIUserChannel::CompleteChannelRequestDfc( + TAny* aPtr + ) + { + C_TRACE( ( _T( "DISIUserChannel::CompleteChReqDfc>" ) ) ); + // Make sure that user side is accessed only by ldd DFCThread. + ASSERT_THREAD_CONTEXT_ALWAYS( ( EISIUserChannelfNotThreadContext2 | EDISIUserChannelTraceId << KClassIdentifierShift ) ); + DISIUserChannel* chPtr = reinterpret_cast( aPtr ); + C_TRACE( ( _T( "DISIUserChannel::CompleteChReqDfc 0x%x 0x%x" ), chPtr, chPtr->iObjId ) ); + TInt request = chPtr->iRequests->iRequestCompletedList[ KFirstRequest ]; + TRequestStatus* status( chPtr->iRequests->iRequestStatusList[ request ] ); + Kern::RequestComplete( chPtr->iThread, status, chPtr->iRequests->iRequestCompletionValueList[ request ] ); + chPtr->iRequests->iRequestCompletedList.Remove( KFirstRequest ); + chPtr->iRequests->iRequestStatusList[ request ] = NULL; + chPtr->iRequests->iRequestCompletionValueList[ request ] = KNotInitializedStatus; + + if( chPtr->iRequests->iRequestCompletedList.Count() != 0 ) + { + CompleteChannelRequestDfc( chPtr ); + } + C_TRACE( ( _T( "DISIUserChannel::CompleteChReqDfc 0x%x 0x%x<" ), chPtr, chPtr->iObjId ) ); + }