__ATTR_LIB_C__ short LoadDLL(const char *DLL_name, long ID, short major, short minor) { SYM_ENTRY *entry; HANDLE h; unsigned char *bptr,*sptr; unsigned short len,offset=0,wrongver=0; unsigned long pc; unsigned long signature[]={__DLL_SIGNATURE,ID}; asm volatile("bsr 0f; 0:move.l (%%sp)+,%0":"=g"(pc)); if(HW_VERSION==2 && pc<0x40000) return DLL_NOTINGHOSTSPACE; if(__DLL_body_ptr) return DLL_ALREADYLOADED; entry=SymFindFirst(NULL,2); do { if(!strcmp(entry->name,DLL_name)&&entry->handle&&!entry->flags.bits.twin &&(entry->flags.bits.archived||!HeapGetLock(entry->handle))) { len=peek_w(bptr=HeapDeref(entry->handle))+2; if(!memcmp(bptr+len-5,"DLL\x00\xF8",5)) { offset=0; for(sptr=bptr+2;(sptr<bptr+len-1)&&!offset;sptr+=2) if(!memcmp(sptr,signature,8)) { if((unsigned short)major!=((__DLL_interface_struct*)sptr)->major ||(unsigned short)minor>((__DLL_interface_struct*)sptr)->minor) wrongver=1; else offset=sptr-bptr,wrongver=0; } if(offset) break; } } } while((entry=SymFindNext())); if(wrongver) return DLL_WRONGVERSION; if(!entry) return DLL_NOTFOUND; if(!HeapLock(h=entry->handle)) return DLL_LOCKFAILED; if(!(__DLL_body_ptr=malloc(len=peek_w(bptr=HeapDeref(h)+2)+2))) { HeapUnlock(h); return DLL_OUTOFMEM; } memcpy(__DLL_body_ptr,bptr,len); EX_patch((char*)__DLL_body_ptr+(HW_VERSION==2?0x40000:0)+2,(char*)__DLL_body_ptr+(HW_VERSION==2?0x40000:0)+len-1); __DLL_interface_ptr=(__DLL_interface_struct*)((char*)__DLL_body_ptr+offset-2); HeapUnlock(h); return DLL_OK; }
__ATTR_TIOS_CALLBACK__ short fputc(short c, FILE *f) { short tmode=!(f->flags&_F_BIN); unsigned short minalloc; char *base=f->base,*oldbase=base; if(f->flags&_F_ERR) return EOF; if(!(f->flags&_F_WRIT)) __FERROR(f); minalloc=peek_w(base)+3; if(minalloc>65520u) __FERROR(f); if(minalloc>f->alloc) { HeapUnlock(f->handle); if(f->alloc<=65520u-f->buffincrement) f->alloc+=f->buffincrement; else f->alloc=65520u; if(!HeapRealloc(f->handle,f->alloc)) __FERROR(f); base=f->base=HLock(f->handle); f->fpos+=base-oldbase; oldbase=base; } if(feof(f)) (*(short*)base)++; if(c=='\n'&&tmode) c='\r'; poke(f->fpos++,c); if(c=='\r'&&tmode) fputc(' ',f); if(base+peek_w(base)+(tmode?0:2)==f->fpos) { f->flags|=_F_EOF; if(tmode) { poke(f->fpos,0); poke(f->fpos+1,0xE0); } } return c; }
void __cdecl xf_dump_chk() { #ifndef CONEMU_MINIMAL PROCESS_HEAP_ENTRY ent = {NULL}; HeapLock(ghHeap); //HeapCompact(ghHeap,0); char sBlockInfo[255]; PVOID pLast = NULL; while(HeapWalk(ghHeap, &ent)) { if (pLast == ent.lpData) { msprintf(sBlockInfo, countof(sBlockInfo), "!!! HeapWalk cycled at 0x%08X, size=0x%08X\n", (DWORD)ent.lpData, ent.cbData); OutputDebugStringA(sBlockInfo); _ASSERTE(pLast != ent.lpData); break; } if (((int)ent.cbData) < 0) { msprintf(sBlockInfo, countof(sBlockInfo), "!!! Invalid memory block size at 0x%08X, size=0x%08X\n", (DWORD)ent.lpData, ent.cbData); OutputDebugStringA(sBlockInfo); _ASSERTE(((int)ent.cbData) >= 0); break; } } HeapUnlock(ghHeap); #endif }
/* Free select data */ void select_data_free (LPSELECTDATA lpSelectData) { DWORD i; #ifdef DBUG dbug_print("Freeing data of %x", lpSelectData); #endif /* Free APC related data, if they exists */ if (lpSelectData->lpWorker != NULL) { worker_job_finish(lpSelectData->lpWorker); lpSelectData->lpWorker = NULL; }; /* Make sure results/queries cannot be accessed */ lpSelectData->nResultsCount = 0; lpSelectData->nQueriesCount = 0; if (!HeapLock(GetProcessHeap())) { win32_maperr(GetLastError()); uerror("select_data_free", Nothing); }; HeapFree(GetProcessHeap(), 0, lpSelectData); HeapUnlock(GetProcessHeap()); }
/* Create data associated with a select operation */ LPSELECTDATA select_data_new (LPSELECTDATA lpSelectData, SELECTTYPE EType) { /* Allocate the data structure */ LPSELECTDATA res; DWORD i; if (!HeapLock(GetProcessHeap())) { win32_maperr(GetLastError()); uerror("select", Nothing); } res = (LPSELECTDATA)HeapAlloc(GetProcessHeap(), 0, sizeof(SELECTDATA)); HeapUnlock(GetProcessHeap()); /* Init common data */ list_init((LPLIST)res); list_next_set((LPLIST)res, (LPLIST)lpSelectData); res->EType = EType; res->nResultsCount = 0; /* Data following are dedicated to APC like call, they will be initialized if required. For now they are set to invalid values. */ res->funcWorker = NULL; res->nQueriesCount = 0; res->EState = SELECT_STATE_NONE; res->nError = 0; res->lpWorker = NULL; return res; }
LPWORKER worker_new (void) { LPWORKER lpWorker = NULL; if (!HeapLock(hWorkerHeap)) { win32_maperr(GetLastError()); uerror("worker_new", Nothing); }; lpWorker = (LPWORKER)HeapAlloc(hWorkerHeap, 0, sizeof(WORKER)); HeapUnlock(hWorkerHeap); list_init((LPLIST)lpWorker); lpWorker->hJobStarted = CreateEvent(NULL, TRUE, FALSE, NULL); lpWorker->hJobStop = CreateEvent(NULL, TRUE, FALSE, NULL); lpWorker->hJobDone = CreateEvent(NULL, TRUE, FALSE, NULL); lpWorker->lpJobUserData = NULL; lpWorker->hWorkerReady = CreateEvent(NULL, FALSE, FALSE, NULL); lpWorker->hCommandReady = CreateEvent(NULL, FALSE, FALSE, NULL); lpWorker->ECommand = WORKER_CMD_NONE; lpWorker->hThread = CreateThread( NULL, THREAD_WORKERS_MEM, worker_wait, (LPVOID)lpWorker, 0, NULL); return lpWorker; };
void __cdecl xf_dump() { PROCESS_HEAP_ENTRY ent = {NULL}; HeapLock(ghHeap); HeapCompact(ghHeap,0); char sBlockInfo[255]; while (HeapWalk(ghHeap, &ent)) { if (ent.wFlags & PROCESS_HEAP_ENTRY_BUSY) { xf_mem_block* p = (xf_mem_block*)ent.lpData; if (p->bBlockUsed==TRUE && p->nBlockSize==ent.cbData) { #ifndef _WIN64 wsprintfA(sBlockInfo, "!!! Lost memory block at 0x%08X, size %u\n Allocated from: %s\n", ent.lpData, ent.cbData, p->sCreatedFrom); #else wsprintfA(sBlockInfo, "!!! Lost memory block at 0x%I64X, size %u\n Allocated from: %s\n", ent.lpData, ent.cbData, p->sCreatedFrom); #endif } else { #ifndef _WIN64 wsprintfA(sBlockInfo, "!!! Lost memory block at 0x%08X, size %u\n Allocated from: %s\n", ent.lpData, ent.cbData, "<Header information broken!>"); #else wsprintfA(sBlockInfo, "!!! Lost memory block at 0x%I64X, size %u\n Allocated from: %s\n", ent.lpData, ent.cbData, "<Header information broken!>"); #endif } OutputDebugStringA(sBlockInfo); } } HeapUnlock(ghHeap); }
int hprintf(HANDLE h, const char *fmt, ...) { /* WriteFile is *not* atomic after a 512 byte boundary, we need to lock */ static CRITICAL_SECTION sync; static int init = 0; /* We use the heap lock to assure mutual exclusion during initialization */ if (!init) { HANDLE heap = GetProcessHeap(); if (!HeapLock(heap)) panic("Could not lock the global heap lock"); if (!init) { InitializeCriticalSection(&sync); init = 1; } if (!HeapUnlock(heap)) panic("Could not unlock the global heap lock"); } int sz; char *buf = NULL; va_list vl; va_list vlc; va_start(vl, fmt); va_copy(vlc, vl); sz = _vscprintf(fmt, vlc); va_end(vlc); int rc = -1; if (sz <= 0) goto end; ++sz; buf = (char*)malloc(sz); if (!buf) goto end; rc = vsnprintf(buf, sz, fmt, vl); if (rc <= 0) goto end; DWORD written; EnterCriticalSection(&sync); if (!WriteFile(h, buf, rc, &written, NULL)) { rc = -1; errno = EIO; } else { rc = written; } LeaveCriticalSection(&sync); end: free(buf); va_end(vl); return rc; }
void* prim_heapUnlock(HANDLE arg1) { static struct {HsInt gc_failed;HsPtr gc_failstring;} gc_result; int gc_failed; char* gc_failstring; do { BOOL res1=HeapUnlock(arg1); if ((gc_failed = ( res1==0 ))) {gc_failstring = ErrorWin("HeapUnlock") ;} else {gc_failed = 0;} gc_result.gc_failed = gc_failed; gc_result.gc_failstring = gc_failstring; return(&gc_result);} while(0); }
BOOL WINAPI HeapSafeFree(_Inout_ HANDLE hHeap, _In_ DWORD dwFlags, _In_opt_ _Post_ptr_invalid_ LPVOID lpMem) { SIZE_T cbMem; BOOL res; if (!hHeap || !lpMem) return FALSE; if (!HeapLock(hHeap)) return FALSE; cbMem = HeapSize(hHeap, dwFlags, lpMem); if (cbMem > 0 && cbMem != (SIZE_T)-1) SecureZeroMemory(lpMem, cbMem); res = HeapFree(hHeap, dwFlags, lpMem); HeapUnlock(hHeap); return res; }
guint gum_peek_private_memory_usage (void) { guint total_size = 0; BOOL success; PROCESS_HEAP_ENTRY entry; success = HeapLock (_gum_memory_heap); g_assert (success); entry.lpData = NULL; while (HeapWalk (_gum_memory_heap, &entry) != FALSE) { if ((entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) total_size += entry.cbData; } success = HeapUnlock (_gum_memory_heap); g_assert (success); return total_size; }
bool winstd::heap::enumerate() { assert(m_h != invalid); bool found = false; // Lock the heap for exclusive access. HeapLock(m_h); PROCESS_HEAP_ENTRY e; e.lpData = NULL; while (HeapWalk(m_h, &e) != FALSE) { if ((e.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) { OutputDebugStr( _T("Allocated block%s%s\n") _T(" Data portion begins at: %#p\n Size: %d bytes\n") _T(" Overhead: %d bytes\n Region index: %d\n"), (e.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) != 0 ? tstring_printf(_T(", movable with HANDLE %#p"), e.Block.hMem).c_str() : _T(""), (e.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) != 0 ? _T(", DDESHARE") : _T(""), e.lpData, e.cbData, e.cbOverhead, e.iRegionIndex); found = true; } } DWORD dwResult = GetLastError(); if (dwResult != ERROR_NO_MORE_ITEMS) OutputDebugStr(_T("HeapWalk failed (error %u).\n"), dwResult); // Unlock the heap. HeapUnlock(m_h); return found; }
void SaveHeapLog() { FILE *f; _HEAPINFO hi; char block[129],*ad; block[128]=0; int code; HANDLE heaps[200]; DWORD n; PROCESS_HEAP_ENTRY phe; f=fopen(WriteDir+SLASH+"heap.log","wb"); SetLastError(0); n=GetProcessHeaps(200,heaps); heaps[n]=GetProcessHeap();n++; fprintf(f,"There are %i heaps for Steem\r\n",n); for (DWORD i=0;i<n;i++){ code=HeapValidate(heaps[i],0,NULL); if (code){ fprintf(f,"Heap %u okay\r\n",i); }else{ fprintf(f,"Heap %u has an error in it!\r\n",i); } HeapLock(heaps[i]); phe.lpData=NULL; while (HeapWalk(heaps[i],&phe)){ fprintf(f,"%s%X\r\n","Bad node, address=",(unsigned long)(phe.lpData)); ad=((char*)phe.lpData)-64; for (int n=0;n<128;n++){ block[n]=*(ad++); if (block[n]==0) block[n]='\\'; if (block[n]==10) block[n]='\\'; if (block[n]==13) block[n]='\\'; } fprintf(f,"%s\r\n",block); } HeapUnlock(heaps[i]); if (phe.lpData==NULL) DisplayLastError(); } fprintf(f,"\r\n\r\n"); code=_heapchk(); if (code==_HEAPOK){ fprintf(f,"%s\r\n","Heap okay, walking:"); }else if (code==_HEAPBADNODE){ fprintf(f,"%s\r\n","Heap has bad node! Walking anyway:"); } hi._pentry=NULL; for(;;){ code=_rtl_heapwalk(&hi); if (code==_HEAPEND) break; if (code==_HEAPBADNODE){ fprintf(f,"%s%X\r\n","Bad node, address=",(unsigned long)(hi.__pentry)); ad=((char*)hi._pentry)-64; for (int n=0;n<128;n++){ block[n]=*(ad++); if (block[n]==0) block[n]='\\'; if (block[n]==10) block[n]='\\'; if (block[n]==13) block[n]='\\'; } fprintf(f,"%s\r\n",block); }else if (code==_HEAPOK){ fprintf(f,"%s%X\r\n","Good node, address=",(unsigned long)(hi.__pentry)); } } fclose(f); }
void TLMemory::Platform::MemOuputAllocations() { DWORD LastError; PROCESS_HEAP_ENTRY Entry; TChar buffer[256] = {0}; // Lock the heap to prevent other threads from accessing the heap // during enumeration. if (HeapLock(g_MemHeap) == FALSE) { _stprintf(&buffer[0], TEXT("Failed to lock heap with LastError %d.\n"), GetLastError()); OutputDebugString(buffer); return; } _stprintf(&buffer[0], TEXT("Walking heap %#p...\n\n"), g_MemHeap); OutputDebugString(buffer); Entry.lpData = NULL; while (HeapWalk(g_MemHeap, &Entry) != FALSE) { if ((Entry.wFlags & PROCESS_HEAP_ENTRY_BUSY) != 0) { _stprintf(&buffer[0], TEXT("Allocated block")); OutputDebugString(buffer); if ((Entry.wFlags & PROCESS_HEAP_ENTRY_MOVEABLE) != 0) { _stprintf(&buffer[0], TEXT(", movable with HANDLE %#p"), Entry.Block.hMem); OutputDebugString(buffer); } if ((Entry.wFlags & PROCESS_HEAP_ENTRY_DDESHARE) != 0) { _stprintf(&buffer[0], TEXT(", DDESHARE")); OutputDebugString(buffer); } } else if ((Entry.wFlags & PROCESS_HEAP_REGION) != 0) { _stprintf(&buffer[0], TEXT("Region\n %d bytes committed\n") \ TEXT(" %d bytes uncommitted\n First block address: %#p\n") \ TEXT(" Last block address: %#p\n"), Entry.Region.dwCommittedSize, Entry.Region.dwUnCommittedSize, Entry.Region.lpFirstBlock, Entry.Region.lpLastBlock); OutputDebugString(buffer); } else if ((Entry.wFlags & PROCESS_HEAP_UNCOMMITTED_RANGE) != 0) { _stprintf(&buffer[0], TEXT("Uncommitted range\n")); OutputDebugString(buffer); } else { _stprintf(&buffer[0], TEXT("Block\n")); OutputDebugString(buffer); } _stprintf(&buffer[0], TEXT(" Data portion begins at: %#p\n Size: %d bytes\n") \ TEXT(" Overhead: %d bytes\n Region index: %d\n\n"), Entry.lpData, Entry.cbData, Entry.cbOverhead, Entry.iRegionIndex); OutputDebugString(buffer); } LastError = GetLastError(); if (LastError != ERROR_NO_MORE_ITEMS) { _stprintf(&buffer[0], TEXT("HeapWalk failed with LastError %d.\n"), LastError); OutputDebugString(buffer); } // // Unlock the heap to allow other threads to access the heap after // enumeration has completed. // if (HeapUnlock(g_MemHeap) == FALSE) { _stprintf(&buffer[0], TEXT("Failed to unlock heap with LastError %d.\n"), GetLastError()); OutputDebugString(buffer); } }
void worker_free (LPWORKER lpWorker) { /* Wait for termination of the worker */ #ifdef DBUG dbug_print("Shutting down worker %x", lpWorker); #endif WaitForSingleObject(lpWorker->hWorkerReady, INFINITE); lpWorker->ECommand = WORKER_CMD_STOP; SetEvent(lpWorker->hCommandReady); WaitForSingleObject(lpWorker->hThread, INFINITE); /* Free resources */ #ifdef DBUG dbug_print("Freeing resources of worker %x", lpWorker); #endif if (lpWorker->hThread != INVALID_HANDLE_VALUE) { CloseHandle(lpWorker->hThread); lpWorker->hThread = INVALID_HANDLE_VALUE; } if (lpWorker->hJobStarted != INVALID_HANDLE_VALUE) { CloseHandle(lpWorker->hJobStarted); lpWorker->hJobStarted = INVALID_HANDLE_VALUE; } if (lpWorker->hJobStop != INVALID_HANDLE_VALUE) { CloseHandle(lpWorker->hJobStop); lpWorker->hJobStop = INVALID_HANDLE_VALUE; } if (lpWorker->hJobDone != INVALID_HANDLE_VALUE) { CloseHandle(lpWorker->hJobDone); lpWorker->hJobDone = INVALID_HANDLE_VALUE; } lpWorker->lpJobUserData = NULL; lpWorker->hJobFunc = NULL; if (lpWorker->hWorkerReady != INVALID_HANDLE_VALUE) { CloseHandle(lpWorker->hWorkerReady); lpWorker->hWorkerReady = INVALID_HANDLE_VALUE; } if (lpWorker->hCommandReady != INVALID_HANDLE_VALUE) { CloseHandle(lpWorker->hCommandReady); lpWorker->hCommandReady = INVALID_HANDLE_VALUE; } if (!HeapLock(hWorkerHeap)) { win32_maperr(GetLastError()); uerror("worker_new", Nothing); }; HeapFree(hWorkerHeap, 0, lpWorker); HeapUnlock(hWorkerHeap); };
void __cdecl xf_dump() { #ifndef CONEMU_MINIMAL PROCESS_HEAP_ENTRY ent = {NULL}; HeapLock(ghHeap); //HeapCompact(ghHeap,0); char sBlockInfo[255]; PVOID pLast = NULL; size_t cbUsedSize = 0, cbBrokenSize = 0; DWORD cCount = 0; while (HeapWalk(ghHeap, &ent)) { if (pLast == ent.lpData) { msprintf(sBlockInfo, countof(sBlockInfo), "!!! HeapWalk cycled at 0x%08X, size=0x%08X\n", (DWORD)ent.lpData, ent.cbData); OutputDebugStringA(sBlockInfo); _ASSERTE(pLast != ent.lpData); break; } if (((int)ent.cbData) < 0) { msprintf(sBlockInfo, countof(sBlockInfo), "!!! Invalid memory block size at 0x%08X, size=0x%08X\n", (DWORD)ent.lpData, ent.cbData); OutputDebugStringA(sBlockInfo); _ASSERTE(((int)ent.cbData) >= 0); break; } if (ent.wFlags & PROCESS_HEAP_ENTRY_BUSY) { xf_mem_block* p = (xf_mem_block*)ent.lpData; if (p->bBlockUsed==TRUE && (p->nBlockSize+sizeof(xf_mem_block)+8)==ent.cbData) { msprintf(sBlockInfo, countof(sBlockInfo), "Used memory block at 0x" WIN3264TEST("%08X","%08X%08X") ", size %u\n Allocated from: %s\n", WIN3264WSPRINT(ent.lpData), ent.cbData, p->sCreatedFrom); cbUsedSize += p->nBlockSize; } else { msprintf(sBlockInfo, countof(sBlockInfo), "Used memory block at 0x" WIN3264TEST("%08X","%08X%08X") ", size %u\n Allocated from: %s\n", WIN3264WSPRINT(ent.lpData), ent.cbData, "<Header information broken!>"); cbBrokenSize += ent.cbData; } cCount++; pLast = ent.lpData; OutputDebugStringA(sBlockInfo); } } HeapUnlock(ghHeap); msprintf(sBlockInfo, countof(sBlockInfo), "Used size 0x" WIN3264TEST("%08X","%08X%08X") ", broken size 0x" WIN3264TEST("%08X","%08X%08X") ", total blocks %u\n", WIN3264WSPRINT(cbUsedSize), WIN3264WSPRINT(cbBrokenSize), cCount); OutputDebugStringA(sBlockInfo); #endif }
CAMLprim value unix_select(value readfds, value writefds, value exceptfds, value timeout) { /* Event associated to handle */ DWORD nEventsCount; DWORD nEventsMax; HANDLE *lpEventsDone; /* Data for all handles */ LPSELECTDATA lpSelectData; LPSELECTDATA iterSelectData; /* Iterator for results */ LPSELECTRESULT iterResult; /* Iterator */ DWORD i; /* Error status */ DWORD err; /* Time to wait */ DWORD milliseconds; /* Is there static select data */ BOOL hasStaticData = FALSE; /* Wait return */ DWORD waitRet; /* Set of handle */ SELECTHANDLESET hds; DWORD hdsMax; LPHANDLE hdsData; /* Length of each list */ DWORD readfds_len; DWORD writefds_len; DWORD exceptfds_len; CAMLparam4 (readfds, writefds, exceptfds, timeout); CAMLlocal5 (read_list, write_list, except_list, res, l); CAMLlocal1 (fd); #ifdef DBUG dbug_print("in select"); #endif nEventsCount = 0; nEventsMax = 0; lpEventsDone = NULL; lpSelectData = NULL; iterSelectData = NULL; iterResult = NULL; err = 0; hasStaticData = 0; waitRet = 0; readfds_len = caml_list_length(readfds); writefds_len = caml_list_length(writefds); exceptfds_len = caml_list_length(exceptfds); hdsMax = MAX(readfds_len, MAX(writefds_len, exceptfds_len)); if (!HeapLock(GetProcessHeap())) { win32_maperr(GetLastError()); uerror("select", Nothing); } hdsData = (HANDLE *)HeapAlloc( GetProcessHeap(), 0, sizeof(HANDLE) * hdsMax); HeapUnlock(GetProcessHeap()); if (Double_val(timeout) >= 0.0) { milliseconds = 1000 * Double_val(timeout); #ifdef DBUG dbug_print("Will wait %d ms", milliseconds); #endif } else { milliseconds = INFINITE; } /* Create list of select data, based on the different list of fd to watch */ #ifdef DBUG dbug_print("Dispatch read fd"); #endif handle_set_init(&hds, hdsData, hdsMax); for (l = readfds; l != Val_int(0); l = Field(l, 1)) { fd = Field(l, 0); if (!handle_set_mem(&hds, Handle_val(fd))) { handle_set_add(&hds, Handle_val(fd)); lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_READ, fd); } else { #ifdef DBUG dbug_print("Discarding handle %x which is already monitor for read", Handle_val(fd)); #endif } } handle_set_reset(&hds); #ifdef DBUG dbug_print("Dispatch write fd"); #endif handle_set_init(&hds, hdsData, hdsMax); for (l = writefds; l != Val_int(0); l = Field(l, 1)) { fd = Field(l, 0); if (!handle_set_mem(&hds, Handle_val(fd))) { handle_set_add(&hds, Handle_val(fd)); lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_WRITE, fd); } else { #ifdef DBUG dbug_print("Discarding handle %x which is already monitor for write", Handle_val(fd)); #endif } } handle_set_reset(&hds); #ifdef DBUG dbug_print("Dispatch exceptional fd"); #endif handle_set_init(&hds, hdsData, hdsMax); for (l = exceptfds; l != Val_int(0); l = Field(l, 1)) { fd = Field(l, 0); if (!handle_set_mem(&hds, Handle_val(fd))) { handle_set_add(&hds, Handle_val(fd)); lpSelectData = select_data_dispatch(lpSelectData, SELECT_MODE_EXCEPT, fd); } else { #ifdef DBUG dbug_print("Discarding handle %x which is already monitor for exceptional", Handle_val(fd)); #endif } } handle_set_reset(&hds); /* Building the list of handle to wait for */ #ifdef DBUG dbug_print("Building events done array"); #endif nEventsMax = list_length((LPLIST)lpSelectData); nEventsCount = 0; if (!HeapLock(GetProcessHeap())) { win32_maperr(GetLastError()); uerror("select", Nothing); } lpEventsDone = (HANDLE *)HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * nEventsMax); HeapUnlock(GetProcessHeap()); iterSelectData = lpSelectData; while (iterSelectData != NULL) { /* Check if it is static data. If this is the case, launch everything * but don't wait for events. It helps to test if there are events on * any other fd (which are not static), knowing that there is at least * one result (the static data). */ if (iterSelectData->EType == SELECT_TYPE_STATIC) { hasStaticData = TRUE; }; /* Execute APC */ if (iterSelectData->funcWorker != NULL) { iterSelectData->lpWorker = worker_job_submit( iterSelectData->funcWorker, (void *)iterSelectData); #ifdef DBUG dbug_print("Job submitted to worker %x", iterSelectData->lpWorker); #endif lpEventsDone[nEventsCount] = worker_job_event_done(iterSelectData->lpWorker); nEventsCount++; }; iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData); }; #ifdef DBUG dbug_print("Need to watch %d workers", nEventsCount); #endif /* Processing select itself */ enter_blocking_section(); /* There are worker started, waiting to be monitored */ if (nEventsCount > 0) { /* Waiting for event */ if (err == 0 && !hasStaticData) { #ifdef DBUG dbug_print("Waiting for one select worker to be done"); #endif switch (WaitForMultipleObjects(nEventsCount, lpEventsDone, FALSE, milliseconds)) { case WAIT_FAILED: err = GetLastError(); break; case WAIT_TIMEOUT: #ifdef DBUG dbug_print("Select timeout"); #endif break; default: #ifdef DBUG dbug_print("One worker is done"); #endif break; }; } /* Ordering stop to every worker */ #ifdef DBUG dbug_print("Sending stop signal to every select workers"); #endif iterSelectData = lpSelectData; while (iterSelectData != NULL) { if (iterSelectData->lpWorker != NULL) { worker_job_stop(iterSelectData->lpWorker); }; iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData); }; #ifdef DBUG dbug_print("Waiting for every select worker to be done"); #endif switch (WaitForMultipleObjects(nEventsCount, lpEventsDone, TRUE, INFINITE)) { case WAIT_FAILED: err = GetLastError(); break; default: #ifdef DBUG dbug_print("Every worker is done"); #endif break; } } /* Nothing to monitor but some time to wait. */ else if (!hasStaticData) { Sleep(milliseconds); } leave_blocking_section(); #ifdef DBUG dbug_print("Error status: %d (0 is ok)", err); #endif /* Build results */ if (err == 0) { #ifdef DBUG dbug_print("Building result"); #endif read_list = Val_unit; write_list = Val_unit; except_list = Val_unit; iterSelectData = lpSelectData; while (iterSelectData != NULL) { for (i = 0; i < iterSelectData->nResultsCount; i++) { iterResult = &(iterSelectData->aResults[i]); l = alloc_small(2, 0); Store_field(l, 0, (value)iterResult->lpOrig); switch (iterResult->EMode) { case SELECT_MODE_READ: Store_field(l, 1, read_list); read_list = l; break; case SELECT_MODE_WRITE: Store_field(l, 1, write_list); write_list = l; break; case SELECT_MODE_EXCEPT: Store_field(l, 1, except_list); except_list = l; break; } } /* We try to only process the first error, bypass other errors */ if (err == 0 && iterSelectData->EState == SELECT_STATE_ERROR) { err = iterSelectData->nError; } iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData); } } /* Free resources */ #ifdef DBUG dbug_print("Free selectdata resources"); #endif iterSelectData = lpSelectData; while (iterSelectData != NULL) { lpSelectData = iterSelectData; iterSelectData = LIST_NEXT(LPSELECTDATA, iterSelectData); select_data_free(lpSelectData); } lpSelectData = NULL; /* Free allocated events/handle set array */ #ifdef DBUG dbug_print("Free local allocated resources"); #endif if (!HeapLock(GetProcessHeap())) { win32_maperr(GetLastError()); uerror("select", Nothing); } HeapFree(GetProcessHeap(), 0, lpEventsDone); HeapFree(GetProcessHeap(), 0, hdsData); HeapUnlock(GetProcessHeap()); #ifdef DBUG dbug_print("Raise error if required"); #endif if (err != 0) { win32_maperr(err); uerror("select", Nothing); } #ifdef DBUG dbug_print("Build final result"); #endif res = alloc_small(3, 0); Store_field(res, 0, read_list); Store_field(res, 1, write_list); Store_field(res, 2, except_list); #ifdef DBUG dbug_print("out select"); #endif CAMLreturn(res); }