RWMutex.inc revision 239462
1218885Sdim//= llvm/Support/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock  =//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file implements the Win32 specific (non-pthread) RWMutex class.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim//===----------------------------------------------------------------------===//
15218885Sdim//=== WARNING: Implementation here must contain only generic Win32 code that
16218885Sdim//===          is guaranteed to work on *all* Win32 variants.
17218885Sdim//===----------------------------------------------------------------------===//
18218885Sdim
19218885Sdim#include "Windows.h"
20218885Sdim
21218885Sdimnamespace llvm {
22218885Sdimusing namespace sys;
23218885Sdim
24226633Sdim// Windows has slim read-writer lock support on Vista and higher, so we
25226633Sdim// will attempt to load the APIs.  If they exist, we will use them, and
26226633Sdim// if not, we will fall back on critical sections.  When we drop support
27226633Sdim// for XP, we can stop lazy-loading these APIs and just use them directly.
28226633Sdim#if defined(__MINGW32__)
29226633Sdim  // Taken from WinNT.h
30226633Sdim  typedef struct _RTL_SRWLOCK {
31226633Sdim    PVOID Ptr;
32226633Sdim  } RTL_SRWLOCK, *PRTL_SRWLOCK;
33226633Sdim
34226633Sdim  // Taken from WinBase.h
35226633Sdim  typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
36226633Sdim#endif
37226633Sdim
38226633Sdimstatic VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL;
39226633Sdimstatic VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL;
40226633Sdimstatic VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL;
41226633Sdimstatic VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL;
42226633Sdimstatic VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL;
43226633Sdim
44226633Sdimstatic bool sHasSRW = false;
45226633Sdim
46226633Sdimstatic bool loadSRW() {
47226633Sdim  static bool sChecked = false;
48226633Sdim  if (!sChecked) {
49226633Sdim    sChecked = true;
50226633Sdim
51226633Sdim    HMODULE hLib = ::LoadLibrary(TEXT("Kernel32"));
52226633Sdim    if (hLib) {
53226633Sdim      fpInitializeSRWLock =
54226633Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
55226633Sdim                                               "InitializeSRWLock");
56226633Sdim      fpAcquireSRWLockExclusive =
57226633Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
58226633Sdim                                               "AcquireSRWLockExclusive");
59226633Sdim      fpAcquireSRWLockShared =
60226633Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
61226633Sdim                                               "AcquireSRWLockShared");
62226633Sdim      fpReleaseSRWLockExclusive =
63226633Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
64226633Sdim                                               "ReleaseSRWLockExclusive");
65226633Sdim      fpReleaseSRWLockShared =
66226633Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
67226633Sdim                                               "ReleaseSRWLockShared");
68226633Sdim      ::FreeLibrary(hLib);
69226633Sdim
70239462Sdim      if (fpInitializeSRWLock != NULL) {
71239462Sdim        sHasSRW = true;
72239462Sdim      }
73226633Sdim    }
74226633Sdim  }
75226633Sdim  return sHasSRW;
76226633Sdim}
77226633Sdim
78218885SdimRWMutexImpl::RWMutexImpl() {
79226633Sdim  if (loadSRW()) {
80226633Sdim    data_ = calloc(1, sizeof(SRWLOCK));
81226633Sdim    fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
82226633Sdim  } else {
83226633Sdim    data_ = calloc(1, sizeof(CRITICAL_SECTION));
84226633Sdim    InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
85226633Sdim  }
86218885Sdim}
87218885Sdim
88218885SdimRWMutexImpl::~RWMutexImpl() {
89226633Sdim  if (sHasSRW) {
90226633Sdim    // Nothing to do in the case of slim reader/writers
91226633Sdim  } else {
92226633Sdim    DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
93226633Sdim    free(data_);
94226633Sdim  }
95218885Sdim}
96218885Sdim
97218885Sdimbool RWMutexImpl::reader_acquire() {
98226633Sdim  if (sHasSRW) {
99226633Sdim    fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_));
100226633Sdim  } else {
101226633Sdim    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
102226633Sdim  }
103218885Sdim  return true;
104218885Sdim}
105218885Sdim
106218885Sdimbool RWMutexImpl::reader_release() {
107226633Sdim  if (sHasSRW) {
108226633Sdim    fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_));
109226633Sdim  } else {
110226633Sdim    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
111226633Sdim  }
112218885Sdim  return true;
113218885Sdim}
114218885Sdim
115218885Sdimbool RWMutexImpl::writer_acquire() {
116226633Sdim  if (sHasSRW) {
117226633Sdim    fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_));
118226633Sdim  } else {
119226633Sdim    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
120226633Sdim  }
121218885Sdim  return true;
122218885Sdim}
123218885Sdim
124218885Sdimbool RWMutexImpl::writer_release() {
125226633Sdim  if (sHasSRW) {
126226633Sdim    fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_));
127226633Sdim  } else {
128226633Sdim    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
129226633Sdim  }
130218885Sdim  return true;
131218885Sdim}
132218885Sdim
133218885Sdim
134218885Sdim}
135