1 /*
2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "rw_lock_win.h"
12 
13 #include "critical_section_wrapper.h"
14 #include "condition_variable_wrapper.h"
15 #include "trace.h"
16 
17 // TODO (hellner) why not just use the rw_lock_generic.cc solution if
18 //                           native is not supported? Unnecessary redundancy!
19 
20 namespace webrtc {
21 bool RWLockWindows::_winSupportRWLockPrimitive = false;
22 static HMODULE library = NULL;
23 
24 PInitializeSRWLock       _PInitializeSRWLock;
25 PAcquireSRWLockExclusive _PAcquireSRWLockExclusive;
26 PAcquireSRWLockShared    _PAcquireSRWLockShared;
27 PReleaseSRWLockShared    _PReleaseSRWLockShared;
28 PReleaseSRWLockExclusive _PReleaseSRWLockExclusive;
29 
RWLockWindows()30 RWLockWindows::RWLockWindows()
31     : _critSectPtr(NULL),
32       _readCondPtr(NULL),
33       _writeCondPtr(NULL),
34       _readersActive(0),
35       _writerActive(false),
36       _readersWaiting(0),
37       _writersWaiting(0)
38 {
39 }
40 
~RWLockWindows()41 RWLockWindows::~RWLockWindows()
42 {
43     delete _writeCondPtr;
44     delete _readCondPtr;
45     delete _critSectPtr;
46 }
47 
Init()48 int RWLockWindows::Init()
49 {
50     if(!library)
51     {
52         // Use native implementation if supported (i.e Vista+)
53         library = LoadLibrary(TEXT("Kernel32.dll"));
54         if(library)
55         {
56             WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
57                          "Loaded Kernel.dll");
58 
59             _PInitializeSRWLock =
60                 (PInitializeSRWLock)GetProcAddress(
61                     library,
62                     "InitializeSRWLock");
63 
64             _PAcquireSRWLockExclusive =
65                (PAcquireSRWLockExclusive)GetProcAddress(
66                    library,
67                    "AcquireSRWLockExclusive");
68             _PReleaseSRWLockExclusive =
69                 (PReleaseSRWLockExclusive)GetProcAddress(
70                     library,
71                     "ReleaseSRWLockExclusive");
72             _PAcquireSRWLockShared =
73                 (PAcquireSRWLockShared)GetProcAddress(
74                     library,
75                     "AcquireSRWLockShared");
76             _PReleaseSRWLockShared =
77                 (PReleaseSRWLockShared)GetProcAddress(
78                     library,
79                     "ReleaseSRWLockShared");
80 
81             if( _PInitializeSRWLock &&
82                 _PAcquireSRWLockExclusive &&
83                 _PReleaseSRWLockExclusive &&
84                 _PAcquireSRWLockShared &&
85                 _PReleaseSRWLockShared )
86             {
87                 WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
88                             "Loaded Simple RW Lock");
89                 _winSupportRWLockPrimitive = true;
90             }
91         }
92     }
93     if(_winSupportRWLockPrimitive)
94     {
95         _PInitializeSRWLock(&_lock);
96     } else {
97         _critSectPtr  = CriticalSectionWrapper::CreateCriticalSection();
98         _readCondPtr  = ConditionVariableWrapper::CreateConditionVariable();
99         _writeCondPtr = ConditionVariableWrapper::CreateConditionVariable();
100     }
101     return 0;
102 }
103 
AcquireLockExclusive()104 void RWLockWindows::AcquireLockExclusive()
105 {
106     if (_winSupportRWLockPrimitive)
107     {
108         _PAcquireSRWLockExclusive(&_lock);
109     } else {
110         _critSectPtr->Enter();
111 
112         if (_writerActive || _readersActive > 0)
113         {
114             ++_writersWaiting;
115             while (_writerActive || _readersActive > 0)
116             {
117                 _writeCondPtr->SleepCS(*_critSectPtr);
118             }
119             --_writersWaiting;
120         }
121         _writerActive = true;
122         _critSectPtr->Leave();
123     }
124 }
125 
ReleaseLockExclusive()126 void RWLockWindows::ReleaseLockExclusive()
127 {
128     if(_winSupportRWLockPrimitive)
129     {
130         _PReleaseSRWLockExclusive(&_lock);
131     } else {
132         _critSectPtr->Enter();
133         _writerActive = false;
134         if (_writersWaiting > 0)
135         {
136             _writeCondPtr->Wake();
137 
138         }else if (_readersWaiting > 0) {
139             _readCondPtr->WakeAll();
140         }
141         _critSectPtr->Leave();
142     }
143 }
144 
AcquireLockShared()145 void RWLockWindows::AcquireLockShared()
146 {
147     if(_winSupportRWLockPrimitive)
148     {
149         _PAcquireSRWLockShared(&_lock);
150     } else
151     {
152         _critSectPtr->Enter();
153         if (_writerActive || _writersWaiting > 0)
154         {
155             ++_readersWaiting;
156 
157             while (_writerActive || _writersWaiting > 0)
158             {
159                 _readCondPtr->SleepCS(*_critSectPtr);
160             }
161             --_readersWaiting;
162         }
163         ++_readersActive;
164         _critSectPtr->Leave();
165     }
166 }
167 
ReleaseLockShared()168 void RWLockWindows::ReleaseLockShared()
169 {
170     if(_winSupportRWLockPrimitive)
171     {
172         _PReleaseSRWLockShared(&_lock);
173     } else
174     {
175         _critSectPtr->Enter();
176 
177         --_readersActive;
178 
179         if (_readersActive == 0 && _writersWaiting > 0)
180         {
181             _writeCondPtr->Wake();
182         }
183         _critSectPtr->Leave();
184     }
185 }
186 } // namespace webrtc
187