//----------------------------------------------------------------------------- // Wrap an unsafe call in a mutex to assure safety // Biggest error issues are: // 1. Timeout (probably handler doesn't exist) // 2. Handler can be destroyed at any time. //----------------------------------------------------------------------------- IPCFuncCallSource::EError IPCFuncCallSource::DoThreadSafeCall() { DWORD dwErr; EError err = Ok; #if defined(ENABLE_TIMING) g_time.Reset(); g_time.Start(); #endif HANDLE hStartEnum = NULL; HANDLE hDoneEnum = NULL; HANDLE hWrapCall = NULL; DWORD dwWaitRet; // Check if we have a handler (handler creates the events) and // abort if not. Do this check asap to optimize the most common // case of no handler. hStartEnum = WszOpenEvent(EVENT_ALL_ACCESS, FALSE, FixupName(StartEnumEventName)); if (hStartEnum == NULL) { dwErr = GetLastError(); err = Fail_NoHandler; goto errExit; } hDoneEnum = WszOpenEvent(EVENT_ALL_ACCESS, FALSE, FixupName(DoneEnumEventName)); if (hDoneEnum == NULL) { dwErr = GetLastError(); err = Fail_NoHandler; goto errExit; } // Need to create the mutex hWrapCall = WszCreateMutex(NULL, FALSE, FixupName(WrapMutexName)); if (hWrapCall == NULL) { dwErr = GetLastError(); err = Fail_CreateMutex; goto errExit; } // Wait for our turn dwWaitRet = WaitForSingleObject(hWrapCall, START_ENUM_TIMEOUT); dwErr = GetLastError(); switch(dwWaitRet) { case WAIT_OBJECT_0: // Good case. All other cases are errors and goto errExit. break; case WAIT_TIMEOUT: err = Fail_Timeout_Lock; goto errExit; break; default: err = Failed; goto errExit; break; } // Our turn: Make the function call { BOOL fSetOK = 0; // Reset the 'Done event' to make sure that Handler sets it after they start. ResetEvent(hDoneEnum); dwErr = GetLastError(); // Signal Handler to execute callback fSetOK = SetEvent(hStartEnum); dwErr = GetLastError(); // Now wait for handler to finish. dwWaitRet = WaitForSingleObject(hDoneEnum, START_ENUM_TIMEOUT); dwErr = GetLastError(); switch (dwWaitRet) { case WAIT_OBJECT_0: break; case WAIT_TIMEOUT: err = Fail_Timeout_Call; break; default: err = Failed; break; } ReleaseMutex(hWrapCall); dwErr = GetLastError(); } // End function call errExit: // Close all handles if (hStartEnum != NULL) { CloseHandle(hStartEnum); hStartEnum = NULL; } if (hDoneEnum != NULL) { CloseHandle(hDoneEnum); hDoneEnum = NULL; } if (hWrapCall != NULL) { CloseHandle(hWrapCall); hWrapCall = NULL; } #if defined(ENABLE_TIMING) g_time.End(); DWORD dwTime = g_time.GetEllapsedMS(); #endif return err; }