/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "rw_lock_win.h" #include "critical_section_wrapper.h" #include "condition_variable_wrapper.h" #include "trace.h" // TODO (hellner) why not just use the rw_lock_generic.cc solution if // native is not supported? Unnecessary redundancy! namespace webrtc { bool RWLockWindows::_winSupportRWLockPrimitive = false; static HMODULE library = NULL; PInitializeSRWLock _PInitializeSRWLock; PAcquireSRWLockExclusive _PAcquireSRWLockExclusive; PAcquireSRWLockShared _PAcquireSRWLockShared; PReleaseSRWLockShared _PReleaseSRWLockShared; PReleaseSRWLockExclusive _PReleaseSRWLockExclusive; RWLockWindows::RWLockWindows() : _critSectPtr(NULL), _readCondPtr(NULL), _writeCondPtr(NULL), _readersActive(0), _writerActive(false), _readersWaiting(0), _writersWaiting(0) { } RWLockWindows::~RWLockWindows() { delete _writeCondPtr; delete _readCondPtr; delete _critSectPtr; } int RWLockWindows::Init() { if(!library) { // Use native implementation if supported (i.e Vista+) library = LoadLibrary(TEXT("Kernel32.dll")); if(library) { WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Kernel.dll"); _PInitializeSRWLock = (PInitializeSRWLock)GetProcAddress( library, "InitializeSRWLock"); _PAcquireSRWLockExclusive = (PAcquireSRWLockExclusive)GetProcAddress( library, "AcquireSRWLockExclusive"); _PReleaseSRWLockExclusive = (PReleaseSRWLockExclusive)GetProcAddress( library, "ReleaseSRWLockExclusive"); _PAcquireSRWLockShared = (PAcquireSRWLockShared)GetProcAddress( library, "AcquireSRWLockShared"); _PReleaseSRWLockShared = (PReleaseSRWLockShared)GetProcAddress( library, "ReleaseSRWLockShared"); if( _PInitializeSRWLock && _PAcquireSRWLockExclusive && _PReleaseSRWLockExclusive && _PAcquireSRWLockShared && _PReleaseSRWLockShared ) { WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Simple RW Lock"); _winSupportRWLockPrimitive = true; } } } if(_winSupportRWLockPrimitive) { _PInitializeSRWLock(&_lock); } else { _critSectPtr = CriticalSectionWrapper::CreateCriticalSection(); _readCondPtr = ConditionVariableWrapper::CreateConditionVariable(); _writeCondPtr = ConditionVariableWrapper::CreateConditionVariable(); } return 0; } void RWLockWindows::AcquireLockExclusive() { if (_winSupportRWLockPrimitive) { _PAcquireSRWLockExclusive(&_lock); } else { _critSectPtr->Enter(); if (_writerActive || _readersActive > 0) { ++_writersWaiting; while (_writerActive || _readersActive > 0) { _writeCondPtr->SleepCS(*_critSectPtr); } --_writersWaiting; } _writerActive = true; _critSectPtr->Leave(); } } void RWLockWindows::ReleaseLockExclusive() { if(_winSupportRWLockPrimitive) { _PReleaseSRWLockExclusive(&_lock); } else { _critSectPtr->Enter(); _writerActive = false; if (_writersWaiting > 0) { _writeCondPtr->Wake(); }else if (_readersWaiting > 0) { _readCondPtr->WakeAll(); } _critSectPtr->Leave(); } } void RWLockWindows::AcquireLockShared() { if(_winSupportRWLockPrimitive) { _PAcquireSRWLockShared(&_lock); } else { _critSectPtr->Enter(); if (_writerActive || _writersWaiting > 0) { ++_readersWaiting; while (_writerActive || _writersWaiting > 0) { _readCondPtr->SleepCS(*_critSectPtr); } --_readersWaiting; } ++_readersActive; _critSectPtr->Leave(); } } void RWLockWindows::ReleaseLockShared() { if(_winSupportRWLockPrimitive) { _PReleaseSRWLockShared(&_lock); } else { _critSectPtr->Enter(); --_readersActive; if (_readersActive == 0 && _writersWaiting > 0) { _writeCondPtr->Wake(); } _critSectPtr->Leave(); } } } // namespace webrtc