static void *worker (void *p) { register int i; for (i = 0; i < PERINC; i++) { EnterSpinLock (&lock); EnterSpinLock (&lock); val++; LeaveSpinLock (&lock); LeaveSpinLock (&lock); } InterlockedIncrement (&done_threads); return NULL; }//end: worker()
void mempool_node_put(mempool p, void *data) { struct node *node; node = DATA_TO_NODE(data); #ifdef MEMPOOLASSERT if(node->magic != NODE_MAGIC) { ShowError(read_message("Source.common.mempool_node_put"), p->name, data); return; // lost, } { struct pool_segment *node_seg = node->segment; if(node_seg->pool != p) { ShowError(read_message("Source.common.mempool_node_put2"), p->name, data, node_seg->pool); return; } } // reset used flag. node->used = false; #endif // EnterSpinLock(&p->nodeLock); node->next = p->free_list; p->free_list = node; LeaveSpinLock(&p->nodeLock); InterlockedIncrement64(&p->num_nodes_free); }//end: mempool_node_put()
static void *mempool_async_allocator(void *x) { mempool p; while(1) { if(l_async_terminate > 0) break; EnterSpinLock(&l_mempoolListLock); for(p = l_mempoolList; p != NULL; p = p->next) { if(p->num_nodes_free < p->elem_realloc_thresh) { // add new segment. segment_allocate_add(p, p->elem_realloc_step); // increase stats counter InterlockedIncrement64(&p->num_realloc_events); } } LeaveSpinLock(&l_mempoolListLock); ramutex_lock(l_async_lock); racond_wait(l_async_cond, l_async_lock, -1); ramutex_unlock(l_async_lock); } return NULL; }//end: mempool_async_allocator()
//------------------------------------------------------------------------- MH_STATUS WINAPI MH_Initialize(VOID) { MH_STATUS status = MH_OK; EnterSpinLock(); if (g_hHeap == NULL) { g_hHeap = HeapCreate(0, 0, 0); if (g_hHeap != NULL) { // Initialize the internal function buffer. InitializeBuffer(); } else { status = MH_ERROR_MEMORY_ALLOC; } } else { status = MH_ERROR_ALREADY_INITIALIZED; } LeaveSpinLock(); return status; }
void mempool_node_put(mempool p, void *data){ struct node *node; node = DATA_TO_NODE(data); #ifdef MEMPOOLASSERT if(node->magic != NODE_MAGIC){ ShowError("Mempool [%s] node_put failed, given address (%p) has invalid magic.\n", p->name, data); return; // lost, } { struct pool_segment *node_seg = node->segment; if(node_seg->pool != p){ ShowError("Mempool [%s] node_put faild, given node (data address %p) doesnt belongs to this pool. ( Node Origin is [%s] )\n", p->name, data, node_seg->pool); return; } } // reset used flag. node->used = false; #endif // EnterSpinLock(&p->nodeLock); node->next = p->free_list; p->free_list = node; LeaveSpinLock(&p->nodeLock); InterlockedIncrement64(&p->num_nodes_free); }//end: mempool_node_put()
//------------------------------------------------------------------------- MH_STATUS WINAPI MH_ApplyQueued(VOID) { MH_STATUS status = MH_OK; UINT i, first = INVALID_HOOK_POS; EnterSpinLock(); if (g_hHeap != NULL) { for (i = 0; i < g_hooks.size; ++i) { if (g_hooks.pItems[i].isEnabled != g_hooks.pItems[i].queueEnable) { first = i; break; } } if (first != INVALID_HOOK_POS) { FROZEN_THREADS threads; Freeze(&threads, ALL_HOOKS_POS, ACTION_APPLY_QUEUED); for (i = first; i < g_hooks.size; ++i) { PHOOK_ENTRY pHook = &g_hooks.pItems[i]; if (pHook->isEnabled != pHook->queueEnable) { status = EnableHookLL(i, pHook->queueEnable); if (status != MH_OK) break; } } Unfreeze(&threads); } } else { status = MH_ERROR_NOT_INITIALIZED; } LeaveSpinLock(); return status; }
//------------------------------------------------------------------------- static MH_STATUS EnableHook(LPVOID pTarget, BOOL enable) { MH_STATUS status = MH_OK; EnterSpinLock(); if (g_hHeap != NULL) { if (pTarget == MH_ALL_HOOKS) { status = EnableAllHooksLL(enable); } else { FROZEN_THREADS threads; UINT pos = FindHookEntry(pTarget); if (pos != INVALID_HOOK_POS) { if (g_hooks.pItems[pos].isEnabled != enable) { Freeze(&threads, pos, ACTION_ENABLE); status = EnableHookLL(pos, enable); Unfreeze(&threads); } else { status = enable ? MH_ERROR_ENABLED : MH_ERROR_DISABLED; } } else { status = MH_ERROR_NOT_CREATED; } } } else { status = MH_ERROR_NOT_INITIALIZED; } LeaveSpinLock(); return status; }
//------------------------------------------------------------------------- MH_STATUS WINAPI MH_RemoveHook(LPVOID pTarget) { MH_STATUS status = MH_OK; EnterSpinLock(); if (g_hHeap != NULL) { UINT pos = FindHookEntry(pTarget); if (pos != INVALID_HOOK_POS) { if (g_hooks.pItems[pos].isEnabled) { FROZEN_THREADS threads; Freeze(&threads, pos, ACTION_DISABLE); status = EnableHookLL(pos, FALSE); Unfreeze(&threads); } if (status == MH_OK) { FreeBuffer(g_hooks.pItems[pos].pTrampoline); DeleteHookEntry(pos); } } else { status = MH_ERROR_NOT_CREATED; } } else { status = MH_ERROR_NOT_INITIALIZED; } LeaveSpinLock(); return status; }
void *mempool_node_get(mempool p) { struct node *node; int64 num_used; if(p->num_nodes_free < p->elem_realloc_thresh) racond_signal(l_async_cond); while(1) { EnterSpinLock(&p->nodeLock); node = p->free_list; if(node != NULL) p->free_list = node->next; LeaveSpinLock(&p->nodeLock); if(node != NULL) break; rathread_yield(); } InterlockedDecrement64(&p->num_nodes_free); // Update peak value num_used = (p->num_nodes_total - p->num_nodes_free); if(num_used > p->peak_nodes_used) { InterlockedExchange64(&p->peak_nodes_used, num_used); } #ifdef MEMPOOLASSERT node->used = true; #endif return NODE_TO_DATA(node); }//end: mempool_node_get()
void mempool_final() { mempool p, pn; if(rand()%2 + 1) return; ShowStatus("Mempool: Terminating async. allocation worker and remaining pools.\n"); // Terminate worker / wait until its terminated. InterlockedIncrement(&l_async_terminate); racond_signal(l_async_cond); rathread_wait(l_async_thread, NULL); // Destroy cond var and mutex. racond_destroy(l_async_cond); ramutex_destroy(l_async_lock); // Free remaining mempools // ((bugged code! this should halppen, every mempool should // be freed by the subsystem that has allocated it.) // EnterSpinLock(&l_mempoolListLock); p = l_mempoolList; while(1) { if(p == NULL) break; pn = p->next; ShowWarning(read_message("Source.common.mempool_final"), p->name); mempool_destroy(p); p = pn; } LeaveSpinLock(&l_mempoolListLock); }//end: mempool_final()
//------------------------------------------------------------------------- MH_STATUS WINAPI MH_Uninitialize(VOID) { MH_STATUS status = MH_OK; EnterSpinLock(); if (g_hHeap != NULL) { status = EnableAllHooksLL(FALSE); if (status == MH_OK) { // Free the internal function buffer. // HeapFree is actually not required, but some tools detect a false // memory leak without HeapFree. UninitializeBuffer(); HeapFree(g_hHeap, 0, g_hooks.pItems); HeapDestroy(g_hHeap); g_hHeap = NULL; g_hooks.pItems = NULL; g_hooks.capacity = 0; g_hooks.size = 0; } } else { status = MH_ERROR_NOT_INITIALIZED; } LeaveSpinLock(); return status; }
//------------------------------------------------------------------------- static MH_STATUS QueueHook(LPVOID pTarget, BOOL queueEnable) { MH_STATUS status = MH_OK; EnterSpinLock(); if (g_hHeap != NULL) { if (pTarget == MH_ALL_HOOKS) { UINT i; for (i = 0; i < g_hooks.size; ++i) g_hooks.pItems[i].queueEnable = queueEnable; } else { UINT pos = FindHookEntry(pTarget); if (pos != INVALID_HOOK_POS) { g_hooks.pItems[pos].queueEnable = queueEnable; } else { status = MH_ERROR_NOT_CREATED; } } } else { status = MH_ERROR_NOT_INITIALIZED; } LeaveSpinLock(); return status; }
void mempool_destroy(mempool p) { struct pool_segment *seg, *segnext; struct node *niter; mempool piter, pprev; char *ptr; int64 i; #ifdef MEMPOOL_DEBUG ShowDebug(read_message("Source.common.mempool_debug4"), p->name); #endif // Unlink from global list. EnterSpinLock(&l_mempoolListLock); piter = l_mempoolList; pprev = l_mempoolList; while(1) { if(piter == NULL) break; if(piter == p) { // unlink from list, // if(pprev == l_mempoolList) { // this (p) is list begin. so set next as head. l_mempoolList = p->next; } else { // replace prevs next wuth our next. pprev->next = p->next; } break; } pprev = piter; piter = piter->next; } p->next = NULL; LeaveSpinLock(&l_mempoolListLock); // Get both locks. EnterSpinLock(&p->segmentLock); EnterSpinLock(&p->nodeLock); if(p->num_nodes_free != p->num_nodes_total) ShowWarning(read_message("Source.common.mempool_destroy"), p->name, (p->num_nodes_total - p->num_nodes_free)); // Free All Segments (this will also free all nodes) // The segment pointer is the base pointer to the whole segment. seg = p->segments; while(1) { if(seg == NULL) break; segnext = seg->next; // .. if(p->ondealloc != NULL) { // walk over the segment, and call dealloc callback! ptr = (char *)seg; ptr += ALIGN_TO_16(sizeof(struct pool_segment)); for(i = 0; i < seg->num_nodes_total; i++) { niter = (struct node *)ptr; ptr += sizeof(struct node); ptr += p->elem_size; #ifdef MEMPOOLASSERT if(niter->magic != NODE_MAGIC) { ShowError(read_message("Source.common.mempool_destroy2"), p->name, niter); continue; } #endif p->ondealloc(NODE_TO_DATA(niter)); } }//endif: ondealloc callback? // simple .. aFree(seg); seg = segnext; } // Clear node ptr p->free_list = NULL; InterlockedExchange64(&p->num_nodes_free, 0); InterlockedExchange64(&p->num_nodes_total, 0); InterlockedExchange64(&p->num_segments, 0); InterlockedExchange64(&p->num_bytes_total, 0); LeaveSpinLock(&p->nodeLock); LeaveSpinLock(&p->segmentLock); // Free pool itself :D aFree(p->name); aFree(p); }//end: mempool_destroy()
mempool mempool_create(const char *name, uint64 elem_size, uint64 initial_count, uint64 realloc_count, memPoolOnNodeAllocationProc onNodeAlloc, memPoolOnNodeDeallocationProc onNodeDealloc) { //.. uint64 realloc_thresh; mempool pool; pool = (mempool)aCalloc(1, sizeof(struct mempool)); if(pool == NULL) { ShowFatalError(read_message("Source.common.mempool_create"), sizeof(struct mempool)); exit(EXIT_FAILURE); } // Check minimum initial count / realloc count requirements. if(initial_count < 50) initial_count = 50; if(realloc_count < 50) realloc_count = 50; // Set Reallocation threshold to 5% of realloc_count, at least 10. realloc_thresh = (realloc_count/100)*5; // if(realloc_thresh < 10) realloc_thresh = 10; // Initialize members.. pool->name = aStrdup(name); pool->elem_size = ALIGN_TO_16(elem_size); pool->elem_realloc_step = realloc_count; pool->elem_realloc_thresh = realloc_thresh; pool->onalloc = onNodeAlloc; pool->ondealloc = onNodeDealloc; InitializeSpinLock(&pool->segmentLock); InitializeSpinLock(&pool->nodeLock); // Initial Statistic values: pool->num_nodes_total = 0; pool->num_nodes_free = 0; pool->num_segments = 0; pool->num_bytes_total = 0; pool->peak_nodes_used = 0; pool->num_realloc_events = 0; // #ifdef MEMPOOL_DEBUG ShowDebug(read_message("Source.common.mempool_create"), pool->name, pool->elem_size, initial_count, pool->elem_realloc_step); #endif // Allocate first segment directly :) segment_allocate_add(pool, initial_count); // Add Pool to the global pool list EnterSpinLock(&l_mempoolListLock); pool->next = l_mempoolList; l_mempoolList = pool; LeaveSpinLock(&l_mempoolListLock); return pool; }//end: mempool_create()
static void segment_allocate_add(mempool p, uint64 count) { // Required Memory: // sz( segment ) // count * sz( real_node_size ) // // where real node size is: // ALIGN_TO_16( sz( node ) ) + p->elem_size // so the nodes usable address is nodebase + ALIGN_TO_16(sz(node)) // size_t total_sz; struct pool_segment *seg = NULL; struct node *nodeList = NULL; struct node *node = NULL; char *ptr = NULL; uint64 i; total_sz = ALIGN_TO_16(sizeof(struct pool_segment)) + ((size_t)count * (sizeof(struct node) + (size_t)p->elem_size)) ; #ifdef MEMPOOL_DEBUG ShowDebug(read_message("Source.common.mempool_debug"), p->name, count, (float)total_sz/1024.f/1024.f); #endif // allocate! (spin forever until weve got the memory.) i=0; while(1) { ptr = (char *)aMalloc(total_sz); if(ptr != NULL) break; i++; // increase failcount. if(!(i & 7)) { ShowWarning(read_message("Source.common.mempool_debug2"), (float)total_sz/1024.f/1024.f, i); #ifdef WIN32 Sleep(1000); #else sleep(1); #endif } else { rathread_yield(); /// allow/force vuln. ctxswitch } }//endwhile: allocation spinloop. // Clear Memory. memset(ptr, 0x00, total_sz); // Initialize segment struct. seg = (struct pool_segment *)ptr; ptr += ALIGN_TO_16(sizeof(struct pool_segment)); seg->pool = p; seg->num_nodes_total = count; seg->num_bytes = total_sz; // Initialze nodes! nodeList = NULL; for(i = 0; i < count; i++) { node = (struct node *)ptr; ptr += sizeof(struct node); ptr += p->elem_size; node->segment = seg; #ifdef MEMPOOLASSERT node->used = false; node->magic = NODE_MAGIC; #endif if(p->onalloc != NULL) p->onalloc(NODE_TO_DATA(node)); node->next = nodeList; nodeList = node; } // Link in Segment. EnterSpinLock(&p->segmentLock); seg->next = p->segments; p->segments = seg; LeaveSpinLock(&p->segmentLock); // Link in Nodes EnterSpinLock(&p->nodeLock); nodeList->next = p->free_list; p->free_list = nodeList; LeaveSpinLock(&p->nodeLock); // Increase Stats: InterlockedExchangeAdd64(&p->num_nodes_total, count); InterlockedExchangeAdd64(&p->num_nodes_free, count); InterlockedIncrement64(&p->num_segments); InterlockedExchangeAdd64(&p->num_bytes_total, total_sz); }//end: segment_allocate_add()
//------------------------------------------------------------------------- MH_STATUS WINAPI MH_CreateHook(LPVOID pTarget, LPVOID pDetour, LPVOID *ppOriginal) { MH_STATUS status = MH_OK; EnterSpinLock(); if (g_hHeap != NULL) { if ((g_Flags & MH_FLAGS_SKIP_EXEC_CHECK) || (IsExecutableAddress(pTarget) && IsExecutableAddress(pDetour)) ) { UINT pos = FindHookEntry(pTarget); if (pos == INVALID_HOOK_POS) { LPVOID pBuffer = AllocateBuffer(pTarget); if (pBuffer != NULL) { TRAMPOLINE ct; ct.pTarget = pTarget; ct.pDetour = pDetour; ct.pTrampoline = pBuffer; if (CreateTrampolineFunction(&ct)) { PHOOK_ENTRY pHook = AddHookEntry(); if (pHook != NULL) { pHook->pTarget = ct.pTarget; #ifdef _M_X64 pHook->pDetour = ct.pRelay; #else pHook->pDetour = ct.pDetour; #endif pHook->pTrampoline = ct.pTrampoline; pHook->patchAbove = ct.patchAbove; pHook->isEnabled = FALSE; pHook->queueEnable = FALSE; pHook->nIP = ct.nIP; memcpy(pHook->oldIPs, ct.oldIPs, ARRAYSIZE(ct.oldIPs)); memcpy(pHook->newIPs, ct.newIPs, ARRAYSIZE(ct.newIPs)); // Back up the target function. if (ct.patchAbove) { memcpy( pHook->backup, (LPBYTE)pTarget - sizeof(JMP_REL), sizeof(JMP_REL) + sizeof(JMP_REL_SHORT)); } else { memcpy(pHook->backup, pTarget, sizeof(JMP_REL)); } if (ppOriginal != NULL) *ppOriginal = pHook->pTrampoline; } else { status = MH_ERROR_MEMORY_ALLOC; } } else { status = MH_ERROR_UNSUPPORTED_FUNCTION; } if (status != MH_OK) { FreeBuffer(pBuffer); } } else { status = MH_ERROR_MEMORY_ALLOC; } } else { status = MH_ERROR_ALREADY_CREATED; } } else { status = MH_ERROR_NOT_EXECUTABLE; } } else { status = MH_ERROR_NOT_INITIALIZED; } LeaveSpinLock(); return status; }