void* calloc(size_t nm, size_t sz) { cpu_AtomicAdd(&alloc_count, 1); static void *(*libc_calloc)(size_t, size_t); if (libc_calloc == NULL) { if (alloc_has_called_dlsym && !alloc_bootstrapped) { ENSURE(nm*sz <= ARRAY_SIZE(alloc_bootstrap_buffer)); #ifdef ALLOC_DEBUG printf("### calloc-bs(%d, %d) = %p\n", nm, sz, alloc_bootstrap_buffer); #endif alloc_bootstrapped = true; return alloc_bootstrap_buffer; } alloc_has_called_dlsym = true; libc_calloc = (void *(*)(size_t, size_t)) dlsym(RTLD_NEXT, "calloc"); } void* ret = libc_calloc(nm, sz); #ifdef ALLOC_DEBUG printf("### calloc(%d, %d) = %p\n", nm, sz, ret); #endif return ret; }
// called when an exception is detected (see below); provides detailed // debugging information and exits. // // note: keep memory allocs and locking to an absolute minimum, because // they may deadlock the process! long __stdcall wseh_ExceptionFilter(struct _EXCEPTION_POINTERS* ep) { // OutputDebugString raises an exception, which OUGHT to be swallowed // by WaitForDebugEvent but sometimes isn't. if we see it, ignore it. if(ep->ExceptionRecord->ExceptionCode == 0x40010006) // DBG_PRINTEXCEPTION_C return EXCEPTION_CONTINUE_EXECUTION; // if run in a debugger, let it handle exceptions (tends to be more // convenient since it can bring up the crash location) if(IsDebuggerPresent()) return EXCEPTION_CONTINUE_SEARCH; // make sure we don't recurse infinitely if this function raises an // SEH exception. (we may only have the guard page's 4 KB worth of // stack space if the exception is EXCEPTION_STACK_OVERFLOW) static intptr_t nestingLevel = 0; cpu_AtomicAdd(&nestingLevel, 1); if(nestingLevel >= 3) return EXCEPTION_CONTINUE_SEARCH; // someone is already holding the dbghelp lock - this is bad. // we'll report this problem first and then try to display the // exception info regardless (maybe dbghelp won't blow up). if(wutil_IsLocked(WDBG_SYM_CS) == 1) DEBUG_DISPLAY_ERROR(L"Exception raised while critical section is held - may deadlock.."); // a dump file is essential for debugging, so write it before // anything else goes wrong (especially before showing the error // dialog because the user could choose to exit immediately) wdbg_sym_WriteMinidump(ep); // extract details from ExceptionRecord. wchar_t descriptionBuf[150]; const wchar_t* description = GetExceptionDescription(ep, descriptionBuf, ARRAY_SIZE(descriptionBuf)); wchar_t file[DEBUG_FILE_CHARS] = {0}; int line = 0; wchar_t func[DEBUG_SYMBOL_CHARS] = {0}; GetExceptionLocus(ep, file, &line, func); wchar_t message[500]; const wchar_t* messageFormat = L"Much to our regret we must report the program has encountered an error.\r\n" L"\r\n" L"Please let us know at http://trac.wildfiregames.com/ and attach the crashlog.txt and crashlog.dmp files.\r\n" L"\r\n" L"Details: unhandled exception (%ls)\r\n"; swprintf_s(message, ARRAY_SIZE(message), messageFormat, description); size_t flags = 0; if(ep->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) flags = DE_NO_CONTINUE; const wchar_t* const lastFuncToSkip = WIDEN(STRINGIZE(DECORATED_NAME(wseh_ExceptionFilter))); ErrorReaction er = debug_DisplayError(message, flags, ep->ContextRecord, lastFuncToSkip, file,line,utf8_from_wstring(func).c_str(), 0); ENSURE(er == ER_CONTINUE); // nothing else possible // invoke the Win32 default handler - it calls ExitProcess for // most exception types. return EXCEPTION_CONTINUE_SEARCH; }
void Deallocate(OVERLAPPED* ovl) { cpu_AtomicAdd(&extant, -1); const uintptr_t address = uintptr_t(ovl); ENSURE(uintptr_t(storage) <= address && address < uintptr_t(storage)+storageSize); InterlockedPushEntrySList(&freelist, (PSLIST_ENTRY)(address - offsetof(Entry, ovl))); }
IdxDeleter AddUniqueRangeDeleter(UniqueRangeDeleter deleter) { ENSURE(deleter); IdxDeleter idxDeleter = cpu_AtomicAdd(&numDeleters, 1); ENSURE(idxDeleter < (IdxDeleter)ARRAY_SIZE(deleters)); deleters[idxDeleter] = deleter; return idxDeleter; }
void* realloc(void* ptr, size_t sz) { cpu_AtomicAdd(&alloc_count, 1); static void *(*libc_realloc)(void*, size_t); if (libc_realloc == NULL) { alloc_has_called_dlsym = true; libc_realloc = (void *(*)(void*, size_t)) dlsym(RTLD_NEXT, "realloc"); } void* ret = libc_realloc(ptr, sz); #ifdef ALLOC_DEBUG printf("### realloc(%p, %d) = %p\n", ptr, sz, ret); #endif return ret; }
// @return OVERLAPPED initialized for I/O starting at offset, // or 0 if all available structures have already been allocated. OVERLAPPED* Allocate(off_t offset) { Entry* entry = (Entry*)InterlockedPopEntrySList(&freelist); if(!entry) return 0; OVERLAPPED& ovl = entry->ovl; ovl.Internal = 0; ovl.InternalHigh = 0; ovl.Offset = u64_lo(offset); ovl.OffsetHigh = u64_hi(offset); ovl.hEvent = 0; // (notification is via IOCP and/or polling) cpu_AtomicAdd(&extant, +1); return &ovl; }
// NB: callers should skip this if *idxDeleterOut != 0 (avoids the overhead // of an unnecessary indirect function call) void RegisterUniqueRangeDeleter(UniqueRangeDeleter deleter, volatile IdxDeleter* idxDeleterOut) { ENSURE(deleter); if(!cpu_CAS(idxDeleterOut, idxDeleterNone, -1)) // not the first call for this deleter { // wait until an index has been assigned while(*idxDeleterOut <= 0) cpu_Pause(); return; } const IdxDeleter idxDeleter = cpu_AtomicAdd(&numDeleters, 1); ENSURE(idxDeleter < (IdxDeleter)ARRAY_SIZE(deleters)); deleters[idxDeleter] = deleter; COMPILER_FENCE; *idxDeleterOut = idxDeleter; }
void* malloc(size_t sz) { cpu_AtomicAdd(&alloc_count, 1); static void *(*libc_malloc)(size_t); if (libc_malloc == NULL) { alloc_has_called_dlsym = true; libc_malloc = (void *(*)(size_t)) dlsym(RTLD_NEXT, "malloc"); } void* ret = libc_malloc(sz); #ifdef ALLOC_DEBUG printf("### malloc(%d) = %p\n", sz, ret); #endif if (libc_free == NULL) libc_free = (void (*)(void*)) dlsym(RTLD_NEXT, "free"); return ret; }
void NotifySmallPageCommit() { cpu_AtomicAdd(&smallPageCommits, +1); }