Fixed chunkinfo and RAllocatorHelper crashes.
authorTom Sutcliffe <thomas.sutcliffe@accenture.com>
Wed, 15 Sep 2010 18:07:34 +0100
changeset 59 c9dfb364c2d1
parent 58 377ac716dabb
child 60 f9caadcaea11
Fixed chunkinfo and RAllocatorHelper crashes. Details: * Tidied leak docs * Updated dialog command to workaround text windowserver bug and implement DIALOG_IMPL as an enum option. Also tried to support dismissing the dialog with CTRL-C but ended up just printing a warning as the notifier API is broken * Fixed RAllocatorHelper::OpenChunkHeap() (and thus chunkinfo <address>) and took Adrian's latest changes. * Fixed chunkinfo OOM problem
commands/leak/leak.cif
core/builtins/dialog.cif
core/src/command_wrappers.cpp
core/src/commands.cpp
core/src/commands.h
documentation/change_history.pod
libraries/ltkutils/inc/heaputils.h
libraries/ltkutils/src/heaphackery.cpp
--- a/commands/leak/leak.cif	Tue Sep 14 09:49:39 2010 +0100
+++ b/commands/leak/leak.cif	Wed Sep 15 18:07:34 2010 +0100
@@ -18,7 +18,7 @@
 
 ==long-description
 
-Sits in a loop allocating memory. This continues until either the specified amount of memory has been consumed, or an error occurs. The allocations can be configured to come from a raw RChunk, or via an RHeap (C<User::ChunkHeap()>). The command waits for a keypress before exiting and freeing the memory.
+Sits in a loop allocating memory. This continues until either the specified amount of memory has been consumed, or an error occurs. The allocations are not done in the main application heap, rather the from a raw RChunk (the default), or via an RHeap (C<User::ChunkHeap()>) if the C<--heap> option is given. The command waits for a keypress before exiting and freeing the memory.
 
 ==see-also
 
@@ -40,10 +40,6 @@
 
 The amount of time (in milliseconds) to wait between each increment. Defaults to zero (i.e. no wait).
 
-==option uint a address
-
-The address of a heap to leak into. The value should be in the address space of the process given by the C<--processid> option.
-
 ==option bool H heap
 
 Use a ChunkHeap to consume the memory rather than a straight RChunk.
--- a/core/builtins/dialog.cif	Tue Sep 14 09:49:39 2010 +0100
+++ b/core/builtins/dialog.cif	Wed Sep 15 18:07:34 2010 +0100
@@ -18,29 +18,11 @@
 
 ==long-description
 
-Up to two buttons are supported. By default the first is labelled C<OK> and the second C<Cancel>. The button the user selected can be determined by the return code of the command. The first button will produce a return code of zero (0), and the second a code of one (1). If there was an error displaying the dialog, the error code will be returned (always a negative number). The return code makes it possible to write scripts like:
-
-  dialog --body 'Do you want to proceed?' && do_something
-
-This will result in F<do_something> only being executed if the user presses the first button. An error or the user pressing the second button with NOT result in F<do_something> being executed. Note though that the text window server's notifier implementation appears to assign the first button one (1) and the second, zero (0). Also, on the 3rd edition of S60 killing a dialog command while it is running will result in the handset resetting itself when the actual dialog is dismissed.
-
-The environment variable C<DIALOG_IMPL> can be used to control the way in which the user is interacted with. The following values of C<DIALOG_IMPL> are supported:
-
-=over 5
-
-=item C<notifier>
+Up to two buttons are supported. If neither C<--first-button> or C<--second-button> are specified, two buttons are shown, C<OK> and C<Cancel>. The button the user selected can be determined by the return code of the command. The first button will produce a return code of zero (0), and the second a code of one (1). If there was an error displaying the dialog, the error code will be returned (always a negative number). The return code makes it possible to write scripts like:
 
-The C<RNotifier> API will be used. This is the default if C<DIALOG_IMPL> is not defined The behaviour of C<RNotifier> depends on the handset configuration, but normally it will result in graphical dialogs being displayed.
-
-=item C<console>
-
-The user will be interacted with via the console that the dialog command is connected to. In this mode, pressing the enter (or on some platforms, select) key corresponds to pressing the first button and any other corresponds to pressing the second button.
+  dialog "Do you want to proceed?" && do_something
 
