/*++ Function: ResetEvent See MSDN doc. --*/ BOOL PALAPI ResetEvent( IN HANDLE hEvent) { BOOL bRet = TRUE; Event *pEvent; GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo; PERF_ENTRY(ResetEvent); ENTRY("ResetEvent(hEvent=%p)\n", hEvent); pEvent = (Event *) HMGRLockHandle2(hEvent, HOBJ_EVENT); SHMLock(); if ( pEvent == NULL ) { ERROR("Invalid handle\n"); SetLastError(ERROR_INVALID_HANDLE); bRet = FALSE; } else { pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(pEvent->info); if (pEventInfo == NULL) { ASSERT("Invalid shared memory pointer\n"); SetLastError(ERROR_INTERNAL_ERROR); SHMRelease(); HMGRUnlockHandle(hEvent, &pEvent->objHeader); LOGEXIT("ResetEvent returns BOOL FALSE\n"); PERF_EXIT(ResetEvent); return FALSE; } pEventInfo->state = FALSE; TRACE("Event(%p) being reset.\n", hEvent); } SHMRelease(); if( NULL != pEvent) { HMGRUnlockHandle(hEvent, &pEvent->objHeader); } LOGEXIT("ResetEvent returns BOOL %d\n", bRet); PERF_EXIT(ResetEvent); return bRet; }
/*++ Function: GetThreadContext See MSDN doc. --*/ BOOL CONTEXT_GetThreadContext( HANDLE hThread, LPCONTEXT lpContext) { BOOL ret = FALSE; DWORD processId; #if HAVE_GETCONTEXT ucontext_t registers; #elif HAVE_BSD_REGS_T struct reg registers; #endif // HAVE_BSD_REGS_T if (lpContext == NULL) { ERROR("Invalid lpContext parameter value\n"); SetLastError(ERROR_NOACCESS); goto EXIT; } /* How to consider the case when hThread is different from the current thread of its owner process. Machine registers values could be retreived by a ptrace(pid, ...) call or from the "/proc/%pid/reg" file content. Unfortunately, these two methods only depend on process ID, not on thread ID. */ if (!(processId = THREADGetThreadProcessId(hThread))) { ERROR("Couldn't retrieve the process owner of hThread:%p\n", hThread); SetLastError(ERROR_INTERNAL_ERROR); goto EXIT; } if (processId == GetCurrentProcessId()) { THREAD *thread; thread = (THREAD *) HMGRLockHandle2(hThread, HOBJ_THREAD); if ((thread == NULL) || (thread->dwThreadId != GetCurrentThreadId())) { DWORD flags; // There aren't any APIs for this. We can potentially get the // context of another thread by using per-thread signals, but // on FreeBSD signal handlers that are called as a result // of signals raised via pthread_kill don't get a valid // sigcontext or ucontext_t. But we need this to return TRUE // to avoid an assertion in the CLR in code that manages to // cope reasonably well without a valid thread context. // Given that, we'll zero out our structure and return TRUE. ERROR("GetThreadContext on a thread other than the current " "thread is returning TRUE\n"); flags = lpContext->ContextFlags; memset(lpContext, 0, sizeof(*lpContext)); lpContext->ContextFlags = flags; HMGRUnlockHandle(hThread, &(thread->objHeader)); ret = TRUE; goto EXIT; } HMGRUnlockHandle(hThread, &(thread->objHeader)); } if (lpContext->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER)) { if (CONTEXT_GetRegisters(processId, ®isters) == FALSE) { SetLastError(ERROR_INTERNAL_ERROR); goto EXIT; } if (lpContext->ContextFlags & CONTEXT_CONTROL) { #if HAVE_GETCONTEXT lpContext->Ebp = registers.uc_mcontext.gregs[REG_EBP]; lpContext->Eip = registers.uc_mcontext.gregs[REG_EIP]; lpContext->SegCs = registers.uc_mcontext.gregs[REG_CS]; lpContext->EFlags = registers.uc_mcontext.gregs[REG_EFL]; lpContext->Esp = registers.uc_mcontext.gregs[REG_ESP]; lpContext->SegSs = registers.uc_mcontext.gregs[REG_SS]; #elif HAVE_BSD_REGS_T lpContext->Ebp = registers.r_ebp; lpContext->Eip = registers.r_eip; lpContext->SegCs = registers.r_cs; lpContext->EFlags = registers.r_eflags; lpContext->Esp = registers.r_esp; lpContext->SegSs = registers.r_ss; #endif // HAVE_BSD_REGS_T } if (lpContext->ContextFlags & CONTEXT_INTEGER) { #if HAVE_GETCONTEXT lpContext->Edi = registers.uc_mcontext.gregs[REG_EDI]; lpContext->Esi = registers.uc_mcontext.gregs[REG_ESI]; lpContext->Ebx = registers.uc_mcontext.gregs[REG_EBX]; lpContext->Edx = registers.uc_mcontext.gregs[REG_EDX]; lpContext->Ecx = registers.uc_mcontext.gregs[REG_ECX]; lpContext->Eax = registers.uc_mcontext.gregs[REG_EAX]; #elif HAVE_BSD_REGS_T lpContext->Edi = registers.r_edi; lpContext->Esi = registers.r_esi; lpContext->Ebx = registers.r_ebx; lpContext->Edx = registers.r_edx; lpContext->Ecx = registers.r_ecx; lpContext->Eax = registers.r_eax; #endif // HAVE_BSD_REGS_T } } ret = TRUE; EXIT: return ret; }
/*++ Function: EventRemoveWaitingThread Remove the CurrentThreadId from the list of waiting thread. This function is called when the current thread stops waiting on an Event for a different reason than the Event was signaled. (e.g. a timeout, or the thread was waiting on multiple objects and another object was signaled) Parameters: IN hEvent: event handle of the modify thread waiting list. returns -1: an error occurred 0: if the thread wasn't found in the list. 1: if the thread was removed from the waiting list. --*/ int EventRemoveWaitingThread( IN HANDLE hEvent) { Event *pEvent; GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo; int ret = 0; ThreadWaitingList *pWaitingThread; ThreadWaitingList *pNextWaitingThread; SHMPTR shmpWaitingThread; DWORD CurrentThreadId; DWORD currentPID; pEvent = (Event *) HMGRLockHandle2(hEvent, HOBJ_EVENT); SHMLock(); if ( (pEvent == NULL) || (!IsValidEventObject(pEvent)) ) { ASSERT("Invalid event handle %p\n", hEvent); SHMRelease(); return -1; } pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(pEvent->info); if (pEventInfo == NULL) { ASSERT("Invalid shared memory pointer\n"); SHMRelease(); HMGRUnlockHandle(hEvent,&pEvent->objHeader); return -1; } CurrentThreadId = GetCurrentThreadId(); currentPID = GetCurrentProcessId(); shmpWaitingThread = pEventInfo->waitingThreads; if (shmpWaitingThread == (SHMPTR) NULL) { ret = 0; /* list is empty */ goto RemoveThreadExit; } pWaitingThread = (ThreadWaitingList *) SHMPTR_TO_PTR(shmpWaitingThread); if (pWaitingThread == NULL) { ERROR("Invalid shared memory pointer\n"); ret = 0; /* list is empty */ goto RemoveThreadExit; } /* check if it is the first element in the list */ if (pWaitingThread->threadId == CurrentThreadId && pWaitingThread->processId == currentPID) { pEventInfo->waitingThreads = pWaitingThread->ptr.shmNext; SHMfree(shmpWaitingThread); ret = 1; goto RemoveThreadExit; } else { while (pWaitingThread->ptr.shmNext) { pNextWaitingThread = (ThreadWaitingList *) SHMPTR_TO_PTR(pWaitingThread->ptr.shmNext); if (pNextWaitingThread == NULL) { ERROR("Invalid shared memory pointer\n"); ret = 0; break; } if (pNextWaitingThread->threadId == CurrentThreadId && pNextWaitingThread->processId == currentPID) { /* found, so remove it */ SHMPTR pTemp; pTemp = pWaitingThread->ptr.shmNext; pWaitingThread->ptr.shmNext = pNextWaitingThread->ptr.shmNext; SHMfree (pTemp); ret = 1; break; } pWaitingThread = pNextWaitingThread; } } RemoveThreadExit: SHMRelease(); HMGRUnlockHandle(hEvent,&pEvent->objHeader); if (ret == 0) { TRACE("ThreadId=%#x was not waiting on hEvent=%p\n", CurrentThreadId, hEvent); } else if (ret == 1) { TRACE("ThreadId=%#x is no longer waiting on hEvent=%p\n", CurrentThreadId, hEvent); } return ret; }
/*++ Function: EventWaitOn Check if the event is signaled. If not signaled place the current thread to the list of waiting thread. This function is called by WaitXXXX functions when it's time to wait on a Event. The caller is responsible for blocking the thread, this function does not wait on the event. This function set the last error, if an error occured. Parameters: IN hEvent: handle of the event checked for the signaled state. SHMPTR wait_state : shared memory pointer to waiting thread's wait state returns WAITON_CODE value (see thread.h) --*/ int EventWaitOn( IN HANDLE hEvent, SHMPTR wait_state) { Event *pEvent; GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo; int ret; ThreadWaitingList *pWaitingThread; SHMPTR shmpWaitingThread; pEvent = (Event *) HMGRLockHandle2(hEvent, HOBJ_EVENT); SHMLock(); if ( pEvent == NULL ) { SetLastError(ERROR_INVALID_HANDLE); ERROR("Invalid event handle %p\n", hEvent); SHMRelease(); return WOC_ERROR; } pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(pEvent->info); if (pEventInfo == NULL) { SetLastError(ERROR_INTERNAL_ERROR); ASSERT("Invalid shared memory pointer\n"); SHMRelease(); HMGRUnlockHandle(hEvent,&pEvent->objHeader); return WOC_ERROR; } if (pEventInfo->state) { DWORD *pAwakenState; /* try to flag the thread as awakened, don't add it to the list if it already was. (this happens if an object is signaled while WFMO is still calling WaitOn()) */ pAwakenState = SHMPTR_TO_PTR(wait_state); if(!THREADInterlockedAwaken(pAwakenState,FALSE)) { TRACE("thread is already awake; not waiting on it\n"); ret = WOC_INTERUPTED; } else { TRACE("Event(%p) is signaled, not waiting\n", hEvent); ret = WOC_SIGNALED; /* reset the event, if it's not a manual reset event */ if (pEventInfo->manualReset == FALSE) { pEventInfo->state = FALSE; } } } else { /* this structure needs to be allocated in the shared memory in term of supporting event for inter-process synchronization */ /* add the current thread to the list of waiting threads */ shmpWaitingThread = SHMalloc(sizeof(ThreadWaitingList)); if (shmpWaitingThread == (SHMPTR) NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); ERROR("Not enough memory to allocate a ThreadWaitingList\n"); ret = WOC_ERROR; } else { pWaitingThread = (ThreadWaitingList *) SHMPTR_TO_PTR(shmpWaitingThread); pWaitingThread->threadId = GetCurrentThreadId(); pWaitingThread->processId = GetCurrentProcessId(); pWaitingThread->blockingPipe = THREADGetPipe(); pWaitingThread->ptr.shmNext = (SHMPTR) NULL; pWaitingThread->state.shmAwakened = wait_state; TRACE("ThreadId=%#x will wait on hEvent=%p\n", pWaitingThread->threadId, hEvent); /* place the thread at the end of the list */ if (pEventInfo->waitingThreads == (SHMPTR) NULL) { pEventInfo->waitingThreads = shmpWaitingThread; } else { ThreadWaitingList *pIter; ThreadWaitingList *pNext; pIter = (ThreadWaitingList *) SHMPTR_TO_PTR(pEventInfo->waitingThreads); while (pIter && pIter->ptr.shmNext) { pNext = (ThreadWaitingList *) SHMPTR_TO_PTR(pIter->ptr.shmNext); if (NULL == pNext) { ERROR("Invalid shared memory pointer\n"); /* the list is corrupted, but let's try to keep going anyway with the part that's still good */ pIter->ptr.shmNext = 0; } else { pIter = pNext; } } if(NULL == pIter) { ERROR("Invalid shared memory pointer\n"); /* the list is completely corrupted... start a new one */ pEventInfo->waitingThreads = shmpWaitingThread; } else { pIter->ptr.shmNext = shmpWaitingThread; } } TRACE("Event(%p) is not signaled," " current thread added to the waiting list\n", hEvent); ret = WOC_WAITING; } } SHMRelease(); HMGRUnlockHandle(hEvent,&pEvent->objHeader); return ret; }
/*++ Function: SetEvent See MSDN doc. --*/ BOOL PALAPI SetEvent( IN HANDLE hEvent) { BOOL bRet = TRUE; Event *pEvent; GLOBAL_EVENT_SYSTEM_OBJECT *pEventInfo; SHMPTR pTemp; ThreadWaitingList *pWaitingThread; PERF_ENTRY(SetEvent); ENTRY("SetEvent(hEvent=%p)\n", hEvent); pEvent = (Event *) HMGRLockHandle2(hEvent, HOBJ_EVENT); if(NULL == pEvent) { ERROR("Unable to lock handle %p!\n", hEvent); SetLastError(ERROR_INVALID_HANDLE); LOGEXIT("SetEvent returns BOOL %d\n",FALSE); PERF_EXIT(SetEvent); return FALSE; } SHMLock(); pEventInfo = (GLOBAL_EVENT_SYSTEM_OBJECT*) SHMPTR_TO_PTR(pEvent->info); if (pEventInfo == NULL) { ASSERT("Invalid shared memory pointer\n"); SetLastError(ERROR_INTERNAL_ERROR); bRet = FALSE; goto SetEventExit; } if (!pEventInfo->state) { DWORD *pAwakenState; SHMPTR shmWaitingThread; ThreadWaitingList *prevThread = NULL; pEventInfo->state = TRUE; shmWaitingThread = pEventInfo->waitingThreads; /* wake up waiting threads */ while (shmWaitingThread) { pWaitingThread = SHMPTR_TO_PTR(shmWaitingThread); if (pWaitingThread == NULL) { ASSERT("Invalid shared memory pointer\n"); SetLastError(ERROR_INTERNAL_ERROR); bRet = FALSE; goto SetEventExit; } /* check whether thread is already awake. this can happen if another object already woke up the thread, but the thread hasn't yet had time to remove itself from all waiting lists. */ pAwakenState = SHMPTR_TO_PTR(pWaitingThread->state.shmAwakened); if(!THREADInterlockedAwaken(pAwakenState, FALSE)) { TRACE("thread is already awake, skipping it\n"); prevThread = pWaitingThread; shmWaitingThread = pWaitingThread->ptr.shmNext; continue; } /* remove thread from waiting list */ pTemp = shmWaitingThread; shmWaitingThread = pWaitingThread->ptr.shmNext; if(NULL == prevThread) { pEventInfo->waitingThreads = shmWaitingThread; } else { prevThread->ptr.shmNext = shmWaitingThread; } TRACE("Waking up thread(%#x) Event has been set (%p)\n", pWaitingThread->threadId, hEvent); WakeUpThread(pWaitingThread->threadId, pWaitingThread->processId, pWaitingThread->blockingPipe, WUTC_SIGNALED ); SHMfree(pTemp); /* if the event is auto-reset, we only want to wake up one thread, so break out.*/ if (pEventInfo->manualReset == FALSE) { pEventInfo->state = FALSE; break; } } } SetEventExit: SHMRelease(); HMGRUnlockHandle(hEvent, &pEvent->objHeader); LOGEXIT("SetEvent returns BOOL %d\n", bRet); PERF_EXIT(SetEvent); return bRet; }