1 #ifdef _WIN32
2 
3 #include "lldb/Host/ProcessRunLock.h"
4 #include "lldb/Host/windows/windows.h"
5 
6 namespace lldb_private {
7 
8     // Windows has slim read-writer lock support on Vista and higher, so we
9     // will attempt to load the APIs.  If they exist, we will use them, and
10     // if not, we will fall back on critical sections.  When we drop support
11     // for XP, we can stop lazy-loading these APIs and just use them directly.
12 #if defined(__MINGW32__)
13     // Taken from WinNT.h
14     typedef struct _RTL_SRWLOCK {
15         PVOID Ptr;
16     } RTL_SRWLOCK, *PRTL_SRWLOCK;
17 
18     // Taken from WinBase.h
19     typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
20 #endif
21 
22 
23     typedef struct Win32RWLOCK
24     {
25         long int readlockcount;
26         HANDLE writable;
27         CRITICAL_SECTION writelock;
28         long int writelocked;
29     } Win32RWLOCK;
30 
31     typedef Win32RWLOCK* PWin32RWLOCK;
32 
33     static VOID (WINAPI *fpInitializeSRWLock)(PSRWLOCK lock) = NULL;
34     static VOID (WINAPI *fpAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL;
35     static VOID (WINAPI *fpAcquireSRWLockShared)(PSRWLOCK lock) = NULL;
36     static VOID (WINAPI *fpReleaseSRWLockExclusive)(PSRWLOCK lock) = NULL;
37     static VOID (WINAPI *fpReleaseSRWLockShared)(PSRWLOCK lock) = NULL;
38     static BOOL (WINAPI *fpTryAcquireSRWLockExclusive)(PSRWLOCK lock) = NULL;
39     static BOOL (WINAPI *fpTryAcquireSRWLockShared)(PSRWLOCK lock) = NULL;
40 
41     static bool sHasSRW = false;
42 
43     static bool loadSRW()
44     {
45         static bool sChecked = false;
46         if (!sChecked)
47         {
48             sChecked = true;
49             return false;
50 
51             HMODULE hLib = ::LoadLibrary(TEXT("Kernel32"));
52             if (hLib)
53             {
54                 fpInitializeSRWLock =
55                     (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
56                     "InitializeSRWLock");
57                 fpAcquireSRWLockExclusive =
58                     (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
59                     "AcquireSRWLockExclusive");
60                 fpAcquireSRWLockShared =
61                     (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
62                     "AcquireSRWLockShared");
63                 fpReleaseSRWLockExclusive =
64                     (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
65                     "ReleaseSRWLockExclusive");
66                 fpReleaseSRWLockShared =
67                     (VOID (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
68                     "ReleaseSRWLockShared");
69                 fpTryAcquireSRWLockExclusive =
70                     (BOOL (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
71                     "TryAcquireSRWLockExclusive");
72                 fpTryAcquireSRWLockShared =
73                     (BOOL (WINAPI *)(PSRWLOCK))::GetProcAddress(hLib,
74                     "TryAcquireSRWLockShared");
75 
76                 ::FreeLibrary(hLib);
77 
78                 if (fpInitializeSRWLock != NULL) {
79                     sHasSRW = true;
80                 }
81             }
82         }
83         return sHasSRW;
84     }
85 
86     ProcessRunLock::ProcessRunLock ()
87         : m_running(false)
88     {
89         if (loadSRW())
90         {
91             m_rwlock = calloc(1, sizeof(SRWLOCK));
92             fpInitializeSRWLock(static_cast<PSRWLOCK>(m_rwlock));
93         }
94         else
95         {
96             m_rwlock = calloc(1, sizeof(Win32RWLOCK));
97             static_cast<PWin32RWLOCK>(m_rwlock)->readlockcount = 0;
98             static_cast<PWin32RWLOCK>(m_rwlock)->writable = CreateEvent(NULL, true, true, NULL);
99             InitializeCriticalSection(&static_cast<PWin32RWLOCK>(m_rwlock)->writelock);
100         }
101     }
102 
103     ProcessRunLock::~ProcessRunLock ()
104     {
105         if (!sHasSRW)
106         {
107             CloseHandle(static_cast<PWin32RWLOCK>(m_rwlock)->writable);
108             DeleteCriticalSection(&static_cast<PWin32RWLOCK>(m_rwlock)->writelock);
109         }
110         free(m_rwlock);
111     }
112 
113     bool ReadLock (lldb::rwlock_t rwlock)
114     {
115         if (sHasSRW)
116         {
117             fpAcquireSRWLockShared(static_cast<PSRWLOCK>(rwlock));
118             return true;
119         }
120         else
121         {
122             EnterCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock);
123             InterlockedIncrement(&static_cast<PWin32RWLOCK>(rwlock)->readlockcount);
124             ResetEvent(static_cast<PWin32RWLOCK>(rwlock)->writable);
125             LeaveCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock);
126             return true;
127         }
128     }
129 
130     bool ProcessRunLock::ReadTryLock ()
131     {
132         ReadLock(m_rwlock);
133         if (m_running == false)
134             return true;
135         ReadUnlock();
136         return false;
137     }
138 
139     bool ProcessRunLock::ReadUnlock ()
140     {
141         if (sHasSRW)
142         {
143             fpReleaseSRWLockShared(static_cast<PSRWLOCK>(m_rwlock));
144             return true;
145         }
146         else
147         {
148             unsigned long int value = InterlockedDecrement(&static_cast<PWin32RWLOCK>(m_rwlock)->readlockcount);
149             assert(((int)value) >= 0);
150             if (value == 0)
151                 SetEvent(static_cast<PWin32RWLOCK>(m_rwlock)->writable);
152             return true;
153         }
154     }
155 
156     bool WriteLock(lldb::rwlock_t rwlock)
157     {
158         if (sHasSRW)
159         {
160             fpAcquireSRWLockExclusive(static_cast<PSRWLOCK>(rwlock));
161             return true;
162         }
163         else
164         {
165             EnterCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock);
166             WaitForSingleObject(static_cast<PWin32RWLOCK>(rwlock)->writable, INFINITE);
167             int res = InterlockedExchange(&static_cast<PWin32RWLOCK>(rwlock)->writelocked, 1);
168             assert(res == 0);
169             return true;
170         }
171     }
172 
173     bool WriteTryLock(lldb::rwlock_t rwlock)
174     {
175         if (sHasSRW)
176         {
177             return fpTryAcquireSRWLockExclusive(static_cast<PSRWLOCK>(rwlock)) != 0;
178         }
179         else
180         {
181             if (TryEnterCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock)) {
182                 if (WaitForSingleObject(static_cast<PWin32RWLOCK>(rwlock)->writable, 0)) {
183                     LeaveCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock);
184                     return false;
185                 }
186                 int res = InterlockedExchange(&static_cast<PWin32RWLOCK>(rwlock)->writelocked, 1);
187                 assert(res == 0);
188                 return true;
189             }
190             return false;
191         }
192     }
193 
194     bool WriteUnlock(lldb::rwlock_t rwlock)
195     {
196         if (sHasSRW)
197         {
198             fpReleaseSRWLockExclusive(static_cast<PSRWLOCK>(rwlock));
199             return true;
200         }
201         else
202         {
203             int res = InterlockedExchange(&static_cast<PWin32RWLOCK>(rwlock)->writelocked, 0);
204             if (res == 1) {
205                 LeaveCriticalSection(&static_cast<PWin32RWLOCK>(rwlock)->writelock);
206                 return true;
207             }
208             return false;
209         }
210     }
211 
212     bool ProcessRunLock::SetRunning ()
213     {
214         WriteLock(m_rwlock);
215         m_running = true;
216         WriteUnlock(m_rwlock);
217         return true;
218     }
219 
220     bool ProcessRunLock::TrySetRunning ()
221     {
222         if (WriteTryLock(m_rwlock))
223         {
224             bool r = !m_running;
225             m_running = true;
226             WriteUnlock(m_rwlock);
227             return r;
228         }
229         return false;
230     }
231 
232     bool ProcessRunLock::SetStopped ()
233     {
234         WriteLock(m_rwlock);
235         m_running = false;
236         WriteUnlock(m_rwlock);
237         return true;
238     }
239 }
240 
241 #endif
242