sl@0: /************************************************************************************************ sl@0: NC_ALLOC.CPP sl@0: sl@0: * Portions Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. sl@0: * sl@0: * Copyright (c) 1997 sl@0: * Mark of the Unicorn, Inc. sl@0: * sl@0: * Permission to use, copy, modify, distribute and sell this software sl@0: * and its documentation for any purpose is hereby granted without fee, sl@0: * provided that the above copyright notice appear in all copies and sl@0: * that both that copyright notice and this permission notice appear sl@0: * in supporting documentation. Mark of the Unicorn makes no sl@0: * representations about the suitability of this software for any sl@0: * purpose. It is provided "as is" without express or implied warranty. sl@0: sl@0: ************************************************************************************************/ sl@0: sl@0: #include "nc_alloc.h" sl@0: #include sl@0: sl@0: #if defined (EH_NEW_HEADERS) sl@0: # include sl@0: # include sl@0: # include sl@0: #else sl@0: # include sl@0: # include sl@0: # include sl@0: #endif sl@0: sl@0: #if defined (EH_NEW_IOSTREAMS) sl@0: # include sl@0: #else sl@0: # include sl@0: #endif sl@0: sl@0: long alloc_count = 0; sl@0: long object_count = 0; sl@0: long TestController::possible_failure_count = 0; sl@0: const char* TestController::current_test = ""; sl@0: const char* TestController::current_test_category = "no category"; sl@0: const char* TestController::current_container = 0; sl@0: bool TestController::nc_verbose = true; sl@0: bool TestController::never_fail = false; sl@0: bool TestController::track_allocations = false; sl@0: bool TestController::leak_detection_enabled = false; sl@0: sl@0: TestController gTestController; sl@0: sl@0: //************************************************************************************************ sl@0: void TestController::maybe_fail(long) { sl@0: if (never_fail || Failure_threshold() == kNotInExceptionTest) sl@0: return; sl@0: sl@0: // throw if allocation would satisfy the threshold sl@0: if (possible_failure_count++ >= Failure_threshold()) { sl@0: // what about doing some standard new_handler() behavior here (to test it!) ??? sl@0: sl@0: // reset and simulate an out-of-memory failure sl@0: Failure_threshold() = kNotInExceptionTest; sl@0: #ifndef EH_NO_EXCEPTIONS sl@0: throw EH_STD::bad_alloc(); sl@0: #endif sl@0: } sl@0: } sl@0: sl@0: #if defined (EH_HASHED_CONTAINERS_IMPLEMENTED) sl@0: # if defined (__SGI_STL) sl@0: # if defined (EH_NEW_HEADERS) sl@0: # include sl@0: # else sl@0: # include sl@0: # endif sl@0: # elif defined (__MSL__) sl@0: # include sl@0: # else sl@0: # error what do I include to get hash_set? sl@0: # endif sl@0: #else sl@0: # if defined (EH_NEW_HEADERS) sl@0: # include sl@0: # else sl@0: # include sl@0: # endif sl@0: #endif sl@0: sl@0: #if !defined (EH_HASHED_CONTAINERS_IMPLEMENTED) sl@0: typedef EH_STD::set > allocation_set; sl@0: #else sl@0: sl@0: USING_CSTD_NAME(size_t) sl@0: sl@0: struct hash_void { sl@0: size_t operator()(void* x) const { return (size_t)x; } sl@0: }; sl@0: sl@0: typedef EH_STD::hash_set > allocation_set; sl@0: #endif sl@0: sl@0: static allocation_set& alloc_set() { sl@0: static allocation_set s; sl@0: return s; sl@0: } sl@0: sl@0: // Prevents infinite recursion during allocation sl@0: static bool using_alloc_set = false; sl@0: sl@0: #if !defined (NO_FAST_ALLOCATOR) sl@0: // sl@0: // FastAllocator -- speeds up construction of TestClass objects when sl@0: // TESTCLASS_DEEP_DATA is enabled, and speeds up tracking of allocations sl@0: // when the suite is run with the -t option. sl@0: // sl@0: class FastAllocator { sl@0: public: sl@0: //FastAllocator() : mFree(0), mUsed(0) {} sl@0: static void *Allocate(size_t s) { sl@0: void *result = 0; sl@0: sl@0: if (s <= sizeof(Block)) { sl@0: if (mFree != 0) { sl@0: result = mFree; sl@0: mFree = mFree->next; sl@0: } sl@0: else if (mBlocks != 0 && mUsed < kBlockCount) { sl@0: result = (void*)&mBlocks[mUsed++]; sl@0: } sl@0: } sl@0: return result; sl@0: } sl@0: sl@0: static bool Free(void* p) { sl@0: Block* b = (Block*)p; sl@0: if (mBlocks == 0 || b < mBlocks || b >= mBlocks + kBlockCount) sl@0: return false; sl@0: b->next = mFree; sl@0: mFree = b; sl@0: return true; sl@0: } sl@0: sl@0: struct Block; sl@0: friend struct Block; sl@0: sl@0: enum { sl@0: // Number of fast allocation blocks to create. sl@0: kBlockCount = 1500, sl@0: sl@0: // You may need to adjust this number for your platform. sl@0: // A good choice will speed tests. A bad choice will still work. sl@0: kMinBlockSize = 48 sl@0: }; sl@0: sl@0: struct Block { sl@0: union { sl@0: Block *next; sl@0: double dummy; // fbp - force alignment sl@0: char dummy2[kMinBlockSize]; sl@0: }; sl@0: }; sl@0: sl@0: static Block* mBlocks; sl@0: static Block *mFree; sl@0: static size_t mUsed; sl@0: }; sl@0: sl@0: FastAllocator::Block *FastAllocator::mBlocks = sl@0: (FastAllocator::Block*)EH_CSTD::calloc( sizeof(FastAllocator::Block), FastAllocator::kBlockCount ); sl@0: FastAllocator::Block *FastAllocator::mFree; sl@0: size_t FastAllocator::mUsed; sl@0: sl@0: sl@0: static FastAllocator gFastAllocator; sl@0: #endif sl@0: sl@0: inline char* AllocateBlock(size_t s) { sl@0: #if !defined (NO_FAST_ALLOCATOR) sl@0: char * const p = (char*)gFastAllocator.Allocate( s ); sl@0: if (p != 0) sl@0: return p; sl@0: #endif sl@0: sl@0: return (char*)EH_CSTD::malloc(s); sl@0: } sl@0: sl@0: static void* OperatorNew( size_t s ) { sl@0: if (!using_alloc_set) { sl@0: simulate_possible_failure(); sl@0: ++alloc_count; sl@0: } sl@0: sl@0: char *p = AllocateBlock(s); sl@0: sl@0: if (gTestController.TrackingEnabled() && sl@0: gTestController.LeakDetectionEnabled() && sl@0: !using_alloc_set) { sl@0: using_alloc_set = true; sl@0: bool inserted = alloc_set().insert(p).second; sl@0: EH_ASSERT(inserted); sl@0: using_alloc_set = false; sl@0: } sl@0: sl@0: return p; sl@0: } sl@0: #if 0 //sandeep sl@0: void* _STLP_CALL operator new(size_t s) sl@0: #ifdef EH_DELETE_HAS_THROW_SPEC sl@0: throw(EH_STD::bad_alloc) sl@0: #endif sl@0: { return OperatorNew( s ); } sl@0: sl@0: #ifdef EH_USE_NOTHROW sl@0: void* _STLP_CALL operator new(size_t size, const EH_STD::nothrow_t&) throw() { sl@0: try { sl@0: return OperatorNew( size ); sl@0: } sl@0: catch (...) { sl@0: return 0; sl@0: } sl@0: } sl@0: #endif sl@0: sl@0: #if defined (EH_VECTOR_OPERATOR_NEW) sl@0: void* _STLP_CALL operator new[](size_t size ) throw(EH_STD::bad_alloc) { sl@0: return OperatorNew( size ); sl@0: } sl@0: sl@0: # ifdef EH_USE_NOTHROW sl@0: void* _STLP_CALL operator new[](size_t size, const EH_STD::nothrow_t&) throw() { sl@0: try { sl@0: return OperatorNew(size); sl@0: } sl@0: catch (...) { sl@0: return 0; sl@0: } sl@0: } sl@0: # endif sl@0: sl@0: void _STLP_CALL operator delete[](void* ptr) throw() sl@0: { operator delete( ptr ); } sl@0: #endif sl@0: sl@0: #if defined (EH_DELETE_HAS_THROW_SPEC) sl@0: void _STLP_CALL operator delete(void* s) throw() sl@0: #else sl@0: void _STLP_CALL operator delete(void* s) sl@0: #endif sl@0: { sl@0: if ( s != 0 ) { sl@0: if ( !using_alloc_set ) { sl@0: --alloc_count; sl@0: sl@0: if ( gTestController.TrackingEnabled() && gTestController.LeakDetectionEnabled() ) { sl@0: using_alloc_set = true; sl@0: allocation_set::iterator p = alloc_set().find( (char*)s ); sl@0: EH_ASSERT( p != alloc_set().end() ); sl@0: alloc_set().erase( p ); sl@0: using_alloc_set = false; sl@0: } sl@0: } sl@0: # if ! defined (NO_FAST_ALLOCATOR) sl@0: if ( !gFastAllocator.Free( s ) ) sl@0: # endif sl@0: EH_CSTD::free(s); sl@0: } sl@0: } sl@0: #endif //sandeep sl@0: sl@0: sl@0: /*=================================================================================== sl@0: ClearAllocationSet (private helper) sl@0: sl@0: EFFECTS: Empty the set of allocated blocks. sl@0: ====================================================================================*/ sl@0: void TestController::ClearAllocationSet() { sl@0: if (!using_alloc_set) { sl@0: using_alloc_set = true; sl@0: alloc_set().clear(); sl@0: using_alloc_set = false; sl@0: } sl@0: } sl@0: sl@0: sl@0: bool TestController::ReportLeaked() { sl@0: EndLeakDetection(); sl@0: sl@0: if (using_alloc_set) sl@0: EH_ASSERT( alloc_count == static_cast(alloc_set().size()) ); sl@0: sl@0: if (alloc_count != 0 || object_count != 0) { sl@0: EH_STD::cerr<<"\nEH TEST FAILURE !\n"; sl@0: PrintTestName(true); sl@0: if (alloc_count) sl@0: EH_STD::cerr << "ERROR : " << alloc_count << " outstanding allocations.\n"; sl@0: if (object_count) sl@0: EH_STD::cerr << "ERROR : " << object_count << " non-destroyed objects.\n"; sl@0: alloc_count = object_count = 0; sl@0: return true; sl@0: } sl@0: return false; sl@0: } sl@0: sl@0: sl@0: sl@0: /*=================================================================================== sl@0: PrintTestName sl@0: sl@0: EFFECTS: Prints information about the current test. If err is false, ends with sl@0: an ellipsis, because the test is ongoing. If err is true an error is being sl@0: reported, and the output ends with an endl. sl@0: ====================================================================================*/ sl@0: sl@0: void TestController::PrintTestName(bool err) { sl@0: if (current_container) sl@0: EH_STD::cerr<<"["<