-=item C<null>
-
-No attempt is made to interact with the user and it is assumed that the first button is always pressed. This mode allows all user interaction to be disabled.
-
-=back
+This will result in C<do_something> only being executed if the user presses the first button. An error or the user pressing the second button with NOT result in C<do_something> being executed. Note that killing a dialog command while it is running will usually result in the device crashing or hanging, to prevent this the dialog command traps the CTRL-C key combination.
 
 ==argument string body optional
 
@@ -48,7 +30,7 @@
 
 ==option string t title
 
-The title of the dialog.
+The title of the dialog. If not specified, defaults to "Attention".
 
 ==option string f first-button
 
@@ -58,6 +40,22 @@
 
 The text for the first button.
 
+==option enum m mode DIALOG_IMPL
+
+Specify the way in which the dialog is displayed. If not specified the default is "notifier".
+
+==enum-value notifier
+
+The C<RNotifier> API will be used. The behaviour of C<RNotifier> depends on the handset configuration, but normally it will result in a graphical dialog being displayed.
+
+==enum-value console
+
+The user will be interacted with via the console that the dialog command is connected to. In this mode, pressing the enter (or on some platforms, select) key corresponds to pressing the first button and any other input corresponds to pressing the second button.
+
+==enum-value null
+
+The dialog is not shown to the user and it is assumed that the first button is always pressed. This mode allows all user interaction to be disabled.
+
 ==copyright
 
 Copyright (c) 2006-2010 Accenture. All rights reserved.
--- a/core/src/command_wrappers.cpp	Tue Sep 14 09:49:39 2010 +0100
+++ b/core/src/command_wrappers.cpp	Wed Sep 15 18:07:34 2010 +0100
@@ -17,7 +17,7 @@
 // Constants.
 //
 
-const TInt KMaxHeapSize = KMinHeapSize * 1024;
+const TInt KMaxHeapSize = 1024*1024; // 1 MB
 
 
 //
--- a/core/src/commands.cpp	Tue Sep 14 09:49:39 2010 +0100
+++ b/core/src/commands.cpp	Wed Sep 15 18:07:34 2010 +0100
@@ -4731,14 +4731,17 @@
 
 CCmdDialog::~CCmdDialog()
 	{
+	Cancel();
+	iNotifier.Close();
 	delete iTitle;
 	delete iBody;
 	delete iButton1;
 	delete iButton2;
 	}
 
-CCmdDialog::CCmdDialog() : CCommandBase(EManualComplete)
-	{
+CCmdDialog::CCmdDialog() : CCommandBase(EManualComplete|ECaptureCtrlC)
+	{
+	SetExtension(this);
 	}
 
 const TDesC& CCmdDialog::Name() const
@@ -4747,34 +4750,6 @@
 	return KName;
 	}
 
-CCmdDialog::TMode CCmdDialog::ModeL() const
-	{
-	_LIT(KDialogImpl, "DIALOG_IMPL");
-	_LIT(KImplNotifier, "notifier");
-	_LIT(KImplConsole, "console");
-	_LIT(KImplNull, "null");
-
-	TMode mode = EModeNotifier;
-	if (Env().IsDefined(KDialogImpl))
-		{
-		const TDesC& impl = Env().GetAsDesL(KDialogImpl);
-		if (impl == KImplNotifier)
-			{
-			mode = EModeNotifier;
-			}
-		else if (impl == KImplConsole)
-			{
-			mode = EModeConsole;
-			}
-		else if (impl == KImplNull)
-			{
-			mode = EModeNull;
-			}
-		}
-
-	return mode;
-	}
-
 void CCmdDialog::DoRunL()
 	{
 	if (iTitle == NULL)
@@ -4803,21 +4778,14 @@
 		Stdin().ReadL(ptr);
 		}
 	
