📄 object.cxx
字号:
/*
* object.cxx
*
* Global object support.
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Revision: 19008 $
* $Author: rjongbloed $
* $Date: 2007-11-29 09:17:41 +0000 (Thu, 29 Nov 2007) $
*/
#ifdef __GNUC__
#pragma implementation "pfactory.h"
#endif // __GNUC__
#include <ptlib.h>
#include <ptlib/pfactory.h>
#include <ctype.h>
#ifdef _WIN32
#include <ptlib/msos/ptlib/debstrm.h>
#if defined(_MSC_VER) && !defined(_WIN32_WCE)
#include <crtdbg.h>
#endif
#elif defined(__NUCLEUS_PLUS__)
#include <ptlib/NucleusDebstrm.h>
#else
#include <signal.h>
#endif
#ifdef P_LINUX
extern PString PX_GetThreadName(pthread_t);
#endif
PFactoryBase::FactoryMap & PFactoryBase::GetFactories()
{
static FactoryMap factories;
return factories;
}
PMutex & PFactoryBase::GetFactoriesMutex()
{
static PMutex mutex;
return mutex;
}
PFactoryBase::FactoryMap::~FactoryMap()
{
FactoryMap::iterator entry;
for (entry = begin(); entry != end(); ++entry){
delete entry->second;
entry->second = NULL;
}
}
void PAssertFunc(const char * file,
int line,
const char * className,
PStandardAssertMessage msg)
{
if (msg == POutOfMemory) {
// Special case, do not use ostrstream in other PAssertFunc if have
// a memory out situation as that would probably also fail!
static const char fmt[] = "Out of memory at file %.100s, line %u, class %.30s";
char msgbuf[sizeof(fmt)+100+10+30];
sprintf(msgbuf, fmt, file, line, className);
PAssertFunc(msgbuf);
return;
}
static const char * const textmsg[PMaxStandardAssertMessage] = {
NULL,
"Out of memory",
"Null pointer reference",
"Invalid cast to non-descendant class",
"Invalid array index",
"Invalid array element",
"Stack empty",
"Unimplemented function",
"Invalid parameter",
"Operating System error",
"File not open",
"Unsupported feature",
"Invalid or closed operating system window"
};
const char * theMsg;
char msgbuf[20];
if (msg < PMaxStandardAssertMessage)
theMsg = textmsg[msg];
else {
sprintf(msgbuf, "Assertion %i", msg);
theMsg = msgbuf;
}
PAssertFunc(file, line, className, theMsg);
}
void PAssertFunc(const char * file, int line, const char * className, const char * msg)
{
#if defined(_WIN32)
DWORD err = GetLastError();
#else
int err = errno;
#endif
#if (__GNUC__ >= 3) && defined (__USE_STL__)
ostringstream str;
#else
ostrstream str;
#endif
str << "Assertion fail: ";
if (msg != NULL)
str << msg << ", ";
str << "file " << file << ", line " << line;
if (className != NULL)
str << ", class " << className;
if (err != 0)
str << ", Error=" << err;
str << ends;
#if (__GNUC__ >= 3) && defined (__USE_STL__)
string sstr = str.str();
const char * s = sstr.c_str();
#else
const char * s = str.str();
#endif
PAssertFunc(s);
}
PObject::Comparison PObject::CompareObjectMemoryDirect(const PObject&obj) const
{
int retval = memcmp(this, &obj, sizeof(PObject));
if (retval < 0)
return LessThan;
if (retval > 0)
return GreaterThan;
return EqualTo;
}
PObject * PObject::Clone() const
{
PAssertAlways(PUnimplementedFunction);
return NULL;
}
PObject::Comparison PObject::Compare(const PObject & obj) const
{
return (Comparison)CompareObjectMemoryDirect(obj);
}
void PObject::PrintOn(ostream & strm) const
{
strm << GetClass();
}
void PObject::ReadFrom(istream &)
{
}
PINDEX PObject::HashFunction() const
{
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// General reference counting support
PSmartPointer::PSmartPointer(const PSmartPointer & ptr)
{
object = ptr.object;
if (object != NULL)
++object->referenceCount;
}
PSmartPointer & PSmartPointer::operator=(const PSmartPointer & ptr)
{
if (object == ptr.object)
return *this;
if ((object != NULL) && (--object->referenceCount == 0))
delete object;
object = ptr.object;
if (object != NULL)
++object->referenceCount;
return *this;
}
PSmartPointer::~PSmartPointer()
{
if ((object != NULL) && (--object->referenceCount == 0))
delete object;
}
PObject::Comparison PSmartPointer::Compare(const PObject & obj) const
{
PAssert(PIsDescendant(&obj, PSmartPointer), PInvalidCast);
PSmartObject * other = ((const PSmartPointer &)obj).object;
if (object == other)
return EqualTo;
return object < other ? LessThan : GreaterThan;
}
//////////////////////////////////////////////////////////////////////////////////////////
#if PMEMORY_CHECK
#undef malloc
#undef realloc
#undef free
#if (__GNUC__ >= 3) || ((__GNUC__ == 2)&&(__GNUC_MINOR__ >= 95)) //2.95.X & 3.X
void * operator new(size_t nSize) throw (std::bad_alloc)
#else
void * operator new(size_t nSize)
#endif
{
return PMemoryHeap::Allocate(nSize, (const char *)NULL, 0, NULL);
}
#if (__GNUC__ >= 3) || ((__GNUC__ == 2)&&(__GNUC_MINOR__ >= 95)) //2.95.X & 3.X
void * operator new[](size_t nSize) throw (std::bad_alloc)
#else
void * operator new[](size_t nSize)
#endif
{
return PMemoryHeap::Allocate(nSize, (const char *)NULL, 0, NULL);
}
#if (__GNUC__ >= 3) || ((__GNUC__ == 2)&&(__GNUC_MINOR__ >= 95)) //2.95.X & 3.X
void operator delete(void * ptr) throw()
#else
void operator delete(void * ptr)
#endif
{
PMemoryHeap::Deallocate(ptr, NULL);
}
#if (__GNUC__ >= 3) || ((__GNUC__ == 2)&&(__GNUC_MINOR__ >= 95)) //2.95.X & 3.X
void operator delete[](void * ptr) throw()
#else
void operator delete[](void * ptr)
#endif
{
PMemoryHeap::Deallocate(ptr, NULL);
}
DWORD PMemoryHeap::allocationBreakpoint = 0;
char PMemoryHeap::Header::GuardBytes[NumGuardBytes];
PMemoryHeap::Wrapper::Wrapper()
{
// The following is done like this to get over brain dead compilers that cannot
// guarentee that a static global is contructed before it is used.
static PMemoryHeap real_instance;
instance = &real_instance;
if (instance->isDestroyed)
return;
#if defined(_WIN32)
EnterCriticalSection(&instance->mutex);
#elif defined(P_MAC_MPTHREADS)
long err;
PAssertOS((err = MPEnterCriticalRegion(instance->mutex, kDurationForever)) == 0);
#elif defined(P_PTHREADS)
pthread_mutex_lock(&instance->mutex);
#elif defined(P_VXWORKS)
semTake((SEM_ID)instance->mutex, WAIT_FOREVER);
#endif
}
PMemoryHeap::Wrapper::~Wrapper()
{
if (instance->isDestroyed)
return;
#if defined(_WIN32)
LeaveCriticalSection(&instance->mutex);
#elif defined(P_MAC_MPTHREADS)
long err;
PAssertOS((err = MPExitCriticalRegion(instance->mutex)) == 0 || instance->isDestroyed);
#elif defined(P_PTHREADS)
pthread_mutex_unlock(&instance->mutex);
#elif defined(P_VXWORKS)
semGive((SEM_ID)instance->mutex);
#endif
}
PMemoryHeap::PMemoryHeap()
{
isDestroyed = PFalse;
listHead = NULL;
listTail = NULL;
allocationRequest = 1;
firstRealObject = 0;
flags = NoLeakPrint;
allocFillChar = '\x5A';
freeFillChar = '\xA5';
currentMemoryUsage = 0;
peakMemoryUsage = 0;
currentObjects = 0;
peakObjects = 0;
totalObjects = 0;
for (PINDEX i = 0; i < Header::NumGuardBytes; i++)
Header::GuardBytes[i] = (i&1) == 0 ? '\x55' : '\xaa';
#if defined(_WIN32)
InitializeCriticalSection(&mutex);
static PDebugStream debug;
leakDumpStream = &debug;
#else
#if defined(P_PTHREADS)
#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
pthread_mutex_t recursiveMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
mutex = recursiveMutex;
#else
pthread_mutex_init(&mutex, NULL);
#endif
#elif defined(P_VXWORKS)
mutex = semMCreate(SEM_Q_FIFO);
#endif
leakDumpStream = &cerr;
#endif
}
PMemoryHeap::~PMemoryHeap()
{
if (leakDumpStream != NULL) {
InternalDumpStatistics(*leakDumpStream);
InternalDumpObjectsSince(firstRealObject, *leakDumpStream);
}
isDestroyed = PTrue;
#if defined(_WIN32)
DeleteCriticalSection(&mutex);
extern void PWaitOnExitConsoleWindow();
PWaitOnExitConsoleWindow();
#elif defined(P_PTHREADS)
pthread_mutex_destroy(&mutex);
#elif defined(P_VXWORKS)
semDelete((SEM_ID)mutex);
#endif
}
void * PMemoryHeap::Allocate(size_t nSize, const char * file, int line, const char * className)
{
Wrapper mem;
return mem->InternalAllocate(nSize, file, line, className);
}
void * PMemoryHeap::Allocate(size_t count, size_t size, const char * file, int line)
{
Wrapper mem;
char oldFill = mem->allocFillChar;
mem->allocFillChar = '\0';
void * data = mem->InternalAllocate(count*size, file, line, NULL);
mem->allocFillChar = oldFill;
return data;
}
void * PMemoryHeap::InternalAllocate(size_t nSize, const char * file, int line, const char * className)
{
if (isDestroyed)
return malloc(nSize);
Header * obj = (Header *)malloc(sizeof(Header) + nSize + sizeof(Header::GuardBytes));
if (obj == NULL) {
PAssertAlways(POutOfMemory);
return NULL;
}
// Ignore all allocations made before main() is called. This is indicated
// by PProcess::PreInitialise() clearing the NoLeakPrint flag. Why do we do
// this? because the GNU compiler is broken in the way it does static global
// C++ object construction and destruction.
if (firstRealObject == 0 && (flags&NoLeakPrint) == 0)
firstRealObject = allocationRequest;
if (allocationBreakpoint != 0 && allocationRequest == allocationBreakpoint) {
#ifdef _WIN32
__asm int 3;
#elif defined(P_VXWORKS)
kill(taskIdSelf(), SIGABRT);
#else
kill(getpid(), SIGABRT);
#endif
}
currentMemoryUsage += nSize;
if (currentMemoryUsage > peakMemoryUsage)
peakMemoryUsage = currentMemoryUsage;
currentObjects++;
if (currentObjects > peakObjects)
peakObjects = currentObjects;
totalObjects++;
char * data = (char *)&obj[1];
obj->prev = listTail;
obj->next = NULL;
obj->size = nSize;
obj->fileName = file;
obj->line = (WORD)line;
#ifdef P_LINUX
obj->thread = pthread_self();
#endif
obj->className = className;
obj->request = allocationRequest++;
obj->flags = flags;
memcpy(obj->guard, obj->GuardBytes, sizeof(obj->guard));
memset(data, allocFillChar, nSize);
memcpy(&data[nSize], obj->GuardBytes, sizeof(obj->guard));
if (listTail != NULL)
listTail->next = obj;
listTail = obj;
if (listHead == NULL)
listHead = obj;
return data;
}
void * PMemoryHeap::Reallocate(void * ptr, size_t nSize, const char * file, int line)
{
if (ptr == NULL)
return Allocate(nSize, file, line, NULL);
if (nSize == 0) {
Deallocate(ptr, NULL);
return NULL;
}
Wrapper mem;
if (mem->isDestroyed)
return realloc(ptr, nSize);
if (mem->InternalValidate(ptr, NULL, mem->leakDumpStream) != Ok)
return NULL;
Header * obj = (Header *)realloc(((Header *)ptr)-1, sizeof(Header) + nSize + sizeof(obj->guard));
if (obj == NULL) {
PAssertAlways(POutOfMemory);
return NULL;
}
if (mem->allocationBreakpoint != 0 && mem->allocationRequest == mem->allocationBreakpoint) {
#ifdef _WIN32
__asm int 3;
#elif defined(P_VXWORKS)
kill(taskIdSelf(), SIGABRT);
#else
kill(getpid(), SIGABRT);
#endif
}
mem->currentMemoryUsage -= obj->size;
mem->currentMemoryUsage += nSize;
if (mem->currentMemoryUsage > mem->peakMemoryUsage)
mem->peakMemoryUsage = mem->currentMemoryUsage;
char * data = (char *)&obj[1];
memcpy(&data[nSize], obj->GuardBytes, sizeof(obj->guard));
obj->size = nSize;
obj->fileName = file;
obj->line = (WORD)line;
obj->request = mem->allocationRequest++;
if (obj->prev != NULL)
obj->prev->next = obj;
else
mem->listHead = obj;
if (obj->next != NULL)
obj->next->prev = obj;
else
mem->listTail = obj;
return data;
}
void PMemoryHeap::Deallocate(void * ptr, const char * className)
{
if (ptr == NULL)
return;
Wrapper mem;
Header * obj = ((Header *)ptr)-1;
if (mem->isDestroyed) {
free(obj);
return;
}
switch (mem->InternalValidate(ptr, className, mem->leakDumpStream)) {
case Ok :
break;
case Trashed :
free(ptr);
return;
case Bad :
free(obj);
return;
}
if (obj->prev != NULL)
obj->prev->next = obj->next;
else
mem->listHead = obj->next;
if (obj->next != NULL)
obj->next->prev = obj->prev;
else
mem->listTail = obj->prev;
mem->currentMemoryUsage -= obj->size;
mem->currentObjects--;
memset(ptr, mem->freeFillChar, obj->size); // Make use of freed data noticable
free(obj);
}
PMemoryHeap::Validation PMemoryHeap::Validate(const void * ptr,
const char * className,
ostream * error)
{
Wrapper mem;
return mem->InternalValidate(ptr, className, error);
}
PMemoryHeap::Validation PMemoryHeap::InternalValidate(const void * ptr,
const char * className,
ostream * error)
{
if (isDestroyed)
return Bad;
if (ptr == NULL)
return Trashed;
Header * obj = ((Header *)ptr)-1;
Header * link = listTail;
while (link != NULL && link != obj)
link = link->prev;
if (link == NULL) {
if (error != NULL)
*error << "Block " << ptr << " not in heap!" << endl;
return Trashed;
}
if (memcmp(obj->guard, obj->GuardBytes, sizeof(obj->guard)) != 0) {
if (error != NULL)
*error << "Underrun at " << ptr << '[' << obj->size << "] #" << obj->request << endl;
return Bad;
}
if (memcmp((char *)ptr+obj->size, obj->GuardBytes, sizeof(obj->guard)) != 0) {
if (error != NULL)
*error << "Overrun at " << ptr << '[' << obj->size << "] #" << obj->request << endl;
return Bad;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -