Files
m241Neelima/vxworks-6.9/target/src/event/evtLogLib.c
T
2026-07-30 11:19:44 +05:30

846 lines
25 KiB
C

/* evtLogLib.c - event logging library */
/*
* Copyright (c) 1994-2008, 2010-2012 Wind River Systems, Inc.
*
* The right to copy, distribute, modify or otherwise make use
* of this software may be licensed only pursuant to the terms
* of an applicable Wind River license agreement.
*/
/*
modification history
--------------------
04k,04jul12,wzc WIND00361531 - Remove building warnings.
04j,29aug11,wzc Updated to support dynamic power management.(WIND00295115)
04i,27jul11,wzc PPM for SV (WIND00214625)
04h,29jun10,wzc Line aligned.
04g,18jun10,wzc Check the string length and avoid too long.(WIND00206550)
04f,16jun10,vhe Coding conventions
04e,21jan10,wzc Adapt SV to vxWorks 64bit.
04d,10sep08,tcr change references to _WRS_VX_SMP
04c,03sep08,jpb Renamed VSB header file
04b,16jul08,tcr BLOB macros, fix warnings
04a,09may08,tcr update funcptrs, remove redundant code
03z,08apr08,tcr add log routines for perfMon implementation
03y,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
for kernel configurations options set in vsb.
03x,10jul07,tcr more SMP updates
03w,19dec06,tcr changes for SMP
fix defect WIND00083624
03w,07feb07,lei removed "IMPORT Q_HEAD readyQHead", declared in kernelLibP.h;
changed "" to <> for header files.
03v,20sep06,tcr fix non-aligned write in wvEvent() (WIND00066146)
remove i960 code
03u,22sep04,tcr don't use MEM_ROUND_UP
03t,21apr04,tcr add parameter to logging function
03s,05mar04,tcr move evtEdrErrorInject() prototype to header
03r,04mar04,tcr fix event space allocation for evtEdrErrorInject()
03q,11feb04,tcr fix build error in evtLogSyscall
03p,16dec03,syy Added evtLogOBinary()
03o,04dec03,aim added evtEdrErrorInject
03r,03nov03,tcr add WindView syscall logging rtn
add parameter to evtLogString()
03q,16sep03,tcr allow evtLogString to take variable num of params
03p,10sep03,tcr update evtLogString to take another parameter
03o,26aug03,tcr changes for Base6
03n,08may03,pes PAL conditional compilation cleanup. Phase 2.
03m,14aug98,cth removed MEM_ROUND_UP from evtLogPoint
03m,10aug98,pr added i960 function pointers to evtLogFuncBind
03l,30jul98,cjtc removed logMsg EVTLOG_RESERVE_BUFF_SPACE macros which resulted
in stack corruption of the calling task (SPR 21993)
03k,13may98,pr modified logMsg content
03j,12may98,pr added logMsg and stop windview if buffer is full
03i,17apr98,cth removed function evtHeaderLog
03h,15apr98,cth added binding of _func_evtLogReserveTaskName
03g,10apr98,cjtc architecture port for i960 processors.
fixed bug in evtLogT0_noInt in which timestamp was written to
the event buffer before it was read.
Removed unused local variable "level" from evtLogT0_noInt
03f,09apr98,pr added evtLogT0_noInt declaration
03e,08apr98,pr modified evtLogO to be of general use. Added evtLogT0_noInt
03d,06apr98,nps 68k family nows shares portable code.
03c,18mar98,nps fixed check for 'thin' mode when creating header.
03b,17feb98,dvs added events for memory instrumentation in evtLogO and
pr fixed evtLogO buffer size.
03a,03feb98,cth changed evtBufferId from static to global
02z,27jan98,cth added evtObjLogFuncBind, evtLogFuncBind, evtBufferBind and
evtHeaderLog, updated copyright
02y,25jan98,pr changed size in evtLogT1_noTS
02x,22jan98,pr fixed evtsched
02w,18dec97,cth changed include buffer.h to wvBufferP.h, changed tmpBufId to
evtBufferId
02v,16nov97,cth removed evtBuf and rBuff references
changed buffer writes to use generic WV2.0 buffers
02u,22oct97,pr fixed EVTLOG_RESERVE_BUFF_SPACE_L for evtLogT1_noTS
02t,21oct97,nps use modified rBuff API
02s,18aug97,nps fixed bug in evtLogM1
02r,20jul97,nps added ring buffer support
02q,24jun97,pr commented the evtLogTIsOn for evtLogPoint
02p,08jul96,pr added evtLogT1_noTS for PPC
02o,06dec94,rdc fixed bogus intlocks that should have been unlocks.
02n,08nov94,rdc added 960 kernel instrumentation routines.
02m,02nov94,rdc added argument to evtLogString to support lockCount param
in EVENT_TASKNAME.
02l,02nov94,rdc unlocked interrupts before returning because of errors.
02k,27may94,smb now use alignment macros to store data in buffer.
02j,23may94,pme removed taskIdLogin for EVENT_WIND_EXIT_NODISPATCH
made evtsched equivalent to the 68k assembly version
01i,05may94,smb sparc porting
01h,16mar94,smb removed EVENT_WIND_EXIT_IDLENOT
level 1 optimisations.
01g,22feb94,smb changed typedef EVENT_TYPE to event_t (SPR #3064)
01f,24jan94,smb fixed return values for eventPoint()
01e,19jan94,smb event buffer fix SPR #2904
01d,14jan94,c_s evtLogOInt now handles EVENT_SIGWRAPPER correctly (SPR #2883).
01c,04jan94,c_s evtLogPoint now validates the user event ID correctly.
SPR #2724.
01b,30dec93,c_s evtLogPoint now uses memcpy (), rather than strncpy (), to
transfer the user's buffer of data for user-defined events
to the logging area. SPR #2799.
01a,10dec93,smb created
*/
/*
DESCRIPTION
This library provides routines which log events to the buffer for different
types of events generated by the instrumented code.
INCLUDE FILES:
SEE ALSO:
\NOMANUAL
*/
#include <vxWorks.h>
#include <vsbConfig.h>
#include <logLib.h>
#include <wvLib.h>
#include <string.h>
#include <taskLib.h>
#include <sysLib.h>
#include <private/taskLibP.h>
#include <private/eventP.h>
#include <private/kernelLibP.h>
#include <private/workQLibP.h>
#include <private/wvBufferP.h>
#include <private/evtLogLibP.h>
#include <private/kernelLibP.h>
#include <private/syscallLibP.h>
#include <private/svFuncBindP.h>
#include <private/wvBufferP.h> /* BUFFER_ID */
#ifdef _WRS_CONFIG_SMP
#include <spinLockLib.h>
#endif /* _WRS_CONFIG_SMP */
/* optimized version no longer used for 680X0 */
#define evtLogLib_PORTABLE
/* defines */
/* 29 bits for payload length, 3 bits for padding length */
#define MAX_PAYLOAD_SIZE (0x1fffffff)
#define MAX_WV_TASKS 500 /* should be the same MAX_DSP_TASKS */
#define EVTLOG_RESERVE_BUFF_SPACE(EVENT_SIZE) \
eventBase = (event_t *) evtBufferId->writeRtn (evtBufferId,NULL,EVENT_SIZE); \
\
if (!eventBase) \
{ \
wvEvtLogStop(); \
CRIT_REGION_EXIT(); \
return; \
}
#define EVTLOG_RESERVE_BUFF_SPACE_STAT(EVENT_SIZE) \
eventBase = (event_t *) evtBufferId->writeRtn (evtBufferId,NULL,EVENT_SIZE); \
\
if (!eventBase) \
{ \
wvEvtLogStop(); \
CRIT_REGION_EXIT(); \
return (ERROR); \
}
#define EVTLOG_RESERVE_BUFF_SPACE_L(EVENT_SIZE) \
eventBase = (event_t *) evtBufferId->writeRtn (evtBufferId,NULL,EVENT_SIZE); \
\
if (!eventBase) \
{ \
wvEvtLogStop(); \
CRIT_REGION_EXIT(); \
return; \
}
#define CRIT_REGION_ENTER() evtBufferId->lockRtn(evtBufferId)
#define CRIT_REGION_EXIT() evtBufferId->unlockRtn(evtBufferId)
/*
* EVENT_CPU_ID is only required for SMP builds
* This macro inserts an event indicating the current CPU, for SMP
* systems. On UP systems, it does nothing.
*/
#ifdef _WRS_CONFIG_SMP
#define CPU_EVENT_EMIT(cpuId) \
do { \
EVT_STORE_UINT16(eventBase,EVENT_CPU_ID); \
EVT_STORE_UINT16(eventBase,cpuId); \
} while (0)
#define SIZEOF_CPU_ID_EVENT (sizeof (event_t) + sizeof (UINT16))
#else /* _WRS_CONFIG_SMP */
#define CPU_EVENT_EMIT(cpuId)
#define SIZEOF_CPU_ID_EVENT 0
#endif /* _WRS_CONFIG_SMP */
#ifdef _WRS_CONFIG_SMP
/*
* Macro which inserts a CPU_ID event if this event came from a
* different CPU to the last event recorded into the buffer
*/
#define CONDITIONAL_CPU_EMIT(allocator,eventSize) \
{ \
int cpuId; \
cpuId = vxCpuIndexGet (); \
if (cpuId != currentCpuId) \
{ \
allocator(eventSize + SIZEOF_CPU_ID_EVENT); \
CPU_EVENT_EMIT((UINT16)cpuId); \
currentCpuId = cpuId; \
} \
else \
allocator(eventSize); \
}
#else /* _WRS_CONFIG_SMP */
#define CONDITIONAL_CPU_EMIT(allocator,eventSize) allocator(eventSize)
#endif /* _WRS_CONFIG_SMP */
/* local */
BUFFER_ID evtBufferId; /* event buffer identifier */
/* flag indicating library is initialized */
LOCAL int libInitialized = 0;
#ifdef _WRS_CONFIG_SMP
/* track which CPU is emitting events. Only used while spinlock held */
LOCAL int currentCpuId = -1;
#endif /* _WRS_CONFIG_SMP */
/* forward declarations */
void evtLogOBinary (event_t action, int nParam, int arg1, int arg2, int arg3,
int arg4, int arg5, int arg6, int payloadSize,
const char *payload);
void evtLogString (event_t action, int nArgs, int arg1, int arg2, int arg3,
int arg4, int arg5, int arg6, int arg7, const char *string);
void evtObjNameBuffAdd (event_t action, int nArgs, int arg1, int arg2, int arg3,
int arg4, int arg5, const char *string);
void evtLogSyscall (unsigned int nParam, const SYSCALL_ENTRY_STATE * pState);
#if defined _WRS_EVTLOGT1_NOTS
void evtLogT1_noTS (event_t action, int param);
#endif /* _WRS_EVTLOGT1_NOTS */
/*******************************************************************************
*
* evtLogLibInit - initialize evtLogLib
*
* This function initializes the spinlock for the logging routines
*
* RETURNS: OK, or ERROR
* \NOMANUAL
*/
STATUS evtLogLibInit (void)
{
if (!libInitialized)
{
libInitialized = 1;
return (OK);
}
else
return (ERROR);
}
/*******************************************************************************
*
* evtObjLogFuncBind - bind object-level logging functions
*
* This routine binds the function pointers used to log system-object events
* to the appropriate functions in this library.
*
* RETURNS: N/A
* \NOMANUAL
*/
void evtObjLogFuncBind (void)
{
}
/*******************************************************************************
*
* evtLogFuncBind - bind general event-logging functions
*
* This function binds instrumentation function pointers to logging functions
* in this file. Event logging routines associated with class-1 (object-
* class) logging must be bound earlier, with a call to evtObjLogFuncBind.
*
* RETURNS: N/A
* \NOMANUAL
*/
void evtLogFuncBind (void)
{
_func_evtLogPayload = &evtLogPayload;
_func_evtLogPayloadString = &evtLogPayloadString;
_func_evtLogReserveTaskName = &wvObjNameCurrentBuffAdd;
_func_evtLogSyscall = &evtLogSyscall;
_func_edrEvt = &evtEdrErrorInject;
}
/*******************************************************************************
*
* evtNewBufferCallback - callback to run when new buffer started in log
*
* This function writes initial data into the buffer when a new buffer is started
* by the buffer library. This is to save context data so that in wrapping
* mode, even when buffers are dropped, it is possible to interpret events from
* the beginning of the log correctly.
*
* RETURNS: OK, or ERROR
* \NOMANUAL
*/
LOCAL STATUS evtNewBufferCallback (BUFFER_ID buff)
{
#ifdef _WRS_CONFIG_SMP
event_t * eventBase;
eventBase = (event_t *) evtBufferId->writeRtn (buff,NULL,4);
if (eventBase == NULL)
return (ERROR);
EVT_STORE_UINT16(eventBase,EVENT_CPU_ID);
EVT_STORE_UINT16(eventBase,(UINT16)vxCpuIndexGet ());
#endif /* _WRS_CONFIG_SMP */
return OK;
}
/*******************************************************************************
*
* evtBufferBind - bind logging routines to a specific event buffer
*
* This routine associates a specific event buffer with the event-logging
* routines.
*
* RETURNS: N/A
* \NOMANUAL
*/
void evtBufferBind
(
BUFFER_ID bufId /* bind logging functions to this buffer */
)
{
/* lock buffer until connection completed */
bufId->lockRtn (bufId);
evtBufferId = bufId;
#ifdef _WRS_CONFIG_SMP
bufId->newBuffHookAdd (evtBufferId, evtNewBufferCallback);
#endif /* _WRS_CONFIG_SMP */
bufId->unlockRtn (bufId);
}
/*******************************************************************************
*
* evtLogSyscall - record syscall events with up to 8 params
*
* This event logging routine stores
* event id (short )
* timestamp (int )
* param[0..7] (int ) - no. of param logged depends on the event id.
*
* This routine lock insterrupts
*
* It takes a syscall state struct, and the number of parameters. This avoids
* a WindView dependancy on the syscall component.
*
* SEE ALSO:
* \NOMANUAL
*/
void evtLogSyscall
(
unsigned int nParam, /* number of params to record */
const SYSCALL_ENTRY_STATE * pState /* parameter array, syscall num */
)
{
event_t * eventBase;
int * intBase;
long int * longBase;
int timestamp;
unsigned int n;
/*
* This max number of params may be #defined somewhere, but in syscallLibP.h
* it's fixed as 8. If the requested number is wrong, make it safe.
*/
if (nParam > 8)
nParam = 0;
CRIT_REGION_ENTER();
/* reserve space for eventid, timestamp, syscallid, and some parameters */
CONDITIONAL_CPU_EMIT(EVTLOG_RESERVE_BUFF_SPACE,
sizeof (UINT16) + sizeof (UINT32) +
sizeof (UINT16) + (nParam * sizeof (long int)));
/* create event id indexed of the first */
EVT_STORE_UINT16 (eventBase, (event_t)(EVENT_SYSCALL_0 + nParam));
intBase = (int *) eventBase;
timestamp = (* _func_tmrStamp) ();
EVT_STORE (intBase, timestamp);
eventBase = (event_t *) intBase;
EVT_STORE_UINT16 (eventBase, (unsigned short)pState -> scn);
longBase = (long int *) eventBase;
for (n = 0; n < nParam; n++)
{
EVT_STORE (longBase, (long int)(pState->args [n]));
}
CRIT_REGION_EXIT();
}
/*******************************************************************************
*
* evtLogPoint - logs a user defined event or eventpoint via event () or e ().
*
* This event logging routine stores
* event id (short )
* timestamp (int)
* address (int)
* buffer size (int) - if size is ZERO the buffer does not exist.
* buffer (char)
*
* RETURNS: OK, or ERROR if unable to log event point
* SEE ALSO:
* \NOMANUAL
*
* INTERNAL
* When storing payload data, we need to honour the alignment
* constraints. Currently, all data must be half-word aligned.
* The host needs to know how much padding is attached to a data item, and we
* use the top bits of the length item for this information. The
* remaining bits contain the length requested by the caller. The length
* stored is the requested length, plus any padding.
*/
STATUS evtLogPoint
(
event_t action, /* user event id (0 - 25535) */
void * addr, /* pc address */
size_t nbytes, /* buffer size */
char * buffer /* buffer */
)
{
event_t * eventBase;
event_t biasedAction;
int * intBase;
long int * longBase;
int timestamp;
size_t actualBytes;
size_t padding;
long iAddr;
biasedAction = (event_t)(action + MIN_USER_ID);
if (nbytes > MAX_PAYLOAD_SIZE)
return (ERROR);
/* payload must not result in non-aligned write of following event */
actualBytes = (nbytes + 1) & (~1);
padding = actualBytes - nbytes;
/* is event id within the range of user event ids? */
if (biasedAction < MIN_USER_ID || biasedAction > MAX_USER_ID)
return (ERROR);
CRIT_REGION_ENTER();
/* Always timestamp and two params. Sometimes a payload, too */
CONDITIONAL_CPU_EMIT(EVTLOG_RESERVE_BUFF_SPACE_STAT,
actualBytes + EVTLOG_TN_SIZE(2));
EVT_STORE_UINT16 (eventBase, biasedAction);
intBase = (int *) eventBase;
timestamp = (* _func_tmrStamp) ();
EVT_STORE (intBase, timestamp);
longBase = (long int *)intBase;
iAddr = (long)addr;
EVT_STORE (longBase, iAddr);
intBase = (int *)longBase;
EVT_STORE (intBase, (int)(nbytes + (padding << PADDING_SHIFT_COUNT)));
/* copy buffer contents into event buffer */
if ((nbytes != 0) && (buffer != NULL))
{
memcpy ((char *) intBase, buffer, nbytes);
}
CRIT_REGION_EXIT();
return (OK);
}
#if defined _WRS_EVTLOGT1_NOTS
/*******************************************************************************
*
* evtLogT1_noTS - log event id without getting timestamp
*
* This event logging routine stores
* event id (short )
* time (int )
*
* This routines is very similar to the evtLogT1. The main difference
* is that no timestamp is here. The parameter passed is actually the
* current timestamp for this event. This routine is called when an
* interrupt is entered. It is used for PPC architecture. PPC generates
* only one kind of interrupt. When the interrupt is entered, the timestamp
* for windview is obtained. No information about the type of interrupt is
* known at that point. Only when the sysIbcIntHandler routine is called,
* the interrupt vector handler is obtained and it is passed to this
* routine, together with the timestamp.
* When this routine is called, interrupts must be locked already.
*
* SEE ALSO:
* \NOMANUAL
*/
void evtLogT1_noTS
(
event_t action, /* event id */
int param /* timestamp */
)
{
event_t * eventBase;
CRIT_REGION_ENTER();
CONDITIONAL_CPU_EMIT(EVTLOG_RESERVE_BUFF_SPACE_L,
EVTLOG_TN_SIZE(0));
EVT_STORE_UINT16 (eventBase, action);
CRIT_REGION_EXIT();
}
#endif /* _WRS_EVTLOGT1_NOTS */
/*******************************************************************************
*
* evtEdrErrorInject - log edrErrorInject event to the log.
*
* This event logging routine stores:
* event id (short)
* timestamp (int)
* kind (int)
* len (fileName) (int)
* fileName (char)
* lineNumber (int)
* address (void *)
* len(textPayload)(int) - if size is ZERO the string does not exist.
* textPayload (char)
*
* SEE ALSO:
* \NOMANUAL
*/
void evtEdrErrorInject
(
event_t action, /* the event id */
int kind, /* error-record kind */
const char * fileName, /* fileName */
int lineNumber, /* lineNumber from fileName */
const void * address, /* faulting address */
const char * textPayload /* error-record summary */
)
{
event_t * eventBase;
int * intBase;
long int * longBase;
size_t len1;
size_t len2;
size_t evtSize;
int timestamp;
long iAddr;
if (fileName != NULL)
len1 = strlen (fileName);
else
len1 = 0;
/* ensure len + data will be half word aligned. */
if (len1 & 0x1)
len1++;
if (textPayload != NULL)
len2 = strlen (textPayload);
else
len2 = 0;
if (len2 & 0x1)
len2++;
evtSize = (sizeof (event_t) +
sizeof (int) + /* timestamp */
4 * (sizeof (int)) + /* kind, line, len1, len2 */
sizeof (address) +
len1 + len2);
CRIT_REGION_ENTER();
CONDITIONAL_CPU_EMIT(EVTLOG_RESERVE_BUFF_SPACE,evtSize);
EVT_STORE_UINT16 (eventBase, action);
intBase = (int *) eventBase;
timestamp = (* _func_tmrStamp) ();
EVT_STORE (intBase, timestamp);
EVT_STORE (intBase, kind);
EVT_STORE (intBase, (int)len1);
if (len1 != 0)
{
strncpy ((char *) intBase, fileName, len1);
intBase = (int *) ((char *) intBase + len1);
}
EVT_STORE (intBase, lineNumber);
longBase = (long int *)intBase;
iAddr = (long)address;
EVT_STORE (longBase, iAddr);
intBase = (int *)longBase;
EVT_STORE (intBase, (int)len2);
if (len2 != 0)
{
strncpy ((char *) intBase, textPayload, len2);
intBase = (int *) ((char *) intBase + len2);
}
CRIT_REGION_EXIT();
}
/*******************************************************************************
*
* evtLogPayload - logs an event payload from perfMon data collector
*
* This event logging routine stores
* event id (short )
* timestamp (int)
* data
*
* The length is assumed to be compatible with logging constraints
* (e.g. alignment)
*
* RETURNS: OK, or ERROR if unable to log event
* SEE ALSO:
* \NOMANUAL
*
*/
STATUS evtLogPayload
(
event_t action, /* event id */
int withTimestamp, /* non-zero if timestamp required */
const void * addr, /* pointer to source args */
size_t nbytes /* length of source args*/
)
{
event_t * eventBase;
int * intBase;
int timestamp;
if (nbytes > MAX_PAYLOAD_SIZE)
return (ERROR);
CRIT_REGION_ENTER();
if (withTimestamp)
{
CONDITIONAL_CPU_EMIT(EVTLOG_RESERVE_BUFF_SPACE_STAT,
sizeof (timestamp) + sizeof (action) + nbytes);
}
else
{
CONDITIONAL_CPU_EMIT(EVTLOG_RESERVE_BUFF_SPACE_STAT,
sizeof (action) + nbytes);
}
EVT_STORE_UINT16 (eventBase, action);
intBase = (int *) eventBase;
if (withTimestamp)
{
timestamp = (* _func_tmrStamp) ();
EVT_STORE (intBase, timestamp);
}
/* copy buffer contents into event buffer */
if ((nbytes != 0) && (addr != NULL))
{
memcpy ((char *) intBase, addr, nbytes);
}
CRIT_REGION_EXIT();
return (OK);
}
/*******************************************************************************
*
* evtLogPayloadString - logs an event payload from perfMon data collector
*
* This event logging routine stores
* event id (short )
* timestamp (int)
* data
*
* The length is assumed to be compatible with logging constraints
* (e.g. alignment)
*
* RETURNS: OK, or ERROR if unable to log event
* SEE ALSO:
* \NOMANUAL
*
*/
STATUS evtLogPayloadString
(
event_t action, /* event id */
int withTimestamp, /* non-zero if timestamp required */
const void * addr, /* pointer to source args */
size_t nbytes, /* length of source args (bytes) */
const void * stringAddr, /* address of optional string part */
size_t stringSize /* size of optional string part */
)
{
event_t * eventBase;
int * intBase;
int timestamp;
int eventSize;
int actualBytes;
int padding;
if ((nbytes > MAX_PAYLOAD_SIZE) || (stringSize > MAX_PAYLOAD_SIZE))
return (ERROR);
actualBytes = (int)((stringSize + 1) & (~1));
padding = (int)(actualBytes - stringSize);
eventSize = (int)(sizeof (action) +
nbytes + sizeof (actualBytes) + actualBytes);
CRIT_REGION_ENTER();
if (withTimestamp)
{
CONDITIONAL_CPU_EMIT(EVTLOG_RESERVE_BUFF_SPACE_STAT,
sizeof (timestamp) + eventSize);
}
else
{
CONDITIONAL_CPU_EMIT(EVTLOG_RESERVE_BUFF_SPACE_STAT,
eventSize);
}
EVT_STORE_UINT16 (eventBase, action);
intBase = (int *) eventBase;
if (withTimestamp)
{
timestamp = (* _func_tmrStamp) ();
EVT_STORE (intBase, timestamp);
}
/* copy args into event buffer */
if ((nbytes != 0) && (addr != NULL))
{
memcpy ((char *) intBase, addr, nbytes);
}
/* adjust intBase past args data just written */
intBase += nbytes / sizeof (*intBase);
/* BLOB length */
EVT_STORE (intBase, (int)(stringSize + (padding << PADDING_SHIFT_COUNT)));
/* BLOB data */
if ((stringSize != 0) && (stringAddr != NULL))
{
memcpy ((char *) intBase, stringAddr, stringSize);
}
CRIT_REGION_EXIT();
return (OK);
}