/*** *init.cpp - RTC support * * Copyright (c) 1998-2001, Microsoft Corporation. All rights reserved. * * *Revision History: * 07-28-98 JWM Module incorporated into CRTs (from KFrei) * 10-12-98 KBF Moved _RTC_IsEnabled here from UserAPI, and fixed it * 10-13-98 KBF Added _RTC_SetOutOfMemFunc * 10-28-98 KBF Added _RTC_Shutdown to prevent locks on FreeLibrary * 11-03-98 KBF added throw() to eliminate C++ EH code & improved * termination code * 11-24-98 KBF Added additional callback to _RTC_MSPtrMemCheckN * 11-25-98 KBF Fixed initialization problem * 12-03-98 KBF Added APISet callback, and changed MSPtrMemCheckN * to CheckMem * 05-11-99 KBF Error if RTC support define not enabled * 05-26-99 KBF General cleanup - RTClv cut, _RTC_ADVMEM for reenabling * -RTCm later * 08-03-99 KBF Fixed some pretty bad handle leaks, code cleanup & * commenting * 11-30-99 PML Compile /Wp64 clean. * ****/ #ifndef _RTC #error RunTime Check support not enabled! #endif #include "rtcpriv.h" #pragma intrinsic(memset) #ifdef _RTC_ADVMEM // This is the process wide global data struct pointer // It must maintain backward compatibility at all times! _RTC_globals *_RTC_globptr = 0; // This is only actually used for shadow memory, but it doesn't really hurt // And it serves as a placeholder for future work CRITICAL_SECTION _RTC_memlock; HashTable<_RTC_HeapBlock> *_RTC_heapblocks = 0; _RTC_Container *_RTC_memhier = 0; shadowtag *_RTC_shadow = 0; index_elem *_RTC_pageidx = 0; bool *_RTC_pi_array = 0; bool _RTC_shadowmemory = false; # define FUNCCOUNT 4 #else # define FUNCCOUNT 1 #endif // _RTC_ADVMEM #ifdef _RTC_ADVMEM static _RTC_Funcs this_image; static char name[40] = "#--------RTCSubsystem"; // scoped name for process wide synchronization static HANDLE init_mutex = INVALID_HANDLE_VALUE; // mutex for initialization & termination only static HANDLE work_mutex = INVALID_HANDLE_VALUE; // mutex for all RTC stuff static HANDLE sharedmem = INVALID_HANDLE_VALUE; // the memory mapped file static void *funcs[FUNCCOUNT] = { // List of function pointers that the CRT need hooks too # ifdef _RTC_ADVMEM &_RTC_APISet, &_RTC_Allocate, &_RTC_Free, &_RTC_CheckMem_API # else 0 # endif }; static _RTC_globals * GetRTCGlobalData() throw(); static void _RTC_NotifyOfGlobChange() throw(); static void SetErrors() throw(); static void InitMemoryTracking(bool advmem) throw(); static void InitGlobals() throw(); static void GetGlobals() throw(); static void SetSMName(char which); #endif #if 0 void DBGdumpbin(void *addr, char *buf) { unsigned int x = (unsigned int)addr; for (int i = 0; i < 8; i++) { buf[7-i] = x & 15; if (buf[7-i] < 10) buf[7-i] += '0'; else buf[7-i] += 'a' - 10; x = x >> 4; } } #endif // This initializes the basics of the RTC subsystem void __cdecl _RTC_InitBase(void) { static bool init = false; if (init) return; init = true; _RTC_SetErrorFunc(_CRT_RTC_INIT(0, 0, 0, _RTC_CURRENT_VERSION, 0)); } void __cdecl _RTC_Shutdown(void) { _CRT_RTC_INIT(0, 0, 0, _RTC_CURRENT_VERSION, 1); } #ifdef _RTC_ADVMEM // This initializes the shadow memory subsystem void __cdecl _RTC_InitAdvMem(void) { ACQUIRE(INIT_MUTEX); if (_RTC_shadowmemory) { _RTC_SetErrorFunc(_CRT_RTC_INIT(init_mutex, funcs, FUNCCOUNT, _RTC_CURRENT_VERSION, 0)); return; } ACQUIRE(WORK_MUTEX); GetGlobals(); InitGlobals(); if (_RTC_shadowmemory) { _RTC_SetErrorFunc(_CRT_RTC_INIT(init_mutex, funcs, FUNCCOUNT, _RTC_CURRENT_VERSION, 0)); return; } _RTC_shadowmemory = true; if (!_RTC_shadow) _RTC_MS_Init(); InitMemoryTracking(true); MEMORY_BASIC_INFORMATION mbi; if (VirtualQuery(&_RTC_SetErrorFunc, &mbi, sizeof(mbi))) _RTC_NotifyOthersOfChange((void*)mbi.AllocationBase); RELEASE(WORK_MUTEX); RELEASE(INIT_MUTEX); } #endif #ifdef _RTC_ADVMEM // Remove this image from the list of running images... void __cdecl _RTC_Shutdown(void) { static bool run = false; MEMORY_BASIC_INFORMATION mbi, img_mbi; _RTC_Funcs *curfunc, *prev; if (!_RTC_globptr || run) return; run = true; __try { if (_RTC_Lock(INIT_MUTEX)) { __try { if (_RTC_Lock(WORK_MUTEX)) { __try { _CRT_RTC_INIT(init_mutex, funcs, FUNCCOUNT, _RTC_CURRENT_VERSION, 1); curfunc = _RTC_globptr->callbacks; prev = 0; VirtualQuery(&this_image, &img_mbi, sizeof(img_mbi)); while (curfunc) { VirtualQuery(curfunc, &mbi, sizeof(mbi)); if (mbi.BaseAddress == img_mbi.BaseAddress) { if (prev) prev->next = curfunc->next; else _RTC_globptr->callbacks = curfunc->next; } else if (mbi.State != MEM_COMMIT) { if (prev) prev->next = 0; else _RTC_globptr->callbacks = 0; OutputDebugString("RTC Shutdown problem detected..."); break; } else prev = curfunc; curfunc = curfunc->next; } } __finally { _RTC_Unlock(WORK_MUTEX); } } } __finally { _RTC_Unlock(INIT_MUTEX); } } } __finally { CloseHandle(init_mutex); CloseHandle(work_mutex); if (_RTC_globptr) UnmapViewOfFile(_RTC_globptr); CloseHandle(sharedmem); init_mutex = work_mutex = sharedmem = INVALID_HANDLE_VALUE; } } static void GetGlobals() throw() { static bool init = false; if (init) return; init = true; // Setup the error types for this instance for (int i = 0; i < _RTC_ILLEGAL; i++) _RTC_ErrorLevels[i] = 1; if (!_RTC_globptr) _RTC_globptr = GetRTCGlobalData(); if(_RTC_globptr) _RTC_NotifyOfGlobChange(); } static void InitGlobals() throw() { static bool init = false; if (init) return; init = true; #ifdef _RTC_ADVMEM if (!_RTC_heap2) { _RTC_heap2 = new _RTC_SimpleHeap(8); _RTC_heap4 = new _RTC_SimpleHeap(16); _RTC_heap8 = new _RTC_SimpleHeap(32); } #endif // Add this module to the list of callbacks MEMORY_BASIC_INFORMATION mbi; if (_RTC_globptr && VirtualQuery(&_RTC_SetErrorFunc, &mbi, sizeof(mbi))) { this_image.err = 0; this_image.next = _RTC_globptr->callbacks; this_image.notify = &_RTC_NotifyOfGlobChange; this_image.allocationBase = mbi.AllocationBase; #ifdef _RTC_ADVMEM this_image.shadowoff = 0; #endif _RTC_globptr->callbacks = &this_image; } } static void InitMemoryTracking(bool advmem) throw() { static bool init = false; if (init) return; init = true; // Build the memory block hash table void *hbmem = VirtualAlloc(0, 65521 * sizeof(_RTC_HeapBlock*), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); _RTC_heapblocks = new HashTable<_RTC_HeapBlock>(65521, hbmem); _RTC_MSAllocShadow((memptr)hbmem, 65521 * sizeof(_RTC_HeapBlock*), IDX_STATE_ILLEGAL); _RTC_memhier = new _RTC_Container(0); _RTC_MSAllocateGlobals(); _RTC_SetErrorFunc(_CRT_RTC_INIT(init_mutex, funcs, 2 + (advmem ? 2 : 0), _RTC_CURRENT_VERSION, 0)); } #endif // This is code to post process wide values... #ifdef _RTC_ADVMEM static void SetSMName(char which) { name[0] = which; if (name[1] != '-') return; DWORD pid = GetCurrentProcessId(); char *num = &(name[1]); for (int i = 0; i < 8; i++) { *num = (char)('A' + (pid & 0xF)); num++; pid >>= 4; } } bool _RTC_Lock(int work) // currently work = 1, init = 0 { HANDLE mutex = (work == WORK_MUTEX) ? work_mutex : init_mutex; char chr = (work == WORK_MUTEX) ? 'W' : 'I'; if (mutex == INVALID_HANDLE_VALUE) { SetSMName(chr); mutex = CreateMutex(NULL, FALSE, name); if (mutex == INVALID_HANDLE_VALUE) return false; } WaitForSingleObject(mutex, INFINITE); return true; } void _RTC_Unlock(int work) { ReleaseMutex((work == WORK_MUTEX) ? work_mutex : init_mutex); } static _RTC_globals* GetRTCGlobalData() throw() { // Try to open the memory mapped file // If it's not created, create it & init it to zeroes SetSMName('F'); sharedmem = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, _RTC_GLOBALS_SIZE, name); if (!sharedmem) return 0; DWORD lastErr = GetLastError(); _RTC_globals* data = (_RTC_globals *)MapViewOfFile(sharedmem, FILE_MAP_ALL_ACCESS, 0, 0, 0); if (!data) return 0; if (lastErr != ERROR_ALREADY_EXISTS) { memset(data, 0, sizeof(_RTC_globals)); } return data; } // This function should be called when data in the global pointer has changed // This stuff is highly version sensitive! Be careful! static void _RTC_NotifyOfGlobChange() throw() { _RTC_memlock = _RTC_globptr->memlock; #ifdef _RTC_ADVMEM _RTC_heap2 = _RTC_globptr->heap2; _RTC_heap4 = _RTC_globptr->heap4; _RTC_heap8 = _RTC_globptr->heap8; _RTC_shadow = _RTC_globptr->shadow; _RTC_pageidx = _RTC_globptr->pageidx; _RTC_pi_array = _RTC_globptr->pi_array; _RTC_memhier = _RTC_globptr->memhier; _RTC_heapblocks = _RTC_globptr->heapblocks; _RTC_shadowmemory = _RTC_globptr->shadowmemory; #endif } // This function should be called when local data has changed // and needs copied to global data // This stuff is highly version sensitive! Be careful! void _RTC_NotifyOthersOfChange(void *addr) { _RTC_globptr->memlock = _RTC_memlock; #ifdef _RTC_ADVMEM _RTC_globptr->heap2 = _RTC_heap2; _RTC_globptr->heap4 = _RTC_heap4; _RTC_globptr->heap8 = _RTC_heap8; _RTC_globptr->shadow = _RTC_shadow; _RTC_globptr->heapblocks = _RTC_heapblocks; _RTC_globptr->memhier = _RTC_memhier; _RTC_globptr->pageidx = _RTC_pageidx; _RTC_globptr->pi_array = _RTC_pi_array; _RTC_globptr->shadowmemory = _RTC_shadowmemory; #endif for (_RTC_Funcs *f = _RTC_globptr->callbacks; f; f = f->next) if (f->allocationBase != addr) f->notify(); } void __cdecl _RTC_SetOutOfMemFunc(int (*func)(void)) { if (!_RTC_Lock()) return; MEMORY_BASIC_INFORMATION mbi; if (VirtualQuery(&_RTC_SetErrorFunc, &mbi, sizeof(mbi))) { for (_RTC_Funcs *f = _RTC_globptr->callbacks; f; f = f->next) { if (f->allocationBase == mbi.AllocationBase) { f->shadowoff = func; _RTC_Unlock(); return; } } } _RTC_Unlock(); } #endif // _RTC_ADVMEM