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