1//= llvm/Support/Win32/Mutex.inc - Win32 Reader/Writer Mutual Exclusion Lock  =//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Win32 specific (non-pthread) RWMutex class.
11//
12//===----------------------------------------------------------------------===//
13
14//===----------------------------------------------------------------------===//
15//=== WARNING: Implementation here must contain only generic Win32 code that
16//===          is guaranteed to work on *all* Win32 variants.
17//===----------------------------------------------------------------------===//
18
19#include "WindowsSupport.h"
20
21namespace llvm {
22
23// Windows has slim read-writer lock support on Vista and higher, so we
24// will attempt to load the APIs.  If they exist, we will use them, and
25// if not, we will fall back on critical sections.  When we drop support
26// for XP, we can stop lazy-loading these APIs and just use them directly.
27#if defined(__MINGW32__)
28  // Taken from WinNT.h
29  typedef struct _RTL_SRWLOCK {
30    PVOID Ptr;
31  } RTL_SRWLOCK, *PRTL_SRWLOCK;
32
33  // Taken from WinBase.h
34  typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
35#endif
36
37static VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL;
38static VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL;
39static VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL;
40static VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL;
41static VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL;
42
43static bool sHasSRW = false;
44
45static bool loadSRW() {
46  static bool sChecked = false;
47  if (!sChecked) {
48    sChecked = true;
49
50    if (HMODULE hLib = ::GetModuleHandleW(L"Kernel32.dll")) {
51      fpInitializeSRWLock =
52        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
53                                               "InitializeSRWLock");
54      fpAcquireSRWLockExclusive =
55        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
56                                               "AcquireSRWLockExclusive");
57      fpAcquireSRWLockShared =
58        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
59                                               "AcquireSRWLockShared");
60      fpReleaseSRWLockExclusive =
61        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
62                                               "ReleaseSRWLockExclusive");
63      fpReleaseSRWLockShared =
64        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
65                                               "ReleaseSRWLockShared");
66
67      if (fpInitializeSRWLock != NULL) {
68        sHasSRW = true;
69      }
70    }
71  }
72  return sHasSRW;
73}
74
75sys::RWMutexImpl::RWMutexImpl() {
76  if (loadSRW()) {
77    data_ = safe_calloc(1, sizeof(SRWLOCK));
78    fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
79  } else {
80    data_ = safe_calloc(1, sizeof(CRITICAL_SECTION));
81    InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
82  }
83}
84
85sys::RWMutexImpl::~RWMutexImpl() {
86  if (!sHasSRW)
87    DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
88  // Nothing to do in the case of slim reader/writers except free the memory.
89  free(data_);
90}
91
92bool sys::RWMutexImpl::reader_acquire() {
93  if (sHasSRW) {
94    fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_));
95  } else {
96    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
97  }
98  return true;
99}
100
101bool sys::RWMutexImpl::reader_release() {
102  if (sHasSRW) {
103    fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_));
104  } else {
105    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
106  }
107  return true;
108}
109
110bool sys::RWMutexImpl::writer_acquire() {
111  if (sHasSRW) {
112    fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_));
113  } else {
114    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
115  }
116  return true;
117}
118
119bool sys::RWMutexImpl::writer_release() {
120  if (sHasSRW) {
121    fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_));
122  } else {
123    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
124  }
125  return true;
126}
127
128
129}
130