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
24226890Sdim// Windows has slim read-writer lock support on Vista and higher, so we
25226890Sdim// will attempt to load the APIs.  If they exist, we will use them, and
26226890Sdim// if not, we will fall back on critical sections.  When we drop support
27226890Sdim// for XP, we can stop lazy-loading these APIs and just use them directly.
28226890Sdim#if defined(__MINGW32__)
29226890Sdim  // Taken from WinNT.h
30226890Sdim  typedef struct _RTL_SRWLOCK {
31226890Sdim    PVOID Ptr;
32226890Sdim  } RTL_SRWLOCK, *PRTL_SRWLOCK;
33226890Sdim
34226890Sdim  // Taken from WinBase.h
35226890Sdim  typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
36226890Sdim#endif
37226890Sdim
38226890Sdimstatic VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL;
39226890Sdimstatic VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL;
40226890Sdimstatic VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL;
41226890Sdimstatic VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL;
42226890Sdimstatic VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL;
43226890Sdim
44226890Sdimstatic bool sHasSRW = false;
45226890Sdim
46226890Sdimstatic bool loadSRW() {
47226890Sdim  static bool sChecked = false;
48226890Sdim  if (!sChecked) {
49226890Sdim    sChecked = true;
50226890Sdim
51263509Sdim    if (HMODULE hLib = ::GetModuleHandleW(L"Kernel32.dll")) {
52226890Sdim      fpInitializeSRWLock =
53226890Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
54226890Sdim                                               "InitializeSRWLock");
55226890Sdim      fpAcquireSRWLockExclusive =
56226890Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
57226890Sdim                                               "AcquireSRWLockExclusive");
58226890Sdim      fpAcquireSRWLockShared =
59226890Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
60226890Sdim                                               "AcquireSRWLockShared");
61226890Sdim      fpReleaseSRWLockExclusive =
62226890Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
63226890Sdim                                               "ReleaseSRWLockExclusive");
64226890Sdim      fpReleaseSRWLockShared =
65226890Sdim        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
66226890Sdim                                               "ReleaseSRWLockShared");
67226890Sdim
68245431Sdim      if (fpInitializeSRWLock != NULL) {
69245431Sdim        sHasSRW = true;
70245431Sdim      }
71226890Sdim    }
72226890Sdim  }
73226890Sdim  return sHasSRW;
74226890Sdim}
75226890Sdim
76218885SdimRWMutexImpl::RWMutexImpl() {
77226890Sdim  if (loadSRW()) {
78226890Sdim    data_ = calloc(1, sizeof(SRWLOCK));
79226890Sdim    fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
80226890Sdim  } else {
81226890Sdim    data_ = calloc(1, sizeof(CRITICAL_SECTION));
82226890Sdim    InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
83226890Sdim  }
84218885Sdim}
85218885Sdim
86218885SdimRWMutexImpl::~RWMutexImpl() {
87226890Sdim  if (sHasSRW) {
88226890Sdim    // Nothing to do in the case of slim reader/writers
89226890Sdim  } else {
90226890Sdim    DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
91226890Sdim    free(data_);
92226890Sdim  }
93218885Sdim}
94218885Sdim
95218885Sdimbool RWMutexImpl::reader_acquire() {
96226890Sdim  if (sHasSRW) {
97226890Sdim    fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_));
98226890Sdim  } else {
99226890Sdim    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
100226890Sdim  }
101218885Sdim  return true;
102218885Sdim}
103218885Sdim
104218885Sdimbool RWMutexImpl::reader_release() {
105226890Sdim  if (sHasSRW) {
106226890Sdim    fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_));
107226890Sdim  } else {
108226890Sdim    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
109226890Sdim  }
110218885Sdim  return true;
111218885Sdim}
112218885Sdim
113218885Sdimbool RWMutexImpl::writer_acquire() {
114226890Sdim  if (sHasSRW) {
115226890Sdim    fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_));
116226890Sdim  } else {
117226890Sdim    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
118226890Sdim  }
119218885Sdim  return true;
120218885Sdim}
121218885Sdim
122218885Sdimbool RWMutexImpl::writer_release() {
123226890Sdim  if (sHasSRW) {
124226890Sdim    fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_));
125226890Sdim  } else {
126226890Sdim    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
127226890Sdim  }
128218885Sdim  return true;
129218885Sdim}
130218885Sdim
131218885Sdim
132218885Sdim}
133