AO deadlock

Login to reply to this topic.
Thu, 2007-11-08 20:34
Joined: 2007-08-24
Forum posts: 13

Puzzled

Hi, i have a BIG problem with deadlocks of two active objects.
Please advice wrong in following code.
First Active object is a control object which receve external requests. Sometimes it's get request for sending sms and execute Secont Active object. On all my phones code work perfectly. But on other user phones a bug appear. Program stuck after sending sms. Bug unstable it may appear and disappear. So i expect a deadlock.
Plase look at following code and advice, is there any warnings about deadlock

With best regards


Thu, 2007-11-08 20:35
Joined: 2007-08-24
Forum posts: 13
Re: AO deadlock

Host object

demon::demon()
: CActive( CActive::EPriorityStandard )
{
WaitingPhones = new (ELeave) CDesCArrayFlat(3);
WaitingMessages = new (ELeave) CDesCArrayFlat(3);
RegisteredPhones = new (ELeave) CDesCArrayFlat(3);
}


void demon::ConstructL()
{

CActiveScheduler::Add( this );
iPhoneBookHandler = CPhoneBook::NewL(this);

iSmsHandler = CSmsHandler::NewL();
iSmsHandler->iDemon = this;
}


demon* demon::NewL( )
{
demon* self = NewLC( );
CleanupStack::Pop( self );
return self;
}

demon* demon::NewLC( )
{
demon* self = new ( ELeave ) demon( );
CleanupStack::PushL( self );
self->ConstructL();
return self;
}


demon::~demon()
{
if (iSmsHandler != NULL)
{
iSmsHandler->Cancel();
delete iSmsHandler;
iSmsHandler = NULL;
}

if (RegisteredPhones != NULL)
{
delete RegisteredPhones;
RegisteredPhones = NULL;
}

if (WaitingMessages != NULL)
{
delete WaitingMessages;
WaitingMessages = NULL;
}

if (WaitingPhones != NULL)
{
delete WaitingPhones;
WaitingPhones = NULL;
}

}

void demon::DoCancel()
{
iTimer.Cancel();
}

void demon::StartL( TTimeIntervalMicroSeconds32 aDelay )
{
Cancel();
iState = EUninitialized;
iTimer.After( iStatus, aDelay );
SetActive();
}


void demon::RunL()
{


if ( iState == EUninitialized )
{
// Do something the first time RunL() is called
iState = EInitialized;
}
else if ( iState != EError )
{


if (!iSmsHandler->iBusy)
{
if (WaitingMessages->Count() != 0)
{
if ((*WaitingPhones)[0].Length() > 0)
iSmsHandler->SendL((*WaitingPhones)[0], (*WaitingMessages)[0], WaitingOptions[0]);

WaitingMessages->Delete(0);
WaitingPhones->Delete(0);
WaitingOptions.Remove(0);
}

}

}
iTimer.After( iStatus, 1000000 );
SetActive();
}


TInt demon::RunError( TInt aError )
{
return KErrNone;
}


void demon::SendSMS(const TPtrC & PhoneNum, const TPtrC & Message, TBool AddHeader)
{
if (PhoneNum.Length() <= 0) return;

WaitingPhones->AppendL(PhoneNum);
WaitingMessages->AppendL(send);
WaitingOptions.AppendL(Unicode);
}

Thu, 2007-11-08 20:35
Joined: 2007-08-24
Forum posts: 13
Re: AO deadlock

SMS Sender object

CSmsHandler::CSmsHandler( )
: CActive( CActive::EPriorityStandard )
{
CActiveScheduler::Add( this );
iBusy = EFalse;
}

void CSmsHandler::ConstructL()
{
iSession = CMsvSession::OpenAsyncL( *this );

iSelection = new ( ELeave ) CMsvEntrySelection();

iSMSCleaner = CSMSCleaner::NewL();
iDemon = NULL;
}

CSmsHandler* CSmsHandler::NewL( )
{
CSmsHandler* self = NewLC( );
CleanupStack::Pop( self );
return self;
}

CSmsHandler* CSmsHandler::NewLC( )
{
CSmsHandler* self = new ( ELeave ) CSmsHandler( );
CleanupStack::PushL( self );
self->ConstructL();
return self;
}

