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 {
22using namespace sys;
23
24// Windows has slim read-writer lock support on Vista and higher, so we
25// will attempt to load the APIs.  If they exist, we will use them, and
26// if not, we will fall back on critical sections.  When we drop support
27// for XP, we can stop lazy-loading these APIs and just use them directly.
28#if defined(__MINGW32__)
29  // Taken from WinNT.h
30  typedef struct _RTL_SRWLOCK {
31    PVOID Ptr;
32  } RTL_SRWLOCK, *PRTL_SRWLOCK;
33
34  // Taken from WinBase.h
35  typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
36#endif
37
38static VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL;
39static VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL;
40static VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL;
41static VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL;
42static VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL;
43
44static bool sHasSRW = false;
45
46static bool loadSRW() {
47  static bool sChecked = false;
48  if (!sChecked) {
49    sChecked = true;
50
51    if (HMODULE hLib = ::GetModuleHandleW(L"Kernel32.dll")) {
52      fpInitializeSRWLock =
53        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
54                                               "InitializeSRWLock");
55      fpAcquireSRWLockExclusive =
56        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
57                                               "AcquireSRWLockExclusive");
58      fpAcquireSRWLockShared =
59        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
60                                               "AcquireSRWLockShared");
61      fpReleaseSRWLockExclusive =
62        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
63                                               "ReleaseSRWLockExclusive");
64      fpReleaseSRWLockShared =
65        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
66                                               "ReleaseSRWLockShared");
67
68      if (fpInitializeSRWLock != NULL) {
69        sHasSRW = true;
70      }
71    }
72  }
73  return sHasSRW;
74}
75
76RWMutexImpl::RWMutexImpl() {
77  if (loadSRW()) {
78    data_ = calloc(1, sizeof(SRWLOCK));
79    fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
80  } else {
81    data_ = calloc(1, sizeof(CRITICAL_SECTION));
82    InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
83  }
84}
85
86RWMutexImpl::~RWMutexImpl() {
87  if (!sHasSRW)
88    DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
89  // Nothing to do in the case of slim reader/writers except free the memory.
90  free(data_);
91}
92
93bool RWMutexImpl::reader_acquire() {
94  if (sHasSRW) {
95    fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_));
96  } else {
97    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
98  }
99  return true;
100}
101
102bool RWMutexImpl::reader_release() {
103  if (sHasSRW) {
104    fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_));
105  } else {
106    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
107  }
108  return true;
109}
110
111bool RWMutexImpl::writer_acquire() {
112  if (sHasSRW) {
113    fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_));
114  } else {
115    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
116  }
117  return true;
118}
119
120bool RWMutexImpl::writer_release() {
121  if (sHasSRW) {
122    fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_));
123  } else {
124    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
125  }
126  return true;
127}
128
129
130}
131