| #ifdef _WIN32 |
| |
| #include "lldb/Host/ProcessRunLock.h" |
| #include "lldb/Host/windows/windows.h" |
| |
| namespace lldb_private { |
| |
| // Windows has slim read-writer lock support on Vista and higher, so we |
| // will attempt to load the APIs. If they exist, we will use them, and |
| // if not, we will fall back on critical sections. When we drop support |
| // for XP, we can stop lazy-loading these APIs and just use them directly. |
| #if defined(__MINGW32__) |
| // Taken from WinNT.h |
| typedef struct _RTL_SRWLOCK { |
| PVOID Ptr; |
| } RTL_SRWLOCK, *PRTL_SRWLOCK; |
| |
| // Taken from WinBase.h |
| typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; |
| #endif |
| |
| |
| typedef struct Win32RWLOCK |
| { |
| long int readlockcount; |
| HANDLE writable; |
| CRITICAL_SECTION writelock; |
| long int writelocked; |
| } Win32RWLOCK; |
| |
| typedef Win32RWLOCK* PWin32RWLOCK; |
| |
| static VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL; |
| static VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL; |
| static VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL; |
| static VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL; |
| static VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL; |
| static BOOL (WINAPI *fpTryAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL; |
| static BOOL (WINAPI *fpTryAcquireSRWLockShared)(PSRWLOCK lock) = NULL; |
| |
| static bool sHasSRW = false; |
| |
| static bool loadSRW() |
| { |
| static bool sChecked = false; |
| if (!sChecked) |
| { |
| sChecked = true; |
| return false; |
| |
| HMODULE hLib = ::LoadLibrary(TEXT("Kernel32")); |
| if (hLib) |
| { |
| fpInitializeSRWLock = |
| (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, |
| "InitializeSRWLock"); |
| fpAcquireSRWLockExclusive = |
| (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, |
| "AcquireSRWLockExclusive"); |
| fpAcquireSRWLockShared = |
| (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, |
| "AcquireSRWLockShared"); |
| fpReleaseSRWLockExclusive = |
| (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, |
| "ReleaseSRWLockExclusive"); |
| fpReleaseSRWLockShared = |
| (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, |
| "ReleaseSRWLockShared"); |
| fpTryAcquireSRWLockExclusive = |
| (BOOL (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, |
| "TryAcquireSRWLockExclusive"); |
| fpTryAcquireSRWLockShared = |
| (BOOL (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib, |
| "TryAcquireSRWLockShared"); |
| |
| ::FreeLibrary(hLib); |
| |
| if (fpInitializeSRWLock != NULL) { |
| sHasSRW = true; |
| } |
| } |
| } |
| return sHasSRW; |
| } |
| |
| ProcessRunLock::ProcessRunLock () |
| : m_running(false) |
| { |
| if (loadSRW()) |
| { |
| m_rwlock = calloc(1, sizeof(SRWLOCK)); |
| fpInitializeSRWLock(static_cast<PSRWLOCK>(m_rwlock)); |
| } |
| else |
| { |
| m_rwlock = calloc(1, sizeof(Win32RWLOCK)); |
| static_cast<PWin32RWLOCK>(m_rwlock)->readlockcount = 0; |
| static_cast<PWin32RWLOCK>(m_rwlock)->writable = CreateEvent(NULL, true, true, NULL); |
| InitializeCriticalSection(&static_cast<PWin32RWLOCK>(m_rwlock)->writelock); |
| } |
| } |
| |
| ProcessRunLock::~ProcessRunLock () |
| { |
| if (!sHasSRW) |
| { |
| CloseHandle(static_cast<PWin32RWLOCK>(m_rwlock)->writable); |
| DeleteCriticalSection(&static_cast<PWin32RWLOCK>(m_rwlock)->writelock); |
| } |
| free(m_rwlock); |
| } |
| |
| bool ReadLock (lldb::rwlock_t rwlock) |
| { |
| if (sHasSRW) |
| { |
| fpAcquireSRWLockShared(static_cast<PSRWLOCK>(rwlock)); |
| return true; |
| } |
| else |
| { |
| EnterCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock); |
| InterlockedIncrement(&static_cast<PWin32RWLOCK>(rwlock)->readlockcount); |
| ResetEvent(static_cast<PWin32RWLOCK>(rwlock)->writable); |
| LeaveCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock); |
| return true; |
| } |
| } |
| |
| bool ProcessRunLock::ReadTryLock () |
| { |
| ReadLock(m_rwlock); |
| if (m_running == false) |
| return true; |
| ReadUnlock(); |
| return false; |
| } |
| |
| bool ProcessRunLock::ReadUnlock () |
| { |
| if (sHasSRW) |
| { |
| fpReleaseSRWLockShared(static_cast<PSRWLOCK>(m_rwlock)); |
| return true; |
| } |
| else |
| { |
| unsigned long int value = InterlockedDecrement(&static_cast<PWin32RWLOCK>(m_rwlock)->readlockcount); |
| assert(((int)value) >= 0); |
| if (value == 0) |
| SetEvent(static_cast<PWin32RWLOCK>(m_rwlock)->writable); |
| return true; |
| } |
| } |
| |
| bool WriteLock(lldb::rwlock_t rwlock) |
| { |
| if (sHasSRW) |
| { |
| fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(rwlock)); |
| return true; |
| } |
| else |
| { |
| EnterCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock); |
| WaitForSingleObject(static_cast<PWin32RWLOCK>(rwlock)->writable, INFINITE); |
| int res = InterlockedExchange(&static_cast<PWin32RWLOCK>(rwlock)->writelocked, 1); |
| assert(res == 0); |
| return true; |
| } |
| } |
| |
| bool WriteTryLock(lldb::rwlock_t rwlock) |
| { |
| if (sHasSRW) |
| { |
| return fpTryAcquireSRWLockExclusive(static_cast<PSRWLOCK>(rwlock)) != 0; |
| } |
| else |
| { |
| if (TryEnterCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock)) { |
| if (WaitForSingleObject(static_cast<PWin32RWLOCK>(rwlock)->writable, 0)) { |
| LeaveCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock); |
| return false; |
| } |
| int res = InterlockedExchange(&static_cast<PWin32RWLOCK>(rwlock)->writelocked, 1); |
| assert(res == 0); |
| return true; |
| } |
| return false; |
| } |
| } |
| |
| bool WriteUnlock(lldb::rwlock_t rwlock) |
| { |
| if (sHasSRW) |
| { |
| fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(rwlock)); |
| return true; |
| } |
| else |
| { |
| int res = InterlockedExchange(&static_cast<PWin32RWLOCK>(rwlock)->writelocked, 0); |
| if (res == 1) { |
| LeaveCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock); |
| return true; |
| } |
| return false; |
| } |
| } |
| |
| bool ProcessRunLock::SetRunning () |
| { |
| WriteLock(m_rwlock); |
| m_running = true; |
| WriteUnlock(m_rwlock); |
| return true; |
| } |
| |
| bool ProcessRunLock::TrySetRunning () |
| { |
| if (WriteTryLock(m_rwlock)) |
| { |
| bool r = !m_running; |
| m_running = true; |
| WriteUnlock(m_rwlock); |
| return r; |
| } |
| return false; |
| } |
| |
| bool ProcessRunLock::SetStopped () |
| { |
| WriteLock(m_rwlock); |
| m_running = false; |
| WriteUnlock(m_rwlock); |
| return true; |
| } |
| } |
| |
| #endif |