-	switch (ModeL())
+	switch (iMode)
 		{
 		case EModeNotifier:
 			{
 			RNotifier notifier;
-			User::LeaveIfError(notifier.Connect());
-			CleanupClosePushL(notifier);
-
-			TInt buttonValue;
-			TRequestStatus status;
-			notifier.Notify(*iTitle, *iBody, *iButton1, *iButton2, buttonValue, status);
-			User::WaitForRequest(status);
-			Complete(buttonValue);
-
-			CleanupStack::PopAndDestroy(&notifier);
+			LeaveIfErr(iNotifier.Connect(), _L("Couldn't connect to RNotifier"));
+			iNotifier.Notify(*iTitle, *iBody, *iButton1, *iButton2, iReturnValue, iStatus);
+			SetActive();
 			break;
 			}
 		case EModeConsole:
@@ -4894,10 +4862,12 @@
 	_LIT(KOptTitle, "title");
 	_LIT(KOptButton1, "first-button");
 	_LIT(KOptButton2, "second-button");
+	_LIT(KOptMode, "mode");
 
 	aOptions.AppendStringL(iTitle, KOptTitle);
 	aOptions.AppendStringL(iButton1, KOptButton1);
 	aOptions.AppendStringL(iButton2, KOptButton2);
+	aOptions.AppendEnumL((TInt&)iMode, KOptMode);
 	}
 
 void CCmdDialog::ArgumentsL(RCommandArgumentList& aArguments)
@@ -4906,6 +4876,33 @@
 	aArguments.AppendStringL(iBody, KArgBody);
 	}
 
+void CCmdDialog::DoCancel()
+	{
+	iNotifier.NotifyCancel();
+	}
+
+void CCmdDialog::RunL()
+	{
+	// text notifier gets the buttons the wrong way round, so check if it's running and if so swap the return value around
+	_LIT(KTextWindowServerName, "EWSRV.EXE[100000bf]0001"); // This is the same on winscw and target. The gui windowserver has a different UID
+	RProcess ewsrv;
+	TInt err = ewsrv.Open(KTextWindowServerName);
+	if (err == KErrNone)
+		{
+		if (iReturnValue) iReturnValue = 0;
+		else iReturnValue = 1;
+		ewsrv.Close();
+		}
+
+	Complete(iReturnValue);
+	}
+
+void CCmdDialog::CtrlCPressed()
+	{
+	//Cancel();
+	//Complete(KErrNone);
+	Printf(_L("Sorry, clients of RNotifier cannot safely be killed, and RNotifier::NotifyCancel() doesn't work. If you really want to risk it hit CTRL-Z and run \"kill -Tm *dialog*\". Otherwise you must dismiss the dialog on the device.\r\n"));
+	}
 
 //
 // CCmdJit.
--- a/core/src/commands.h	Tue Sep 14 09:49:39 2010 +0100
+++ b/core/src/commands.h	Wed Sep 15 18:07:34 2010 +0100
@@ -962,32 +962,40 @@
 	TFileName2 iFileName;
 	};
 
-class CCmdDialog : public CCommandBase
+class CCmdDialog : public CCommandBase, public MCommandExtensionsV2
 	{
 public:
 	static CCommandBase* NewLC();
 	~CCmdDialog();
 private:
+	CCmdDialog();
+	void ClearLineL(RIoConsoleWriteHandle& aWriteHandle);
+private: // From CCommandBase.
+	virtual const TDesC& Name() const;
+	virtual void DoRunL();
+	virtual void OptionsL(RCommandOptionList& aOptions);
+	virtual void ArgumentsL(RCommandArgumentList& aArguments);
+private: // From CActive
+	void RunL();
+	void DoCancel();
+private: // From MCommandExtensionsV2
+	void CtrlCPressed();
+
+private:
+	HBufC* iTitle;
+	HBufC* iBody;
+	HBufC* iButton1;
+	HBufC* iButton2;
 	enum TMode
 		{
 		EModeNotifier,
 		EModeConsole,
 		EModeNull
 		};
-private:
-	CCmdDialog();
-	TMode ModeL() const;
-	void ClearLineL(RIoConsoleWriteHandle& aWriteHandle);
-private: // From CCommandBase.
-	virtual const TDesC& Name() const;
-	virtual void DoRunL();
-	virtual void OptionsL(RCommandOptionList& aOptions);
-	virtual void ArgumentsL(RCommandArgumentList& aArguments);
-private:
-	HBufC* iTitle;
-	HBufC* iBody;
-	HBufC* iButton1;
-	HBufC* iButton2;
+	TMode iMode;
+
+	RNotifier iNotifier;
+	TInt iReturnValue;
 	};
 
 #ifdef __WINS__
--- a/documentation/change_history.pod	Tue Sep 14 09:49:39 2010 +0100
+++ b/documentation/change_history.pod	Wed Sep 15 18:07:34 2010 +0100
@@ -48,7 +48,15 @@
 
 =item *
 
