"thomas" <[EMAIL PROTECTED]> wrote
> I have recently heard about this non documented function in the forum.
> Can someone explain what it can be used for and how ?
> I'm currently working on a big project with several developpers and I'd
> like to perform some verifications on our code to fix some unexpected
> behaviour in the app.
> Are there any other non documented functions of this type ?
>
This function is in MemoryMgr.h and there looks like a lot
more functions than are covered by the documentation. I
only needed lock count so I didn't look any further.
Since I've had someone email me asking how to use this to
debug locking problems I've included the simple debug code
I use below. I tried cutting the core routines out but I've
always found code segments less than useful so I've decided
to post the whole debug routine here because I'd like to see
it cleaned up a bit and some critical comment would be a good
start. Hopefully the end result can be added to the resource
base for the group.
The basic technique is the fairly standard practice of redefining
the function you're analysing to point to a debug version that
outputs some information and then calls the normal routine.
This simple fact is buried in a whole stack of code that keeps
counts and outputs the debug information.
Feel free to criticise this if you think it can be done better. I
think one of the things that would be useful as a resource to
the Palm community is a debug framework (of course this
might exist already - I've never looked for one because it's
generally faster just to knock up a debug framework for the
problem at hand).
One criticism would be that it's not particularly efficient. I'm
assuming that you don't have a lot of debug calls in your code.
Mind you, the overhead of the actual logging is probably going
to slow you down more than the efficiency of the string handling
and I've never found the speed to be a problem compared with
the speed of single-stepping with the debugger.
Anther thing that would be useful is a version with Mac debug
support #defined in.
You're unlikely to be able to just drop this in your code and
run. There are connections you're going to have to establish and
things that I've hard-coded that you'll have to change. If anyone
wants to post a more generic version of this I'll happily use it.
(debug.h)
/*----- Debug.h
Provides debug support. Coded in Win32 environment, but I've
tried to do things in a way that would allow the Mac debug routines
to fit the same framework, should someone need to port the code.
Created 21 Jan 00 - Chris Tutty (CJT)
Modified CJT August 2000,
- Rearrange code and add a few new flags.
*/
#ifndef DEBUG_H
#define DEBUG_H
//RefID:10461
//#include <SysAll.h>
#include <palmos.h>
//RefID:10461 Ends
#include "utils.h" // to ensure that gTempStr is available
? You'll need to replace this with your own code that
? either declares gTempStr or remove the need for it.
extern char mstrBuffer[128];
/* debug flags
These turn different behaviour on and off. There are also
module-specific flags at the start of many .c files.
*/
#define DEBUG_ON false
#define DEBUGFLAG_LOCK false
#define DEBUGFLAG_FUNCTIONNAMES false
#define DEBUGFLAG_CHUNKS false
void DebugInitialise(void);
void DebugTerminate(void);
void DebugMsg(const char * msg);
void StartDebugOutput(void);
void StopDebugOutput(void);
// Special-purpose routines
void * DebugLock(MemHandle h, const char * msg);
void DebugUnlock(MemHandle h, const char * msg);
#if DEBUGFLAG_LOCK
#if DEBUGFLAG_FUNCTIONNAMES
#define MemHandleUnlock(x) DebugUnlock((x), cFunctionName)
#define MemHandleLock(x) DebugLock((x), cFunctionName)
#else
#define MemHandleUnlock(x) DebugUnlock((x), NULL)
#define MemHandleLock(x) DebugLock((x), NULL)
#endif // trace
#endif
#define TRACEMSG(text) \
{ StrCopy(mstrBuffer, "\n"); \
StrNCat(mstrBuffer, cFunctionName, sizeof(mstrBuffer)); \
StrNCat(mstrBuffer, ": ", sizeof(mstrBuffer)); \
StrNCat(mstrBuffer, text, sizeof(mstrBuffer)); \
mstrBuffer[127] = '\0'; \
DebugMsg(mstrBuffer); \
}
#if DEBUGFLAG_CHUNKS
// Copy a chunk data dump to gTempStr for use by the calling
// routine. I've never bothered extending this with other chunk info.
// pChunk is a hangover from the previous implementation but
// I've left it in in case a future implementation wants to use it. Since
// this routine is sometimes called for unlocked chunks you should
// always assume that pChunk might be NULL.
#define DUMPCHUNKDATA(hChunk, pChunk) \
{ \
StrNCopy(gTempStr, " H: ", sizeof(gTempStr)); \
StrIToH(&gTempStr[StrLen(gTempStr)], (UInt32) hChunk); \
StrNCat(gTempStr, " Size: ", sizeof(gTempStr)); \
if (hChunk) \
{ StrIToA(&gTempStr[StrLen(gTempStr)], \
MemHandleSize(hChunk)); \
StrNCat(gTempStr, ", Lock: ", sizeof(gTempStr)); \
StrIToA(&gTempStr[StrLen(gTempStr)], MemHandleLockCount(hChunk)); \
} else \
{ StrNCat(gTempStr, " unknown, Lock: unknown", sizeof(gTempStr)); \
} \
}
#else
// Clear the buffer so that it accurately displays nothing
#define DUMPCHUNKDATA(hChunk,pChunk) {gTempStr[0] = '\0';}
#endif //DEBUGFLAG_CHUNKS
#endif // DEBUG_H
(debug.h Ends)
The DEBUGFLAG_FUNCTIONNAMES flag is used to
define a string constant at the start of every function that names
the function at run time. This makes it easier for the debug
routines to dump the function that something happened in.
The debug routines use a gTempStr char buffer that I define
globally for general string use. This is a questionable practice
that I've done only because I've found it reduces the need
for stack-based temporary char buffers.
I've used the HostControl functions that allow logging to file
because it allows me to save and compare debug dumps.
I've noticed that a lot of people just use the normal debug
output calls. The functionality of this code shouldn't depend
on what method you're using - just alter DebugInit,
DebugTerminate and DebugMsg to suit.
(debug.c)
/*----- Debug.c
See debug.h for notes
Created 21 Jan 00 - Chris Tutty (CJT)
*/
//RefID:10461 - SDK3.5
//#include <SysAll.h>
//RefID:10461 Ends
#include <datetime.h>
#include <stringmgr.h>
#include <HostControl.h>
#include "debug.h"
/* Runtime debug flag
This lets you suppress debug output depending on what part of
the code is executing. Use StartDebugOuput and StopDebugOuput.
*/
#ifdef DEBUG_ON
Boolean mDebugActive;
#endif
static const char * cFunctionName = "Debug.c"; // default value
static Int32 SequenceCounter = 0; // Provides a sequence indicator.
static Int32 LockCounter = 0; // Total lock/unlock balance
HostFILE * hfDebug = NULL;
char mstrBuffer[128];
void TimeStamp(void);
/***********************************************************************
*
* FUNCTION: DebugInitialise
*
* DESCRIPTION: Carry out all required initialisation for the debug
routines.
*
***********************************************************************/
void DebugInitialise(void)
{
#if DEBUG_ON
? You'll probably want to change this.
hfDebug = HostFOpen("c:\\temp\\Debug.log", "w");
if (!hfDebug)
return;
HostFPutS("\n--------------------", hfDebug);
HostFPutS("\nDebug session begins\n", hfDebug);
TimeStamp();
HostFPutS(mstrBuffer, hfDebug);
HostFPutS("\n--------------------\n", hfDebug);
HostFFlush(hfDebug);
SequenceCounter = 0; // CJT August 2000, RefID:10383
LockCounter = 0; // CJT August 2000, RefID:10383
StartDebugOutput();
#endif
}
/***********************************************************************
*
* FUNCTION: DebugTerminate
*
* DESCRIPTION: Close and clean up the debug routines.
*
***********************************************************************/
void DebugTerminate(void)
{
if (hfDebug)
{
HostFPutS("\n--------------------", hfDebug);
HostFPutS("\nDebug session ends\n", hfDebug);
TimeStamp();
HostFPutS(mstrBuffer, hfDebug);
HostFPutS("\n--------------------\n", hfDebug);
HostFClose(hfDebug);
hfDebug = NULL;
}
}
/* debug output start and stop
*/
void StartDebugOutput(void)
{
mDebugActive = true;
}
void StopDebugOutput(void)
{
mDebugActive = false;
}
/***********************************************************************
*
* FUNCTION: DebugMsg
*
* DESCRIPTION: Write a text string to the debug log.
*
***********************************************************************/
void DebugMsg(const char * msg)
{
if (hfDebug && msg && mDebugActive)
{
HostFPutS(msg, hfDebug);
HostFFlush(hfDebug);
}
}
/***********************************************************************
*
* FUNCTION: TimeStamp
*
* DESCRIPTION: Copy a date and time string to mstrBuffer
*
***********************************************************************/
void TimeStamp(void)
{
DateTimeType dateTime;
char tBuff[32];
TimSecondsToDateTime (TimGetSeconds (), &dateTime);
DateToAscii(dateTime.month, dateTime.day, dateTime.year, dfDMYLong,
mstrBuffer);
TimeToAscii(dateTime.hour, dateTime.minute, tfColon24h, tBuff);
StrCat(mstrBuffer, " ");
StrCat(mstrBuffer, tBuff);
}
/* Adds a with optional message to the debug log
The dumpcounter provides a sequence counter for use if the output
is loaded into a database for sorting or analysis.
*/
#undef MemHandleLock
void * DebugLock(
MemHandle h // the handle being locked
, const char * msg // a text message to display (can be NULL)
)
{
// Modified CJT August 2000, RefID:10383
// - rearrange h and sequencecounter, add lockcounter
// - make msg optional
//
void * result = NULL;
if (hfDebug)
{
DebugMsg("\nLock, ");
StrPrintF(mstrBuffer, "%lx, %ld, %ld", h, ++SequenceCounter,
++LockCounter);
DebugMsg(mstrBuffer);
}
result = MemHandleLock(h);
if (hfDebug)
{
gTempStr[0] = '\0';
#if DEBUGFLAG_CHUNKS
DUMPCHUNKDATA(h, result);
#endif
if (msg)
StrPrintF(mstrBuffer, ", %lx, %s, %s", result, msg, gTempStr);
else
StrPrintF(mstrBuffer, ", %lx, , %s", result, gTempStr);
DebugMsg(mstrBuffer);
}
return result;
}
#undef MemHandleUnlock
void DebugUnlock(MemHandle h, const char * msg)
{
// Modified CJT August 2000, RefID:10383
// - rearrange h and sequencecounter, add lockcounter
//
if (hfDebug)
{
gTempStr[0] = '\0';
#if DEBUGFLAG_CHUNKS
DUMPCHUNKDATA(h, NULL);
#endif
DebugMsg("\nUnlock, ");
if (msg)
StrPrintF(mstrBuffer, "%lx, %ld, %ld, 0, %s, %s", h,
++SequenceCounter, --LockCounter, msg, gTempStr);
else
StrPrintF(mstrBuffer, "%lx, %ld, %ld, 0, , %s", h,
++SequenceCounter, --LockCounter, gTempStr);
DebugMsg(mstrBuffer);
}
MemHandleUnlock(h);
}
(debug.c ends)
Source code example:
(blah.c)
#include "debug.h"
#if DEBUG_ON
static const char * cFunctionName = "Weights.c";
#define DEBUGFLAG_TRACE_WEIGHTS true
#endif
static void OpenRow(
UInt16 row // the table-relative row for the virtual row
// to be opened
)
{
#if DEBUGFLAG_FUNCTIONNAMES
const char * cFunctionName = "OpenRow";
#endif
#if DEBUGFLAG_TRACE_WEIGHTS
StrIToA(gTempStr, row);
TRACEMSG(gTempStr);
#endif
...
MemHandleUnlock(mEdit.Handle);
...
}
(blah.c ends)
That's it. If it doesn't compile and you can't work out why
let me know. If you feel that this whole function is poor style
feel free to shout - it was written in a hurry to track down a
nasty lock count problem and does the job. However, please
note that complaints about style or content will only be accepted
if accompanied by a rewrite indicating the correct approach. We
will then all happily use the improved version.
Chris Tutty
--
For information on using the Palm Developer Forums, or to unsubscribe, please see
http://www.palmos.com/dev/tech/support/forums/