CSmsHandler::~CSmsHandler()
{
Cancel(); // cancel any outstanding request

delete iOperation;
delete iSelection;
delete iSmsMtm;
delete iSmsMtm2;
delete iMtmRegistry;
delete iSession; // session must be deleted last
if (iSMSCleaner)
{
delete iSMSCleaner;
iSMSCleaner = NULL;
}
}

void CSmsHandler::DoCancel()
{
if ( iOperation )
{
iOperation->Cancel();
}
}

void CSmsHandler::RunL()
{
User::LeaveIfError( iStatus != KErrNone );

TBufC8<KMsvProgressBufferLength> progress( iOperation->ProgressL() );
_LIT8( KCompare, "KErrNone" );
User::LeaveIfError( !progress.Compare( KCompare ) );


delete iOperation;
iOperation = NULL;

switch ( iState )
{
case EWaitingForMoving:
ScheduleL();
break;

case EWaitingForScheduling:
{
TMsvEntry entry( iSmsMtm->Entry().Entry() );
iSMSCleaner->DeleteSMS(entry.Id());
iBusy = EFalse;
break;
}

default:
break;
}
}


void CSmsHandler::HandleSessionEventL( TMsvSessionEvent aEvent,
TAny* aArg1, TAny* aArg2, TAny* aArg3)
{

switch ( aEvent )
{
case EMsvServerReady:
{
TMsvId serviceId( KUidMsgTypeSMS.iUid ); // SMS service id

TBuf8<KBfrLength> progress;
iSession->ServiceProgress( serviceId, progress );
_LIT8( KCompare, "KErrNone" );

if ( progress.Compare( KCompare ) )
{
if ( !iMtmRegistry )
{
AccessMtmL();
}
}

else
{
}

break;
}

case EMsvEntriesCreated:
{
TMsvId* entryId2 = STATIC_CAST( TMsvId*, aArg2 );

if ( *entryId2 != KMsvGlobalInBoxIndexEntryId)
{
break;
}

CMsvEntrySelection* newEntries2 =
STATIC_CAST( CMsvEntrySelection*, aArg1 );

for ( TInt i( 0 ); i < newEntries2->Count(); i++ )
{
iSelection->AppendL( newEntries2->At( i ), 1 );

MessageReceivedL( newEntries2->At( i ) );
}

//CleanupStack::PopAndDestroy(serverEntry2);

break;
}

case EMsvEntriesMoved:
{
TMsvId* entryId = STATIC_CAST( TMsvId*, aArg3 );


if (*entryId != KMsvGlobalOutBoxIndexEntryId)
{
break;
}

CMsvEntrySelection* newEntries =
STATIC_CAST( CMsvEntrySelection*, aArg1 );

for ( TInt i( 0 ); i < newEntries->Count(); i++ )
{
MessageSendL(newEntries->At( i ));
}
break;
}


}

case EMsvCloseSession:
case EMsvServerTerminated:
case EMsvGeneralError:
case EMsvServerFailedToStart:
{
iSession = CMsvSession::OpenAsyncL( *this );
iBusy = EFalse;
AccessMtmL();
break;
}

default:
break;
}
}


void CSmsHandler::AccessMtmL()
{
// Create an MTM Registry object.
iMtmRegistry = CClientMtmRegistry::NewL( *iSession );

// Create an SMS Client MTM object.
iSmsMtm = STATIC_CAST( CSmsClientMtm*, iMtmRegistry->NewMtmL( KUidMsgTypeSMS ) );
iSmsMtm2 = STATIC_CAST( CSmsClientMtm*, iMtmRegistry->NewMtmL( KUidMsgTypeSMS ) );
}

TBool CSmsHandler::SendL( const TDesC& aRecipientNumber,
const TDesC& aMessageText,
TBool Unicode)
{
iBusy = ETrue;
iRecipientNumber = aRecipientNumber;
iMessageText = aMessageText;

if ( CreateMsgL() )
{
return ETrue;
}


return EFalse;
}