-Fixed crash in L<start's|commands::start> C<--timeout> option.
+Fixed crash in L<start's|commands::start> C<--timeout> option and in L<chunkinfo|commands::chunkinfo> when specifying a chunk address.
+
+=item *
+
+The L<dialog|commands::dialog> command no longer misreports the button that was pressed when running under the text windowserver.
+
+=item *
+
+Changed built-in commands maximum heap size from 256KB to 1MB. This is because on a current S60 device 256KB is just too small for commands like chunkinfo to display all the chunks on the system. Also have seen problems listing large directories and deleting large numbers of files, that this change should help with too.
 
 =back
 
--- a/libraries/ltkutils/inc/heaputils.h	Tue Sep 14 09:49:39 2010 +0100
+++ b/libraries/ltkutils/inc/heaputils.h	Wed Sep 15 18:07:34 2010 +0100
@@ -180,7 +180,7 @@
 
 #ifdef __KERNEL_MODE__
 
-class RUserAllocatorHelper : public RAllocatorHelper
+HUCLASS(RUserAllocatorHelper) : public RAllocatorHelper
     {
 public:
 	RUserAllocatorHelper();
@@ -197,7 +197,7 @@
 	DThread* iThread;
 	};
 
-class RKernelCopyAllocatorHelper : public RAllocatorHelper
+HUCLASS(RKernelCopyAllocatorHelper) : public RAllocatorHelper
 	{
 public:
 	RKernelCopyAllocatorHelper();
@@ -217,7 +217,7 @@
 
 #else
 
-class RProxyAllocatorHelper : public RAllocatorHelper
+HUCLASS(RProxyAllocatorHelper) : public RAllocatorHelper
 	{
 public:
 	HUIMPORT_C RProxyAllocatorHelper();
--- a/libraries/ltkutils/src/heaphackery.cpp	Tue Sep 14 09:49:39 2010 +0100
+++ b/libraries/ltkutils/src/heaphackery.cpp	Wed Sep 15 18:07:34 2010 +0100
@@ -433,7 +433,7 @@
 	{
 #ifdef __KERNEL_MODE__
 	// Must be in CS
-	// Assumes that this only ever gets called for the kernel heap. Otherwise goes through RKernelSideAllocatorHelper::OpenUserHeap.
+	// Assumes that this only ever gets called for the kernel heap. Otherwise goes through RUserAllocatorHelper::OpenUserHeap.
 	TInt udeb = EFalse; // We can't figure this out until after we've got the heap
 	TBool isTheKernelHeap = ETrue;
 #else
@@ -443,13 +443,19 @@
 	TBool isTheKernelHeap = EFalse;
 #endif
 
+	if (iAllocatorAddress == 0)
+		{
+		// Subclasses with more knowledge about the layout of the allocator within the chunk may have already set the iAllocatorAddress (eg kernel heap's allocator doesn't start at the chunk base)
+		iAllocatorAddress = aChunkBase;
+		}
+
 	TInt err = IdentifyAllocatorType(udeb, isTheKernelHeap);
 	if (err == KErrNone && iAllocatorType == EAllocator)
 		{
 		// We've no reason to assume it's an allocator because we don't know the iAllocatorAddress actually is an RAllocator*
 		err = KErrNotFound;
 		}
-	if (err && aChunkMaxSize > 0)
+	if (err && aChunkMaxSize > 0 && iAllocatorAddress == aChunkBase)
 		{
 		TInt oldErr = err;
 		TAllocatorType oldType = iAllocatorType;
@@ -1687,7 +1693,7 @@
 DChunk* LtkUtils::RUserAllocatorHelper::OpenUnderlyingChunk()
 	{
 	if (iAllocatorType != EUrelOldRHeap && iAllocatorType != EUdebOldRHeap && iAllocatorType != EUrelHybridHeap && iAllocatorType != EUdebHybridHeap) return NULL;
-	// Note RKernelSideAllocatorHelper doesn't use or access RAllocatorHelper::iChunk, because we figure out the chunk handle in a different way.
+	// Note RUserAllocatorHelper doesn't use or access RAllocatorHelper::iChunk, because we figure out the chunk handle in a different way.
 	// It is for this reason that iChunk is private, to remove temptation
 	
 	// Enter and leave in CS and with no locks held. On exit the returned DChunk has been Open()ed.