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
20namespace webrtc {
21bool RWLockWindows::_winSupportRWLockPrimitive = false;
22static HMODULE library = NULL;
23
24PInitializeSRWLock       _PInitializeSRWLock;
25PAcquireSRWLockExclusive _PAcquireSRWLockExclusive;
26PAcquireSRWLockShared    _PAcquireSRWLockShared;
27PReleaseSRWLockShared    _PReleaseSRWLockShared;
28PReleaseSRWLockExclusive _PReleaseSRWLockExclusive;
29
30RWLockWindows::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
41RWLockWindows::~RWLockWindows()
42{
43    delete _writeCondPtr;
44    delete _readCondPtr;
45    delete _critSectPtr;
46}
47
48int 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
104void 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
126void 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
145void 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
168void 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