TBool CSmsHandler::CreateMsgL(TBool Unicode)
{
iSmsMtm->SwitchCurrentEntryL( KMsvDraftEntryId );

iSmsMtm->CreateMessageL( KUidMsgTypeSMS.iUid );

CMsvEntry& serverEntry = iSmsMtm->Entry();
TMsvEntry entry( serverEntry.Entry() );

CRichText& body = iSmsMtm->Body(); // the body of the message
body.Reset();
body.InsertL( 0, iMessageText );

entry.SetSendingState( KMsvSendStateWaiting );
//not working in 3rd ed
//http://www.forum.nokia.com/document/Forum_Nokia_Technical_Library/contents/FNTL/Custom-created_message_left_in_Outbox.htm
// entry.iDate.HomeTime(); // insert current time
entry.iDate.UniversalTime(); // insert current time

// Set the SMS message settings for the message.
CSmsHeader& header = iSmsMtm->SmsHeader();
CSmsSettings* settings = CSmsSettings::NewL();
CleanupStack::PushL( settings );

settings->CopyL( iSmsMtm->ServiceSettings() ); // restore settings
if (Unicode)
settings->SetCharacterSet(TSmsDataCodingScheme::ESmsAlphabetUCS2);

settings->SetDeliveryReport(EFalse);
settings->SetDelivery( ESmsDeliveryImmediately ); // to be delivered immediately
header.SetSmsSettingsL( *settings ); // new settings



if ( header.Message().ServiceCenterAddress().Length() == 0 )
{
CSmsSettings* serviceSettings = &( iSmsMtm->ServiceSettings() );

if ( !serviceSettings->NumSCAddresses() )
{
CleanupStack::PopAndDestroy( settings );
return EFalse; // quit creating the message
}

else
{
CSmsNumber* smsCenter =
&( serviceSettings->SCAddress( serviceSettings->DefaultSC() ) );
header.Message().SetServiceCenterAddressL( smsCenter->Address() );
}
}

CleanupStack::PopAndDestroy( settings );

entry.iDetails.Set( iRecipientNumber );
iSmsMtm->AddAddresseeL( iRecipientNumber, entry.iDetails );

if ( !ValidateL() )
{
return EFalse;
}

entry.SetVisible( ETrue ); // set message as visible
entry.SetInPreparation( EFalse ); // set together with the visibility flag

entry.iMtmData3 = KVMSDemonUid.iUid;
serverEntry.ChangeL( entry ); // commit changes


iSmsMtm->SaveMessageL(); // save message

TMsvSelectionOrdering selection;
CMsvEntry* parentEntry =
CMsvEntry::NewL( iSmsMtm->Session(), KMsvDraftEntryId, selection );
CleanupStack::PushL( parentEntry );

iOperation =
parentEntry->MoveL( entry.Id(), KMsvGlobalOutBoxIndexEntryId, iStatus );

CleanupStack::PopAndDestroy( parentEntry );

iState = EWaitingForMoving;
SetActive();
return ETrue;
}


TBool CSmsHandler::ValidateL()
{
// Empty part list to hold the result.
TMsvPartList result( KMsvMessagePartNone );

// Validate message body.
result = iSmsMtm->ValidateMessage( KMsvMessagePartBody );

if ( result != KMsvMessagePartNone )
{
return EFalse;
}

// Validate recipient.
result = iSmsMtm->ValidateMessage( KMsvMessagePartRecipient );

if ( result != KMsvMessagePartNone )
{
return EFalse;
}

return ETrue;
}

Thu, 2007-11-08 20:37
Joined: 2007-08-24
Forum posts: 13
Re: AO deadlock

Continue

void CSmsHandler::ScheduleL()
{
if (iSmsMtm->Entry().Entry().iMtmData3 != KVMSDemonUid.iUid)
{
return;
}
CMsvEntrySelection* selection = new ( ELeave ) CMsvEntrySelection;
CleanupStack::PushL( selection );
selection->AppendL( iSmsMtm->Entry().EntryId() ); // add message to selection

// Add entry to task scheduler.
TBuf8<1> dummyParams; // dummy parameters needed for InvokeAsyncFunctionL
iOperation = iSmsMtm->InvokeAsyncFunctionL( ESmsMtmCommandScheduleCopy,//ESmsMtmCommandScheduleCopy,
*selection, dummyParams, iStatus );


CleanupStack::PopAndDestroy( selection );

iState = EWaitingForScheduling;
SetActive();
}


