blob: 82cd0ac04f55ccb8618fc67ef03b7716721733bd [file] [log] [blame]
/*
* 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