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    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    // Nothing to do in the case of slim reader/writers
89  } else {
90    DeleteCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
91    free(data_);
92  }
93}
94
95bool RWMutexImpl::reader_acquire() {
96  if (sHasSRW) {
97    fpAcquireSRWLockShared(static_cast<PSRWLOCK>(data_));
98  } else {
99    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
100  }
101  return true;
102}
103
104bool RWMutexImpl::reader_release() {
105  if (sHasSRW) {
106    fpReleaseSRWLockShared(static_cast<PSRWLOCK>(data_));
107  } else {
108    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
109  }
110  return true;
111}
112
113bool RWMutexImpl::writer_acquire() {
114  if (sHasSRW) {
115    fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(data_));
116  } else {
117    EnterCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
118  }
119  return true;
120}
121
122bool RWMutexImpl::writer_release() {
123  if (sHasSRW) {
124    fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(data_));
125  } else {
126    LeaveCriticalSection(static_cast<LPCRITICAL_SECTION>(data_));
127  }
128  return true;
129}
130
131
132}
133