void CSmsHandler::MessageSendL( TMsvId aEntryId )
{


CMsvEntry* serverEntry(NULL);
TRAPD(KErr, serverEntry = iSession->GetEntryL( aEntryId ));
if (KErr == KErrNotFound || serverEntry == NULL) return;

CleanupStack::PushL(serverEntry);

TMsvEntry entry = serverEntry->Entry(); // currently handled message entry
CleanupStack::PopAndDestroy();

if ( entry.iMtm != KUidMsgTypeSMS )
{
return;
}



iSmsMtm2->SwitchCurrentEntryL(aEntryId);


iSmsMtm2->LoadMessageL();
CRichText& body = iSmsMtm2->Body();


TRAPD(KSMSHdrErr, iSmsMtm2->SmsHeader());

TPtrC Sender = iSmsMtm2->SmsHeader().FromAddress().Right(30);


body.Extract(Buf, 0);


if (Buf.Left(KHdr1().Length()) == KHdr1 ||
Buf.Left(KHdr2().Length()) == KHdr2 ||
Buf.Left(KHdr2().Length()) == KHdr3)
{

CMsvEntry* serverEntry3(NULL);
TRAPD (Err, serverEntry3= iSession->GetEntryL(aEntryId ));
if (Err != KErrNone) return;
CleanupStack::PushL(serverEntry3);
TMsvEntry entry2 = serverEntry3->Entry(); // currently handled message entry
entry2.SetNew( EFalse );
entry2.SetUnread( EFalse );
entry2.SetVisible( EFalse );
TRAPD(err, serverEntry3->ChangeL( entry2 )); // comm
CleanupStack::PopAndDestroy(serverEntry3);

return;
}

}

is that ok, what i use
TBool iBusy

to signal what sms still processing?

Sat, 2007-11-10 14:33
Joined: 2007-08-24
Forum posts: 13
Re: AO deadlock

Please, advice!

Sat, 2007-11-10 17:06
Joined: 2005-11-20
Forum posts: 1239
Re: AO deadlock

For me it's not surprising that your post does not get answers: I think that too much time would be needed for somebody to read your entire program, understand it, and then find the problem. It also does not help that your code is hard to read because somehow the indentation did not survive.

I myself do not know enough about AO to advice anything. I just find it strange that I cannot recognize some of the "usual AO stuff" in your code, like WaitForRequest. Isn't the whole point of AO to get rid of things like your 'iBusy' to signal that something is still working? But as I said, don't ask me about details.

So, if we assume for the sake of argument that my doubts are wrong and your code makes - at least in principle - good use of Symbian active objects, the way "it's meant to be", and just has a bug somewhere, how to proceed then? In this situation I would probably build some logging facility into my program, by writing into a file on the phone what happens in my program. Hopefully by studying the log of a program run where the problem occured I would learn enough about the problem to get nearer to a solution.


René Brunner

Sat, 2007-11-10 17:44
Joined: 2007-08-24
Forum posts: 13
Re: AO deadlock

Hi,
I know it's big, but i make all what i can to solve it. First of all i can't normally repeat bug. It's appear only on special devices in special time. And can disappear with sim changing or program reinstall or just disappear. I check all logs and find what after something happen ActiveSheduller does't execute 1st object RunL(). Like it's haven't asynch requiest.
I think u really can't help me with AO. Bcs WaitForRequest never used in AO.

Mon, 2007-11-12 13:59
Joined: 2004-11-29
Forum posts: 1232
Re: AO deadlock

If I had the problem you have, I would start by adding lots of trace output, to see if something happens in a strange order, that I didn't expect.
Also check what is the last lines run before lockup and try figure out what could be wrong with them. (waste of time to check all lines)
If that doesn't give me anything, write detailed sequence diagrams over what calls what, when, and analyse this for possible deadlocks.
Then repeat point 1, trying to find out why my measurements doesn't show the error, since it then must be something wrong with my measurements, since there is an error..
Then repeat point 2, finding the error in my sequences...
Usually the problem is found after one or two iterations, but if not, I probably would ask for help, and in detail describe what I've tried and my theories, to see if someone could help me with a new angle I havn't tried already.

I think you are very optimistic, and over-estimate our capability a bit, posting several pages of code and expecting us to be able to quickly find a problem in it that you can't find after hours or days of trying (I hope)...

My main tip to you is to not look at code when trying to find deadlocks, look at sequences... what really happens and in what order, when are threads waiting, and for what?

  • Login to reply to this topic.