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 "Windows.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    HMODULE hLib = ::LoadLibrary(TEXT("Kernel32"));
52    if (hLib) {
53      fpInitializeSRWLock =
54        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
55                                               "InitializeSRWLock");
56      fpAcquireSRWLockExclusive =
57        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
58                                               "AcquireSRWLockExclusive");
59      fpAcquireSRWLockShared =
60        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
61                                               "AcquireSRWLockShared");
62      fpReleaseSRWLockExclusive =
63        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
64                                               "ReleaseSRWLockExclusive");
65      fpReleaseSRWLockShared =
66        (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
67                                               "ReleaseSRWLockShared");
68      ::FreeLibrary(hLib);
69
70      if (fpInitializeSRWLock != NULL) {
71        sHasSRW = true;
72      }
73    }
74  }
75  return sHasSRW;
76}
77
78RWMutexImpl::RWMutexImpl() {
79  if (loadSRW()) {
80    data_ = calloc(1, sizeof(SRWLOCK));
81    fpInitializeSRWLock(static_cast<PSRWLOCK>(data_));
82  } else {
83    data_ = calloc(1, sizeof(CRITICAL_SECTION));
84    InitializeCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
85  }
86}
87
88RWMutexImpl::~RWMutexImpl() {
89  if (sHasSRW) {
90    // Nothing to do in the case of slim reader/writers
91  } else {
92    DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
93    free(data_);
94  }
95}
96
97bool RWMutexImpl::reader_acquire() {
98  if (sHasSRW) {
99    fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_));
100  } else {
101    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
102  }
103  return true;
104}
105
106bool RWMutexImpl::reader_release() {
107  if (sHasSRW) {
108    fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_));
109  } else {
110    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
111  }
112  return true;
113}
114
115bool RWMutexImpl::writer_acquire() {
116  if (sHasSRW) {
117    fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_));
118  } else {
119    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
120  }
121  return true;
122}
123
124bool RWMutexImpl::writer_release() {
125  if (sHasSRW) {
126    fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_));
127  } else {
128    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
129  }
130  return true;
131}
132
133
134}
135