AO deadlock
| Thu, 2007-11-08 20:34 | |
|
Hi, i have a BIG problem with deadlocks of two active objects. With best regards |
|
| Thu, 2007-11-08 20:34 | |
|
Hi, i have a BIG problem with deadlocks of two active objects. With best regards |
|
Forum posts: 13
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);
}
Forum posts: 13
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;
}
Forum posts: 13
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?
Forum posts: 13
Please, advice!
Forum posts: 1239
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
Forum posts: 13
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.
Forum posts: 1232
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?