Add ReaderWriterQueue and update ConcurrentQueue

This commit is contained in:
Paul Hollinsky
2020-03-09 13:38:14 -04:00
parent 9ac3fd56bd
commit 42780dc610
1629 changed files with 306008 additions and 868 deletions
@@ -0,0 +1,25 @@
Version 2.4
Features:
+ Support for futex(FUTEX_WAIT/FUTEX_WAKE)
+ Linux/Darwin performance improved (2.5x for Linux, 7x for Darwin)
Fixes:
+ Fixed a bunch of issues with WaitForMultipleObjects()/SignalObjectAndWait()
+ Fixed rare spurious memory leak reports related to test progress reporting
Version 2.3
Features:
+ Support for FlushProcessWriteBuffers()
Version 2.2
Features:
+ Support for pthread_mutex_timedlock()
+ Support for ETIMEDOUT, EINTR in pthread_cond_timedwait()/pthread_cond_wait()
+ rl::hash_ptr(p, sz) function which provides deterministic hashing of pointers
Fixes:
+ Win32 mutex is now recursive
+ Compilation issue on MSVC x64 when RL_DEBUGBREAK_ON_ASSERT/RL_DEBUGBREAK_ON_FAILURE defined
+ Fixed OOM crash when execution history is very large
+ Fixed rare crash during iteration count estimation in context bound scheduler
+ Fixed bug in pthread_rwlock/SRWLOCK that at most 2 readers may acquire it simultaneously
+ Fixed bug regarding false race detection when simulation runs for very long time (int overflow)
@@ -0,0 +1,19 @@
Relacy Race Detector
Copyright (c) 2008-2013, Dmitry S. Vyukov
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the distribution.
- The name of the owner may not be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE OWNER "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
acc09bbe65a1837a08912774c7fed178547514e6
@@ -0,0 +1,195 @@
#include "stdafx.h"
#include "../../relacy/relacy_cli.hpp"
using rl::nvar;
using rl::nvolatile;
using rl::mutex;
template<typename T>
class ws_deque
{
public:
ws_deque()
{
m_mask($) = initial_size - 1;
m_headIndex($) = 0;
m_tailIndex($) = 0;
m_array($) = new nvar<T> [initial_size];
m_arraySize($) = initial_size;
}
bool IsEmpty()
{
return m_headIndex($) >= m_tailIndex($);
}
size_t Count()
{
return m_tailIndex($) - m_headIndex($);
}
void push(T item)
{
size_t tail = m_tailIndex($);
if (tail <= m_headIndex($) + m_mask($))
{
m_array($)[tail & m_mask($)]($) = item;
m_tailIndex($) = tail + 1;
}
else
{
m_foreignLock.lock($);
size_t head = m_headIndex($);
size_t count = Count();
if (count >= m_mask($))
{
size_t arraySize = m_arraySize($);
size_t mask = m_mask($);
nvar<T>* newArray = new nvar<T> [arraySize * 2];
nvar<T>* arr = m_array($);
for (size_t i = 0; i != count; ++i)
newArray[i]($) = arr[(i + head) & mask]($);
m_array($) = newArray;
m_arraySize($) = arraySize * 2;
m_headIndex($) = 0;
m_tailIndex($) = count;
tail = count;
m_mask($) = (mask * 2) | 1;
}
m_array($)[tail & m_mask($)]($) = item;
m_tailIndex($) = tail + 1;
m_foreignLock.unlock($);
}
}
bool pop(T& item)
{
size_t tail = m_tailIndex($);
if (tail == 0)
return false;
tail -= 1;
rl::Interlocked::Exchange(m_tailIndex, tail, $);
if (m_headIndex($) <= tail)
{
item = m_array($)[tail & m_mask($)]($);
return true;
}
else
{
m_foreignLock.lock($);
if (m_headIndex($) <= tail)
{
item = m_array($)[tail & m_mask($)]($);
m_foreignLock.unlock($);
return true;
}
else
{
m_tailIndex($) = tail + 1;
m_foreignLock.unlock($);
return false;
}
}
}
bool steal(T& item)
{
if (false == m_foreignLock.try_lock($))
return false;
size_t head = m_headIndex($);
rl::Interlocked::Exchange(m_headIndex, head + 1, $);
if (head < m_tailIndex($))
{
item = m_array($)[head & m_mask($)]($);
m_foreignLock.unlock($);
return true;
}
else
{
m_headIndex($) = head;
m_foreignLock.unlock($);
return false;
}
}
private:
static size_t const initial_size = 2;
nvar<nvar<T>*> m_array;
nvar<size_t> m_mask;
nvar<size_t> m_arraySize;
nvolatile<size_t> m_headIndex;
nvolatile<size_t> m_tailIndex;
mutex m_foreignLock;
};
struct ws_deque_test : rl::test_suite<ws_deque_test, 2>
{
ws_deque<int> q;
bool state [2];
void before()
{
state[0] = true;
state[1] = true;
}
void after()
{
RL_ASSERT(state[0] == false);
RL_ASSERT(state[1] == false);
}
void thread(unsigned index)
{
if (0 == index)
{
q.push(1);
q.push(2);
int item = 0;
bool res = q.pop(item);
RL_ASSERT(res && item == 2);
RL_ASSERT(state[1]);
state[1] = false;
item = 0;
res = q.pop(item);
if (res)
{
RL_ASSERT(state[0]);
state[0] = false;
}
item = 0;
res = q.pop(item);
RL_ASSERT(res == false);
}
else
{
int item = 0;
bool res = q.steal(item);
if (res)
{
RL_ASSERT(item == 1);
RL_ASSERT(state[0]);
state[0] = false;
}
}
}
};
int main()
{
rl::simulate<ws_deque_test>();
}
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cli_ws_deque", "cli_ws_deque.vcproj", "{0B597F19-DEBB-4832-B520-9A93A286D595}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0B597F19-DEBB-4832-B520-9A93A286D595}.Debug|Win32.ActiveCfg = Debug|Win32
{0B597F19-DEBB-4832-B520-9A93A286D595}.Debug|Win32.Build.0 = Debug|Win32
{0B597F19-DEBB-4832-B520-9A93A286D595}.Release|Win32.ActiveCfg = Release|Win32
{0B597F19-DEBB-4832-B520-9A93A286D595}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="cli_ws_deque"
ProjectGUID="{967F376B-BDBF-4AC8-9325-371CC8ABD8FD}"
RootNamespace="cli_ws_deque"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\cli_ws_deque.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,7 @@
#pragma once
#include "../../relacy/pch.hpp"
@@ -0,0 +1,181 @@
#include "stdafx.h"
#include "../../relacy/relacy_std.hpp"
// THE TEST IS EXPECTED TO FAIL WITH "DEADLOCK"
class CondVar
{
public:
CondVar();
~CondVar();
void Enter();
void Wait();
void Release();
void ReleaseAll();
void Leave();
private:
std::atomic<int> m_lMutex;
std::atomic<unsigned> m_dwWaitingForSignal;
HANDLE m_xhEvtEnter;
HANDLE m_xhSemRelease;
};
CondVar::CondVar()
: m_xhEvtEnter(CreateEvent(0, 0, 0, 0))
, m_xhSemRelease(CreateSemaphore(0, 0, 0x7FFFFFFF, 0))
{
m_lMutex.store(0, std::memory_order_relaxed);
m_dwWaitingForSignal.store(0, std::memory_order_relaxed);
}
CondVar::~CondVar()
{
CloseHandle(m_xhEvtEnter);
CloseHandle(m_xhSemRelease);
}
void CondVar::Enter()
{
int lMutex = m_lMutex.load(std::memory_order_seq_cst);
for (;;)
{
if( lMutex >= 0 )
{
if (m_lMutex.compare_exchange_weak(lMutex, lMutex | 0x80000000u, std::memory_order_seq_cst))
break;
}
else
{
if (false == m_lMutex.compare_exchange_weak(lMutex, lMutex + 1, std::memory_order_seq_cst))
continue;
WaitForSingleObject(m_xhEvtEnter, INFINITE);
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
break;
}
}
}
void CondVar::Wait()
{
unsigned dwWaitingForSignal = m_dwWaitingForSignal.load(std::memory_order_seq_cst);
m_dwWaitingForSignal.store(dwWaitingForSignal + 1, std::memory_order_seq_cst);
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
int lMutex = m_lMutex.load(std::memory_order_seq_cst);
for (;;)
{
unsigned dwWaitingToOwn = lMutex & 0x7FFFFFFFu;
RL_ASSERT(dwWaitingToOwn >= dwWaitingForSignal);
if (dwWaitingToOwn == dwWaitingForSignal)
{
if (m_lMutex.compare_exchange_weak(lMutex, dwWaitingToOwn + 1, std::memory_order_seq_cst))
break;
}
else
{
SetEvent(m_xhEvtEnter);
break;
}
}
WaitForSingleObject(m_xhSemRelease, INFINITE);
WaitForSingleObject(m_xhEvtEnter, INFINITE);
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
}
void CondVar::Release()
{
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
unsigned dwWaitingForSignal = m_dwWaitingForSignal.load(std::memory_order_seq_cst);
if (dwWaitingForSignal != 0)
{
m_dwWaitingForSignal.store(dwWaitingForSignal - 1, std::memory_order_seq_cst);
ReleaseSemaphore(m_xhSemRelease, 1, 0);
}
}
void CondVar::ReleaseAll()
{
RL_ASSERT(m_lMutex.load(std::memory_order_seq_cst) < 0);
unsigned dwWaitingForSignal = m_dwWaitingForSignal.load(std::memory_order_seq_cst);
if (dwWaitingForSignal != 0)
{
m_dwWaitingForSignal.store(0, std::memory_order_seq_cst);
ReleaseSemaphore(m_xhSemRelease, dwWaitingForSignal, 0);
}
}
void CondVar::Leave()
{
int lMutex = m_lMutex.load(std::memory_order_seq_cst);
RL_ASSERT(lMutex < 0);
for (;;)
{
unsigned dwWaitingToOwn = lMutex & 0x7FFFFFFFu;
unsigned dwWaitingForSignal = m_dwWaitingForSignal.load(std::memory_order_seq_cst);
RL_ASSERT(dwWaitingToOwn >= dwWaitingForSignal);
if (dwWaitingToOwn == dwWaitingForSignal)
{
if (m_lMutex.compare_exchange_weak(lMutex, lMutex & 0x7FFFFFFF, std::memory_order_seq_cst))
break;
}
else
{
if (false == m_lMutex.compare_exchange_weak(lMutex, lMutex - 1, std::memory_order_seq_cst))
continue;
SetEvent(m_xhEvtEnter);
break;
}
}
}
struct CondVarTest : rl::test_suite<CondVarTest, 3>
{
VAR_T(int) stage;
CondVar cv;
void before()
{
VAR(stage) = 0;
}
void thread(unsigned index)
{
if (0 == index)
{
cv.Enter();
VAR(stage) += 1;
cv.ReleaseAll();
while (VAR(stage) != 2)
cv.Wait();
cv.Leave();
}
else if (1 == index)
{
cv.Enter();
while (VAR(stage) != 1)
cv.Wait();
VAR(stage) += 1;
cv.ReleaseAll();
cv.Leave();
}
else if (2 == index)
{
cv.Enter();
while (VAR(stage) != 2)
cv.Wait();
cv.Leave();
}
}
};
int main()
{
rl::simulate<CondVarTest>();
}
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "condvar", "condvar.vcproj", "{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.ActiveCfg = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.Build.0 = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.ActiveCfg = Release|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="condvar"
ProjectGUID="{6CC59CF8-408B-441B-8F65-15651210CB82}"
RootNamespace="condvar"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\condvar.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "condvar", "condvar.vcproj", "{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.ActiveCfg = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.Build.0 = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.ActiveCfg = Release|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="condvar"
ProjectGUID="{6CC59CF8-408B-441B-8F65-15651210CB82}"
RootNamespace="condvar"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\condvar.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,14 @@
#pragma once
#ifdef NDEBUG
# define _SECURE_SCL 0
#endif
#define RL_MSVC_OUTPUT
//#define RL_DEBUGBREAK_ON_FAILURE
#include "../../relacy/pch.hpp"
#include "../../relacy/relacy_std.hpp"
@@ -0,0 +1,178 @@
/*
#define BOOST_ALL_NO_LIB
#pragma warning (push, 3)
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_mutex.hpp>
#include "C:\boost_1_35_0\libs\thread\src\win32\exceptions.cpp"
#pragma warning (pop)
class business_logic
{
public:
typedef unsigned account_id_t;
typedef double balance_t;
bool add_account(account_id_t acc_id, balance_t balance)
{
accounts_guard.lock();
if (accounts.find(acc_id) != accounts.end())
{
accounts_guard.unlock();
return false;
}
accounts[acc_id].balance = balance;
accounts_guard.unlock();
return true;
}
bool transfer_balance(account_id_t acc_id1, account_id_t acc_id2, balance_t amount)
{
accounts_guard.lock_shared();
if (accounts.find(acc_id1) != accounts.end()
|| accounts.find(acc_id2) != accounts.end())
{
accounts_guard.unlock_shared();
return false;
}
account_info& acc1 = accounts[acc_id1];
account_info& acc2 = accounts[acc_id2];
acc1.mtx.lock();
acc2.mtx.lock();
accounts_guard.unlock_shared();
acc1.balance -= amount;
acc2.balance += amount;
acc1.mtx.unlock();
acc2.mtx.unlock();
return true;
}
private:
struct account_info
{
balance_t balance;
boost::mutex mtx;
account_info()
: balance()
{}
account_info(account_info const& acc)
: balance(acc.balance)
{}
};
typedef std::map<account_id_t, account_info> account_map_t;
account_map_t accounts;
boost::shared_mutex accounts_guard;
};
*/
/*
#undef RL_TEST
#ifndef RL_TEST
//# define ASSERT assert
typedef boost::mutex mutex_t;
# define $$
#else
//# define ASSERT RL_ASSERT
typedef rl::recursive_mutex mutex_t;
# define $$ $
#endif
class business_logic
{
public:
typedef unsigned account_id_t;
typedef double balance_t;
bool add_account(account_id_t acc_id, balance_t balance)
{
accounts_guard.lock($$);
if (accounts.find(acc_id) != accounts.end())
{
accounts_guard.unlock($$);
return false;
}
accounts[acc_id].balance = balance;
accounts_guard.unlock($$);
return true;
}
bool transfer_balance(account_id_t acc_id1, account_id_t acc_id2, balance_t amount)
{
accounts_guard.lock($$);
if (accounts.find(acc_id1) == accounts.end()
|| accounts.find(acc_id2) == accounts.end())
{
accounts_guard.unlock($$);
return false;
}
account_info& acc1 = accounts[acc_id1];
account_info& acc2 = accounts[acc_id2];
acc1.mtx.lock($$);
acc2.mtx.lock($$);
accounts_guard.unlock($$);
acc1.balance -= amount;
acc2.balance += amount;
acc1.mtx.unlock($$);
acc2.mtx.unlock($$);
return true;
}
private:
struct account_info
{
balance_t balance;
mutex_t mtx;
account_info()
: balance()
{}
account_info(account_info const& acc)
: balance(acc.balance)
{}
};
typedef std::map<account_id_t, account_info> account_map_t;
account_map_t accounts;
mutex_t accounts_guard;
};
*/
/*
struct business_logic_test : rl::test_suite<business_logic_test, 2>
{
business_logic bl;
static size_t const account_count = 10;
void before()
{
for (size_t i = 0; i != account_count; ++i)
{
bool rv = bl.add_account(i, i * 10.0);
RL_ASSERT(rv);
}
}
void thread(unsigned)
{
business_logic::account_id_t acc1 = rl::rand(account_count);
business_logic::account_id_t acc2 = rl::rand(account_count);
bool rv = bl.transfer_balance(acc1, acc2, 1.0);
RL_ASSERT(rv);
}
};
*/
@@ -0,0 +1,707 @@
#include "stdafx.h"
#include "../../relacy/windows.h"
#define HANDLE rl::HANDLE
#define CreateSemaphoreA rl::RL_CreateSemaphore($)
#define CreateSemaphoreW rl::RL_CreateSemaphore($)
#ifndef CreateSemaphore
# define CreateSemaphore CreateSemaphoreW
#endif
#define CloseHandle rl::RL_CloseHandle($)
#include <stddef.h>
#if defined(WIN32) && defined(_MSC_VER)
#include <windows.h>
#include <intrin.h>
class semaphore
{
public:
semaphore()
{
h_ = CreateSemaphore(0, 0, LONG_MAX, 0);
}
~semaphore()
{
CloseHandle(h_);
}
void wait()
{
WaitForSingleObject(h_, INFINITE);
}
void post()
{
ReleaseSemaphore(h_, 1, 0);
}
private:
HANDLE h_;
semaphore(semaphore const&);
semaphore& operator = (semaphore const&);
};
class mutex
{
public:
mutex()
{
InitializeCriticalSection(&cs_);
}
~mutex()
{
DeleteCriticalSection(&cs_);
}
void lock()
{
EnterCriticalSection(&cs_);
}
void unlock()
{
LeaveCriticalSection(&cs_);
}
private:
CRITICAL_SECTION cs_;
mutex(mutex const&);
mutex& operator = (mutex const&);
};
void full_memory_fence()
{
_mm_mfence();
}
#define THREAD_LOCAL __declspec(thread)
#elif defined(POSIX) && defined(GCC)
#include <pthread.h>
#include <semaphore.h>
class semaphore
{
public:
semaphore()
{
sem_init(&sem_, 0, 0);
}
~semaphore()
{
sem_destroy(&sem_);
}
void wait()
{
sem_wait(&sem_);
}
void post()
{
sem_post(&sem_);
}
private:
sem_t sem_;
semaphore(semaphore const&);
semaphore& operator = (semaphore const&);
};
class mutex
{
public:
mutex()
{
pthread_mutex_init(&mutex_, 0);
}
~mutex()
{
pthread_mutex_destroy(&mutex_);
}
void lock()
{
pthread_mutex_lock(&mutex_);
}
void unlock()
{
pthread_mutex_unlock(&mutex_);
}
private:
pthread_mutex_t mutex_;
mutex(mutex const&);
mutex& operator = (mutex const&);
};
void full_memory_fence()
{
__sync_synchronize();
}
#define THREAD_LOCAL __thread
#endif
class lock
{
public:
lock(mutex& m)
: m_(m)
{
m.lock();
}
~lock()
{
m_.unlock();
}
private:
mutex& m_;
lock(lock const&);
lock& operator = (lock const&);
};
/** simple single-threaded double-linked list
* nothing interesting
*/
class dlist
{
public:
struct node
{
node* prev_;
node* next_;
node()
{
prev_ = 0;
next_ = 0;
}
};
dlist()
{
reset();
}
void push(node* n)
{
size_ += 1;
n->next_ = head_.next_;
n->prev_ = &head_;
head_.next_->prev_ = n;
head_.next_ = n;
}
node* pop()
{
if (size_ == 0)
return 0;
node* n = head_.next_;
remove(n);
return n;
}
void remove(node* n)
{
size_ -= 1;
n->prev_->next_ = n->next_;
n->next_->prev_ = n->prev_;
}
size_t size() const
{
return size_;
}
node* begin()
{
return head_.next_;
}
void flush_to(dlist& target)
{
if (size_)
{
target.size_ = size_;
target.head_.next_ = head_.next_;
target.head_.next_->prev_ = &target.head_;
target.tail_.prev_ = tail_.prev_;
target.tail_.prev_->next_ = &target.tail_;
}
else
{
target.reset();
}
reset();
}
static bool not_last(node* n)
{
return n->next_ != 0;
}
static node* get_next(node* n)
{
return n->next_;
}
private:
size_t volatile size_;
node head_;
node tail_;
void reset()
{
size_ = 0;
head_.next_ = &tail_;
head_.prev_ = 0;
tail_.next_ = 0;
tail_.prev_ = &head_;
}
dlist(dlist const&);
dlist& operator = (dlist const&);
};
/** pre-thread descriptor for eventcount
*/
struct ec_thread
{
dlist::node node_;
semaphore sema_;
unsigned epoch_;
bool volatile in_waitset_;
bool spurious_;
void* ctx_;
ec_thread()
{
epoch_ = 0;
in_waitset_ = false;
spurious_ = false;
ctx_ = 0;
}
~ec_thread()
{
if (spurious_)
sema_.wait();
}
static ec_thread* current()
{
static THREAD_LOCAL ec_thread* ec_thread_instance = 0;
ec_thread* instance = ec_thread_instance;
if (instance == 0)
{
instance = new ec_thread;
ec_thread_instance = instance;
}
return instance;
// instance must be destroyed in DllMain() callback
// or in pthread_key_create() callback
}
private:
ec_thread(ec_thread const&);
ec_thread& operator = (ec_thread const&);
};
/** fine-grained eventcount implementation
*/
class eventcount
{
public:
eventcount()
{
epoch_ = 0;
}
void prepare_wait(void* ctx = 0)
{
ec_thread* th = ec_thread::current();
// this is good place to pump previous spurious wakeup
if (th->spurious_)
{
th->spurious_ = false;
th->sema_.wait();
}
th->in_waitset_ = true;
th->ctx_ = ctx;
{
lock l (mtx_);
th->epoch_ = epoch_;
waitset_.push(&th->node_);
}
full_memory_fence();
}
void wait()
{
ec_thread* th = ec_thread::current();
// this check is just an optimization
if (th->epoch_ == epoch_)
th->sema_.wait();
else
retire_wait();
}
void retire_wait()
{
ec_thread* th = ec_thread::current();
// spurious wakeup will be pumped in following prepare_wait()
th->spurious_ = true;
// try to remove node from waitset
if (th->in_waitset_)
{
lock l (mtx_);
if (th->in_waitset_)
{
// successfully removed from waitset,
// so there will be no spurious wakeup
th->in_waitset_ = false;
th->spurious_ = false;
waitset_.remove(&th->node_);
}
}
}
void notify_one()
{
full_memory_fence();
notify_one_relaxed();
}
template<typename predicate_t>
void notify(predicate_t pred)
{
full_memory_fence();
notify_relaxed(pred);
}
void notify_all()
{
full_memory_fence();
notify_all_relaxed();
}
void notify_one_relaxed()
{
if (waitset_.size() == 0)
return;
dlist::node* n;
{
lock l (mtx_);
epoch_ += 1;
n = waitset_.pop();
if (n)
to_ec_thread(n)->in_waitset_ = false;
}
if (n)
{
to_ec_thread(n)->sema_.post();
}
}
template<typename predicate_t>
void notify_relaxed(predicate_t pred)
{
if (waitset_.size() == 0)
return;
dlist temp;
{
lock l (mtx_);
epoch_ += 1;
size_t size = waitset_.size();
size_t idx = 0;
dlist::node* n = waitset_.begin();
while (dlist::not_last(n))
{
dlist::node* next = dlist::get_next(n);
ec_thread* th = to_ec_thread(n);
if (pred(th->ctx_, size, idx))
{
waitset_.remove(n);
temp.push(n);
th->in_waitset_ = false;
}
n = next;
idx += 1;
}
}
dlist::node* n = temp.begin();
while (dlist::not_last(n))
{
dlist::node* next = dlist::get_next(n);
to_ec_thread(n)->sema_.post();
n = next;
}
}
void notify_all_relaxed()
{
if (waitset_.size() == 0)
return;
dlist temp;
{
lock l (mtx_);
epoch_ += 1;
waitset_.flush_to(temp);
dlist::node* n = temp.begin();
while (dlist::not_last(n))
{
to_ec_thread(n)->in_waitset_ = false;
n = dlist::get_next(n);
}
}
dlist::node* n = temp.begin();
while (dlist::not_last(n))
{
dlist::node* next = dlist::get_next(n);
to_ec_thread(n)->sema_.post();
n = next;
}
}
private:
mutex mtx_;
dlist waitset_;
volatile unsigned epoch_;
ec_thread* to_ec_thread(dlist::node* n)
{
return (ec_thread*)((char*)n - offsetof(ec_thread, node_));
}
eventcount(eventcount const&);
eventcount& operator = (eventcount const&);
};
struct scheduler
{
struct tbb_thread {};
eventcount ec_;
tbb_thread* threads_;
bool volatile is_permanently_open_;
void wait_while_pool_is_empty(tbb_thread* th)
{
if (is_permanently_open_)
return;
ec_.prepare_wait(th);
if (pool_is_empty())
ec_.wait();
else
ec_.retire_wait();
}
void notify_about_new_task_available()
{
ec_.notify_one_relaxed();
}
void notify_about_new_task_available_with_preference(tbb_thread* preference)
{
struct local
{
tbb_thread* preference_;
bool fired_;
bool operator () (void* ctx, size_t count, size_t idx)
{
tbb_thread* th = (tbb_thread*)ctx;
if (th == preference_)
{
fired_ = true;
return true;
}
else if (idx == count - 1 && fired_ == false)
{
return true;
}
else
{
return false;
}
}
}
pred = {preference};
ec_.notify_relaxed(pred);
}
void notify_about_list_of_tasks_available(size_t total_count, size_t preference_count, tbb_thread** preferences)
{
struct local
{
size_t remain_to_signal_;
size_t preference_count_;
tbb_thread** preferences_;
bool operator () (void* ctx, size_t count, size_t idx)
{
tbb_thread* th = (tbb_thread*)ctx;
size_t remain_in_waitset = count - idx;
if (remain_in_waitset <= remain_to_signal_)
{
return true;
}
else
{
for (size_t i = 0; i != preference_count_; ++i)
{
if (preferences_[i] == th)
{
remain_to_signal_ -= 1;
return true;
}
}
}
return false;
}
}
pred = {total_count, preference_count, preferences};
ec_.notify_relaxed(pred);
}
bool pool_is_empty()
{
return true;
}
};
struct queue
{
int producer_idx_;
int consumer_idx_;
void** buffer_;
eventcount ec_;
void enqueue(void* data)
{
int idx = ++producer_idx_; // atomic
buffer_[idx] = data;
struct local
{
int idx_;
bool operator () (void* ctx, size_t /*count*/, size_t /*idx*/)
{
return idx_ == *(int*)ctx;
}
}
pred = {idx};
ec_.notify(pred); // not relaxed!!!
}
void* dequeue()
{
int idx = ++consumer_idx_; // atomic
void* data = buffer_[idx];
if (data)
return data;
for (;;)
{
ec_.prepare_wait(&idx);
data = buffer_[idx];
if (data)
{
ec_.retire_wait();
return data;
}
ec_.wait();
data = buffer_[idx];
if (data)
{
return data;
}
}
}
};
class condition_variable
{
eventcount ec_;
public:
void wait(mutex& mtx)
{
ec_.prepare_wait();
mtx.unlock();
ec_.wait();
mtx.lock();
}
void signal()
{
ec_.notify_one();
}
void broadcast()
{
ec_.notify_all();
}
};
struct eventcount_test : rl::test_suite<eventcount_test, 2>
{
void thread(unsigned index)
{
delete ec_thread::current();
(void)index;
}
};
int main()
{
rl::test_params p;
//p.iteration_count = 1000000;
rl::simulate<eventcount_test>(p);
}
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eventcount", "eventcount.vcproj", "{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Debug|Win32.ActiveCfg = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Debug|Win32.Build.0 = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Release|Win32.ActiveCfg = Release|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,203 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="eventcount"
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E54}"
RootNamespace="eventcount"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
<File
RelativePath="..\eventcount.cpp"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eventcount", "eventcount.vcproj", "{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}.Debug|Win32.ActiveCfg = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}.Debug|Win32.Build.0 = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}.Release|Win32.ActiveCfg = Release|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,203 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="eventcount"
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E54}"
RootNamespace="eventcount"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
<File
RelativePath="..\eventcount.cpp"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// ws_deque.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
@@ -0,0 +1,10 @@
#pragma once
#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <intrin.h>
#include <stddef.h>
#include "../../relacy/pch.hpp"
#include "../../relacy/relacy_std.hpp"
@@ -0,0 +1,316 @@
#pragma once
struct amp_raw_condition_variable_s
{
CRITICAL_SECTION access_waiting_threads_count_critsec;
HANDLE wake_waiting_threads_mutex;
HANDLE waking_waiting_threads_count_control_sem;
HANDLE finished_waking_waiting_threads_event;
VAR_T(LONG) waiting_thread_count;
VAR_T(BOOL) broadcast_in_progress;
};
struct amp_raw_mutex_s
{
CRITICAL_SECTION critical_section;
BOOL is_locked;
};
typedef amp_raw_condition_variable_s* amp_raw_condition_variable_t;
typedef amp_raw_mutex_s* amp_raw_mutex_t;
int const AMP_SUCCESS = 0;
int amp_raw_mutex_init(amp_raw_mutex_t mutex)
{
InitializeCriticalSectionAndSpinCount(&mutex->critical_section, 1);
mutex->is_locked = FALSE;
return AMP_SUCCESS;
}
int amp_raw_mutex_finalize(amp_raw_mutex_t mutex)
{
assert(NULL != mutex);
int retval = AMP_SUCCESS;
DeleteCriticalSection(&mutex->critical_section);
return retval;
}
int amp_raw_mutex_lock(amp_raw_mutex_t mutex)
{
assert(NULL != mutex);
EnterCriticalSection(&mutex->critical_section);
mutex->is_locked = TRUE;
return AMP_SUCCESS;
}
int amp_raw_mutex_unlock(amp_raw_mutex_t mutex)
{
assert(NULL != mutex);
mutex->is_locked = FALSE;
LeaveCriticalSection(&mutex->critical_section);
return AMP_SUCCESS;
}
int amp_raw_condition_variable_init(amp_raw_condition_variable_t cond)
{
InitializeCriticalSectionAndSpinCount(&cond->access_waiting_threads_count_critsec, 1);
cond->wake_waiting_threads_mutex = CreateMutex(0, 0, 0);
cond->waking_waiting_threads_count_control_sem = CreateSemaphore(NULL, /* No inheritance to child processes */
0, /* Initially no threads can pass */
LONG_MAX, /* Max semaphore count */
NULL); /* Only intra-process semaphore */
cond->finished_waking_waiting_threads_event = CreateEvent(NULL, /* Default security and no inheritance to child processes */
FALSE, /* No manual reset */
0, /* Initially not signaled */
NULL /* Not inter-process available */
);
cond->VAR(waiting_thread_count) = 0l;
cond->VAR(broadcast_in_progress) = FALSE;
return AMP_SUCCESS;
}
int amp_raw_condition_variable_finalize(amp_raw_condition_variable_t cond)
{
DeleteCriticalSection(&cond->access_waiting_threads_count_critsec);
CloseHandle(cond->wake_waiting_threads_mutex);
CloseHandle(cond->waking_waiting_threads_count_control_sem);
CloseHandle(cond->finished_waking_waiting_threads_event);
int ret_error_code = AMP_SUCCESS;
return ret_error_code;
}
int amp_raw_condition_variable_signal(amp_raw_condition_variable_t cond)
{
WaitForSingleObject(cond->wake_waiting_threads_mutex,
INFINITE);
BOOL at_least_one_waiting_thread = (0l != cond->VAR(waiting_thread_count));
if (at_least_one_waiting_thread) {
LONG prev_sem_count = 0;
ReleaseSemaphore(cond->waking_waiting_threads_count_control_sem,
1,
&prev_sem_count /* No interest in the previous sem count. */
);
WaitForSingleObject(cond->finished_waking_waiting_threads_event,
INFINITE);
}
ReleaseMutex(cond->wake_waiting_threads_mutex);
return AMP_SUCCESS;
}
int amp_raw_condition_variable_broadcast(amp_raw_condition_variable_t cond)
{
WaitForSingleObject(cond->wake_waiting_threads_mutex,
INFINITE);
LONG const waiting_thread_count = cond->VAR(waiting_thread_count);
if (0 < waiting_thread_count) {
cond->VAR(broadcast_in_progress) = TRUE;
/* Releasing the sem here and waiting on it should update the memory of
* the waiting threads to see that a broadcast is in progress.
*/
LONG prev_sem_count = 0;
/* Assuming that less threads exist than max possible semaphore count.
* TODO: @todo Decide if to spin here if the assumption doesn't hold
* true in the future?
*/
ReleaseSemaphore(cond->waking_waiting_threads_count_control_sem,
waiting_thread_count,
&prev_sem_count /* No interest in the previous sem count. */
);
WaitForSingleObject(cond->finished_waking_waiting_threads_event,
INFINITE);
cond->VAR(broadcast_in_progress) = FALSE;
}
ReleaseMutex(cond->wake_waiting_threads_mutex);
return AMP_SUCCESS;
}
int amp_raw_condition_variable_wait(amp_raw_condition_variable_t cond,
struct amp_raw_mutex_s *mutex)
{
WaitForSingleObject(cond->wake_waiting_threads_mutex,
INFINITE);
{
++(cond->VAR(waiting_thread_count));
}
amp_raw_mutex_unlock(mutex);
SignalObjectAndWait(cond->wake_waiting_threads_mutex, cond->waking_waiting_threads_count_control_sem, INFINITE, FALSE);
BOOL broadcast_in_progress = FALSE;
LONG count = 0;
EnterCriticalSection(&cond->access_waiting_threads_count_critsec);
{
count = --(cond->VAR(waiting_thread_count));
broadcast_in_progress = cond->VAR(broadcast_in_progress);
}
LeaveCriticalSection(&cond->access_waiting_threads_count_critsec);
BOOL all_waiting_threads_awake = TRUE;
if (TRUE == broadcast_in_progress && count > 0) {
all_waiting_threads_awake = FALSE;
}
if (TRUE == all_waiting_threads_awake) {
SetEvent(cond->finished_waking_waiting_threads_event);
}
amp_raw_mutex_lock(mutex);
return AMP_SUCCESS;
}
struct amp_condvar_test : rl::test_suite<amp_condvar_test, 2>
{
VAR_T(int) data;
amp_raw_mutex_s mtx;
amp_raw_condition_variable_s cv;
void before()
{
VAR(data) = 0;
amp_raw_mutex_init(&mtx);
amp_raw_condition_variable_init(&cv);
}
void after()
{
amp_raw_mutex_finalize(&mtx);
amp_raw_condition_variable_finalize(&cv);
}
void thread(unsigned index)
{
if (0 == index)
{
amp_raw_mutex_lock(&mtx);
data($) += 1;
amp_raw_condition_variable_signal(&cv);
amp_raw_mutex_unlock(&mtx);
}
else
{
amp_raw_mutex_lock(&mtx);
while (0 == data($))
{
amp_raw_condition_variable_wait(&cv, &mtx);
}
amp_raw_mutex_unlock(&mtx);
}
}
};
struct amp_condvar_test2 : rl::test_suite<amp_condvar_test2, 4>
{
VAR_T(int) stage;
amp_raw_mutex_s mtx;
amp_raw_condition_variable_s cv;
void before()
{
VAR(stage) = 0;
amp_raw_mutex_init(&mtx);
amp_raw_condition_variable_init(&cv);
}
void after()
{
amp_raw_mutex_finalize(&mtx);
amp_raw_condition_variable_finalize(&cv);
}
void thread(unsigned index)
{
if (0 == index)
{
amp_raw_mutex_lock(&mtx);
stage($) += 1;
amp_raw_condition_variable_broadcast(&cv);
while (stage($) < 2)
amp_raw_condition_variable_wait(&cv, &mtx);
amp_raw_mutex_unlock(&mtx);
}
else if (1 == index)
{
amp_raw_mutex_lock(&mtx);
while (stage($) != 1)
amp_raw_condition_variable_wait(&cv, &mtx);
stage($) += 1;
amp_raw_condition_variable_broadcast(&cv);
amp_raw_mutex_unlock(&mtx);
}
else if (2 == index)
{
amp_raw_mutex_lock(&mtx);
while (stage($) != 2)
amp_raw_condition_variable_wait(&cv, &mtx);
stage($) += 1;
//amp_raw_condition_variable_broadcast(&cv);
amp_raw_mutex_unlock(&mtx);
amp_raw_condition_variable_signal(&cv);
}
else if (3 == index)
{
amp_raw_mutex_lock(&mtx);
while (stage($) != 3)
amp_raw_condition_variable_wait(&cv, &mtx);
amp_raw_mutex_unlock(&mtx);
}
}
};
@@ -0,0 +1,17 @@
#include "stdafx.h"
#include "spsc_overwrite_queue.hpp"
#include "amp_condvar.hpp"
int main()
{
rl::test_params p;
p.iteration_count = 10000;
//p.search_type = rl::sched_bound;
//p.context_bound = 3;
rl::execute<spsc_overwrite_queue_test, 2>(p);
rl::simulate<amp_condvar_test>(p);
rl::simulate<amp_condvar_test2>(p);
}
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "examples", "examples.vcproj", "{6CC59CF8-408B-441B-8F65-15651210CB82}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6CC59CF8-408B-441B-8F65-15651210CB82}.Debug|Win32.ActiveCfg = Debug|Win32
{6CC59CF8-408B-441B-8F65-15651210CB82}.Debug|Win32.Build.0 = Debug|Win32
{6CC59CF8-408B-441B-8F65-15651210CB82}.Release|Win32.ActiveCfg = Release|Win32
{6CC59CF8-408B-441B-8F65-15651210CB82}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="examples"
ProjectGUID="{1EB73A6F-7F94-4ED4-8EB3-C245E773207A}"
RootNamespace="examples"
Keyword="Win32Proj"
TargetFrameworkVersion="0"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\amp_condvar.hpp"
>
</File>
<File
RelativePath="..\examples.cpp"
>
</File>
<File
RelativePath="..\spsc_overwrite_queue.hpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,202 @@
#pragma once
template<typename T>
class queue
{
public:
queue(size_t count)
{
assert(count >= 6);
sema = CreateSemaphore(0, 0, 1, 0);
waiting.store(false, std::memory_order_relaxed);
deq_node = 0;
block = new node [count];
block->next.store(0, std::memory_order_relaxed);
full_tail = block;
full_head.store(block, std::memory_order_relaxed);
free_head = block + 1;
free_tail.store(block + count - 1, std::memory_order_relaxed);
free_tail.load(std::memory_order_relaxed)->next.store(0, std::memory_order_relaxed);
for (size_t i = 1; i != count - 1; i += 1)
block[i].next.store(block + i + 1, std::memory_order_relaxed);
}
~queue()
{
CloseHandle(sema);
delete [] block;
}
VAR_T(T)& enqueue_prepare()
{
return full_tail->data;
}
void enqueue_commit()
{
node* n = get_free_node();
n->next.store(0, std::memory_order_release);
full_tail->next.store(n, std::memory_order_seq_cst);
bool signal = waiting.load(std::memory_order_seq_cst);
full_tail = n;
if (signal)
{
waiting.store(false, std::memory_order_relaxed);
ReleaseSemaphore(sema, 1, 0);
}
}
VAR_T(T)& dequeue_prepare()
{
deq_node = get_full_node();
return deq_node->data;
}
void dequeue_commit()
{
deq_node->next.store(0, std::memory_order_release);
node* prev = free_tail.exchange(deq_node, std::memory_order_acq_rel);
prev->next.store(deq_node, std::memory_order_release);
}
private:
struct node
{
std::atomic<node*> next;
VAR_T(T) data;
};
node* block;
node* full_tail;
node* free_head;
node* deq_node;
char pad [64];
std::atomic<node*> full_head;
std::atomic<node*> free_tail;
std::atomic<bool> waiting;
HANDLE sema;
node* get_free_node()
{
for (;;)
{
node* n = free_head;
node* next = n->next.load(std::memory_order_acquire);
if (next)
{
free_head = next;
return n;
}
n = full_head.load(std::memory_order_acquire);
next = n->next.load(std::memory_order_acquire);
if (next)
{
if (full_head.compare_exchange_strong(n, next, std::memory_order_seq_cst))
{
//node* n2 = free_head;
//node* next2 = n2->next.load(std::memory_order_acquire);
//if (next2)
//{
// n->next.store(0, std::memory_order_release);
// node* prev = free_tail.exchange(n, std::memory_order_acq_rel);
// prev->next.store(n, std::memory_order_release);
// free_head = next2;
// return n2;
//}
//else
{
return n;
}
}
}
}
}
node* get_full_node()
{
node* n = full_head.load(std::memory_order_acquire);
for (;;)
{
node* next = n->next.load(std::memory_order_acquire);
if (next == 0)
{
waiting.store(true, std::memory_order_seq_cst);
n = full_head.load(std::memory_order_seq_cst);
next = n->next.load(std::memory_order_acquire);
if (next)
{
waiting.store(false, std::memory_order_relaxed);
}
else
{
WaitForSingleObject(sema, INFINITE);
n = full_head.load(std::memory_order_acquire);
continue;
}
}
if (full_head.compare_exchange_strong(n, next, std::memory_order_acq_rel))
return n;
}
}
};
unsigned RL_STDCALL consumer_thread(void* ctx)
{
queue<int>* q = (queue<int>*)ctx;
int prev_data = -1;
for (;;)
{
VAR_T(int)& data0 = q->dequeue_prepare();
int data = VAR(data0);
assert(data > prev_data);
prev_data = data;
q->dequeue_commit();
//printf("%d\n", prev_data);
if (prev_data == 11)
break;
//Sleep(5);
}
return 0;
}
unsigned RL_STDCALL producer_thread(void* ctx)
{
queue<int>* q = (queue<int>*)ctx;
for (int i = 0; i != 12; i += 1)
{
VAR_T(int)& data = q->enqueue_prepare();
VAR(data) = i;
q->enqueue_commit();
//Sleep(1);
}
return 0;
}
void spsc_overwrite_queue_test()
{
queue<int> q (6);
HANDLE th [2];
th[0] = (HANDLE)_beginthreadex(0, 0, consumer_thread, &q, 0, 0);
th[1] = (HANDLE)_beginthreadex(0, 0, producer_thread, &q, 0, 0);
WaitForMultipleObjects(2, th, 1, INFINITE);
for (int i = 100; i != 104; i += 1)
{
VAR_T(int)& data = q.enqueue_prepare();
VAR(data) = i;
q.enqueue_commit();
}
for (int i = 100; i != 104; i += 1)
{
VAR_T(int)& data0 = q.dequeue_prepare();
int data = VAR(data0);
assert(data == i);
q.dequeue_commit();
}
}
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,16 @@
#pragma once
#ifdef NDEBUG
# define _SECURE_SCL 0
#endif
#define RL_FORCE_SEQ_CST
#define RL_MSVC_OUTPUT
//#define RL_DEBUGBREAK_ON_FAILURE
#include "../../relacy/pch.hpp"
#include "../../relacy/relacy_std.hpp"
#include "../../relacy/stdlib/windows.hpp"
@@ -0,0 +1,195 @@
#include "stdafx.h"
#include "../../relacy/relacy_java.hpp"
using rl::jvar;
using rl::jvolatile;
using rl::mutex;
template<typename T>
class ws_deque
{
public:
ws_deque()
{
m_mask($) = initial_size - 1;
m_headIndex($) = 0;
m_tailIndex($) = 0;
m_array($) = new jvar<T> [initial_size];
m_arraySize($) = initial_size;
}
bool IsEmpty()
{
return m_headIndex($) >= m_tailIndex($);
}
size_t Count()
{
return m_tailIndex($) - m_headIndex($);
}
void push(T item)
{
size_t tail = m_tailIndex($);
if (tail <= m_headIndex($) + m_mask($))
{
m_array($)[tail & m_mask($)]($) = item;
m_tailIndex($) = tail + 1;
}
else
{
m_foreignLock.lock($);
size_t head = m_headIndex($);
size_t count = Count();
if (count >= m_mask($))
{
size_t arraySize = m_arraySize($);
size_t mask = m_mask($);
jvar<T>* newArray = new jvar<T> [arraySize * 2];
jvar<T>* arr = m_array($);
for (size_t i = 0; i != count; ++i)
newArray[i]($) = arr[(i + head) & mask]($);
m_array($) = newArray;
m_arraySize($) = arraySize * 2;
m_headIndex($) = 0;
m_tailIndex($) = count;
tail = count;
m_mask($) = (mask * 2) | 1;
}
m_array($)[tail & m_mask($)]($) = item;
m_tailIndex($) = tail + 1;
m_foreignLock.unlock($);
}
}
bool pop(T& item)
{
size_t tail = m_tailIndex($);
if (tail == 0)
return false;
tail -= 1;
m_tailIndex($) = tail;
if (m_headIndex($) <= tail)
{
item = m_array($)[tail & m_mask($)]($);
return true;
}
else
{
m_foreignLock.lock($);
if (m_headIndex($) <= tail)
{
item = m_array($)[tail & m_mask($)]($);
m_foreignLock.unlock($);
return true;
}
else
{
m_tailIndex($) = tail + 1;
m_foreignLock.unlock($);
return false;
}
}
}
bool steal(T& item)
{
if (false == m_foreignLock.try_lock($))
return false;
size_t head = m_headIndex($);
m_headIndex($) = head + 1;
if (head < m_tailIndex($))
{
item = m_array($)[head & m_mask($)]($);
m_foreignLock.unlock($);
return true;
}
else
{
m_headIndex($) = head;
m_foreignLock.unlock($);
return false;
}
}
private:
static size_t const initial_size = 2;
jvar<jvar<T>*> m_array;
jvar<size_t> m_mask;
jvar<size_t> m_arraySize;
jvolatile<size_t> m_headIndex;
jvolatile<size_t> m_tailIndex;
mutex m_foreignLock;
};
struct ws_deque_test : rl::test_suite<ws_deque_test, 2>
{
ws_deque<int> q;
bool state [2];
void before()
{
state[0] = true;
state[1] = true;
}
void after()
{
RL_ASSERT(state[0] == false);
RL_ASSERT(state[1] == false);
}
void thread(unsigned index)
{
if (0 == index)
{
q.push(1);
q.push(2);
int item = 0;
bool res = q.pop(item);
RL_ASSERT(res && item == 2);
RL_ASSERT(state[1]);
state[1] = false;
item = 0;
res = q.pop(item);
if (res)
{
RL_ASSERT(state[0]);
state[0] = false;
}
item = 0;
res = q.pop(item);
RL_ASSERT(res == false);
}
else
{
int item = 0;
bool res = q.steal(item);
if (res)
{
RL_ASSERT(item == 1);
RL_ASSERT(state[0]);
state[0] = false;
}
}
}
};
int main()
{
rl::simulate<ws_deque_test>();
}
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "java_ws_deque", "java_ws_deque.vcproj", "{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.ActiveCfg = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.Build.0 = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.ActiveCfg = Release|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="java_ws_deque"
ProjectGUID="{9E88433F-779E-4461-9963-35E3338873AC}"
RootNamespace="java_ws_deque"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\java_ws_deque.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,7 @@
#pragma once
#include "../../relacy/pch.hpp"
@@ -0,0 +1,511 @@
#include "stdafx.h"
#ifdef RL_TEST
#define ATOMIC(x) rl::atomic<x>
#define VAR(x) rl::var<x>
#define ATOMIC_FETCH_ADD(x, v) x($).fetch_add(v)
#define ATOMIC_COMPARE_EXCHANGE(x, c, v) x($).compare_exchange(c, v)
#define LOAD_ACQ(x) x($).load(rl::memory_order_acquire)
#define STORE_REL(x, v) x($).store(v, rl::memory_order_release)
#else
#define ATOMIC(x) x volatile
#define VAR(x) x
#define ATOMIC_FETCH_ADD(x, v) _InterlockedExchangeAdd((long*)&x, v)
#define ATOMIC_COMPARE_EXCHANGE(x, c, v) interlocked_compare_exchange(x, c, v)
#define LOAD_ACQ(x) x
#define STORE_REL(x, v) x = v
template<typename T>
bool interlocked_compare_exchange(T& x, T& c, T v)
{
T c0 = _InterlockedCompareExchange((long*)&x), v, c);
if (c0 == c)
{
return true;
}
else
{
c = c0;
return false;
}
}
#endif
//#include "pcx.h"
/*
template<typename T>
class mpmcq
{
public:
mpmcq()
{
STORE_REL(head_, alloc_block());
STORE_REL(tail_, LOAD_ACQ(head_));
}
void enqueue(T v)
{
for (;;)
{
block* b = LOAD_ACQ(head_);
unsigned raw = ATOMIC_FETCH_ADD(b->state_, state_head_inc);
unsigned idx = raw >> state_head_pos;
if (idx < item_count)
{
STORE_REL(b->data_[idx], v);
return;
}
unsigned last = raw & state_last_msk;
if (0 == last)
{
ATOMIC_COMPARE_EXCHANGE(head_, b, b+1);
}
else
{
block* b2 = LOAD_ACQ(b->next_);
if (b2)
{
ATOMIC_COMPARE_EXCHANGE(head_, b, b2);
}
else
{
b2 = alloc_block();
block* b3 = 0;
if (ATOMIC_COMPARE_EXCHANGE(b->next_, b3, b2))
{
ATOMIC_COMPARE_EXCHANGE(head_, b, b2);
}
else
{
for (;;)
{
b = LOAD_ACQ(head_);
while (0 == (LOAD_ACQ(b->state_) & state_last_msk))
b = b + 1;
while (LOAD_ACQ(b->next_))
b = LOAD_ACQ(b->next_) + block_count - 1;
b3 = 0;
if (ATOMIC_COMPARE_EXCHANGE(b->next_, b3, b2))
break;
}
}
}
}
}
}
T dequeue()
{
for (;;)
{
block* b = LOAD_ACQ(tail_);
unsigned cmp = LOAD_ACQ(b->state_);
unsigned tail = cmp & (state_last_msk - 1);
if (tail < item_count)
{
unsigned head = cmp >> state_head_pos;
if (tail < head)
{
unsigned xchg = cmp + state_tail_inc;
if (ATOMIC_COMPARE_EXCHANGE(b->state_, cmp, xchg))
{
for (;;)
{
T v = LOAD_ACQ(b->data_[tail]);
if (v != T())
return v;
rl::yield($);
}
}
}
else
{
return T();
}
}
else
{
unsigned last = cmp & state_last_msk;
if (0 == last)
{
ATOMIC_COMPARE_EXCHANGE(tail_, b, b+1);
}
else
{
block* b2 = LOAD_ACQ(b->next_);
if (0 == b2)
return T();
ATOMIC_COMPARE_EXCHANGE(tail_, b, b2);
}
}
}
}
private:
static unsigned const state_head_pos = 7;
static unsigned const state_head_inc = 1 << state_head_pos;
static unsigned const state_last_msk = 1 << 6;
static unsigned const state_tail_inc = 1 << 0;
static unsigned const item_count = 2;
static unsigned const block_count = 16;
struct block
{
//unsigned head_ : 24;
//unsigned last_ : 1;
//unsigned tail_ : 7;
ATOMIC(unsigned) state_;
ATOMIC(block*) next_;
ATOMIC(T) data_ [item_count];
};
struct superblock
{
block blocks_ [block_count];
};
char pad0_ [64];
ATOMIC(block*) head_;
char pad1_ [64];
ATOMIC(block*) tail_;
char pad2_ [64];
block* alloc_block()
{
superblock* sb = RL_NEW(superblock);
for (int x = 0; x != block_count; ++x)
{
block* b = &sb->blocks_[x];
STORE_REL(b->state_, 0);
STORE_REL(b->next_, 0);
for (int y = 0; y != item_count; ++y)
{
STORE_REL(b->data_[y], 0);
}
}
STORE_REL(sb->blocks_[block_count - 1].state_, 1 * state_head_inc + 1 * state_tail_inc + state_last_msk);
return &sb->blocks_[0];
}
};
struct test_mpmc : rl::test_suite<test_mpmc, 6>
{
mpmcq<int> q;
void thread(unsigned idx)
{
if (idx < thread_count / 2)
{
for (int i = 0; i != 2; ++i)
q.enqueue(1);
}
else
{
for (int i = 0; i != 2; ++i)
q.dequeue();
}
}
};
*/
struct thread_node
{
rl::var<thread_node*> next;
rl::var<size_t> count;
rl::var<size_t> unconsumed;
rl::HANDLE sema;
rl::CRITICAL_SECTION mtx;
};
void on_thread_exit(thread_node*& t_thread_node)
{
thread_node* head = t_thread_node;
thread_node* my = 0;
if (head)
{
rl::EnterCriticalSection(&head->mtx, $);
std::atomic_thread_fence($)(std::memory_order_seq_cst);
if (head->next($))
{
my = head->next($);
head->next($) = (thread_node*)my->next($);
}
else
{
my = head;
}
std::atomic_thread_fence($)(std::memory_order_seq_cst);
rl::LeaveCriticalSection(&head->mtx, $);
while (my->unconsumed($))
{
rl::WaitForSingleObject(my->sema, rl::RL_INFINITE, $);
my->unconsumed($) -= 1;
}
rl::DeleteCriticalSection(&my->mtx, $);
rl::CloseHandle(my->sema, $);
RL_DELETE(my);
}
}
struct eventcount
{
eventcount()
{
root($) = 0;
rl::InitializeCriticalSection(&mtx, $);
}
~eventcount()
{
rl::DeleteCriticalSection(&mtx, $);
}
void prepare_wait(thread_node*& t_thread_node)
{
thread_node* my = 0;
thread_node* head = t_thread_node;
if (head)
{
rl::EnterCriticalSection(&head->mtx, $);
std::atomic_thread_fence($)(std::memory_order_seq_cst);
//RL_ASSERT(head->status == stat_root);
RL_ASSERT (root($) != head);
if (head->next($))
{
my = head->next($);
head->next($) = (thread_node*)my->next($);
my->next($) = 0;
//node_status st;
//if (stat_bucket != (st = (node_status)_InterlockedExchange(&my->status, stat_private)))
// __asm int 3;
RL_ASSERT (0 == my->count($));
}
else
{
my = head;
//node_status st;
//if (stat_root != (st = (node_status)_InterlockedExchange(&my->status, stat_private)))
// __asm int 3;
RL_ASSERT(0 == my->count($));
}
std::atomic_thread_fence($)(std::memory_order_seq_cst);
rl::LeaveCriticalSection(&head->mtx, $);
}
else
{
my = RL_NEW thread_node;
my->next($) = 0;
my->count($) = 0;
my->unconsumed($) = 0;
my->sema = rl::CreateSemaphore(0, 0, LONG_MAX, 0, $);
//my->status = stat_private;
rl::InitializeCriticalSection(&my->mtx, $);
}
while (my->unconsumed($))
{
rl::WaitForSingleObject(my->sema, rl::RL_INFINITE, $);
my->unconsumed($) -= 1;
}
RL_ASSERT(0 == my->next($));
RL_ASSERT(0 == my->count($));
//if (my->status != stat_private) __asm int 3;
rl::EnterCriticalSection(&mtx, $);
std::atomic_thread_fence($)(std::memory_order_seq_cst);
RL_ASSERT(root($) != my);
if (root($))
{
my->next($) = (thread_node*)((thread_node*)root($))->next($);
((thread_node*)root($))->next($) = my;
//node_status st;
//if (stat_private != (st = (node_status)_InterlockedExchange(&my->status, stat_bucket)))
// __asm int 3;
my = root($);
}
else
{
root($) = my;
//node_status st;
//if (stat_private != (st = (node_status)_InterlockedExchange(&my->status, stat_root)))
// __asm int 3;
}
((thread_node*)root($))->count($) += 1;
std::atomic_thread_fence($)(std::memory_order_seq_cst);
rl::LeaveCriticalSection(&mtx, $);
t_thread_node = my;
}
void wait(thread_node*& t_thread_node)
{
thread_node* head = t_thread_node;
if (head == root($))
{
rl::WaitForSingleObject(head->sema, rl::RL_INFINITE, $);
}
else
{
rl::EnterCriticalSection(&head->mtx, $);
std::atomic_thread_fence($)(std::memory_order_seq_cst);
head->unconsumed($) += 1;
std::atomic_thread_fence($)(std::memory_order_seq_cst);
rl::LeaveCriticalSection(&head->mtx, $);
}
}
void retire_wait(thread_node*& t_thread_node)
{
thread_node* head = t_thread_node;
if (head == root($))
{
rl::EnterCriticalSection(&mtx, $);
std::atomic_thread_fence($)(std::memory_order_seq_cst);
if (head == root($))
{
thread_node* my = 0;
head->count($) -= 1;
if (head->next($))
{
my = head->next($);
head->next($) = (thread_node*)my->next($);
my->next($) = 0;
}
else
{
my = head;
root($) = 0;
}
std::atomic_thread_fence($)(std::memory_order_seq_cst);
rl::LeaveCriticalSection(&mtx, $);
//my->status = stat_root;
t_thread_node = my;
return;
}
std::atomic_thread_fence($)(std::memory_order_seq_cst);
rl::LeaveCriticalSection(&mtx, $);
}
rl::EnterCriticalSection(&head->mtx, $);
std::atomic_thread_fence($)(std::memory_order_seq_cst);
head->unconsumed($) += 1;
std::atomic_thread_fence($)(std::memory_order_seq_cst);
rl::LeaveCriticalSection(&head->mtx, $);
}
void signal_all()
{
//std::
//_mm_mfence();
thread_node* head = root($);
if (0 == head)
return;
rl::EnterCriticalSection(&mtx, $);
std::atomic_thread_fence($)(std::memory_order_seq_cst);
if (head != root($))
{
std::atomic_thread_fence($)(std::memory_order_seq_cst);
rl::LeaveCriticalSection(&mtx, $);
return;
}
size_t count = head->count($);
head->count($) = 0;
root($) = 0;
std::atomic_thread_fence($)(std::memory_order_seq_cst);
rl::LeaveCriticalSection(&mtx, $);
rl::ReleaseSemaphore(head->sema, count, 0, $);
}
std::atomic<thread_node*> root;
rl::CRITICAL_SECTION mtx;
};
struct test_ec : rl::test_suite<test_ec, 8>
{
std::atomic<int> x [2];
eventcount ec;
void before()
{
x[0]($) = 0;
x[1]($) = 0;
}
void thread(unsigned idx)
{
if (idx < 4)
{
for (int i = 0; i != 3; ++i)
{
x[idx % 2]($).fetch_add(1);
ec.signal_all();
}
}
else
{
thread_node* my = 0;
for (int i = 0; i != 3; ++i)
{
for (;;)
{
int cmp = x[idx % 2]($);
if (cmp > 0)
{
if (x[idx % 2]($).compare_exchange(cmp, cmp - 1))
break;
}
else
{
for (;;)
{
ec.prepare_wait(my);
cmp = x[idx % 2]($);
if (cmp > 0)
{
ec.retire_wait(my);
break;
}
ec.wait(my);
cmp = x[idx % 2]($);
if (cmp > 0)
{
break;
}
}
}
}
}
on_thread_exit(my);
}
}
};
int main()
{
rl::test_params p;
p.iteration_count = 20000000;
p.initial_state = "10000000";
rl::simulate<test_ec>(p);
}
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mpmc", "mpmc.vcproj", "{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}.Debug|Win32.ActiveCfg = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}.Debug|Win32.Build.0 = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}.Release|Win32.ActiveCfg = Release|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="mpmc"
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E4}"
RootNamespace="mpmc"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\mpmc.cpp"
>
</File>
<File
RelativePath="..\pcx.h"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,481 @@
#pragma once
#include <intrin.h>
#pragma intrinsic (_InterlockedExchangeAdd)
#pragma intrinsic (_InterlockedCompareExchange)
//#define PCX_DEBUG
#ifdef PCX_DEBUG
#include <sstream>
#include <windows.h>
#endif
namespace rl
{
size_t const cacheline_size = 64;
struct pcx_node
{
typedef void (*pcx_dtor_t)(pcx_node*);
ATOMIC(pcx_node*) pcx_next_;
ATOMIC(pcx_dtor_t) pcx_dtor_;
};
namespace pcx_int
{
unsigned const word_bits = 32;
unsigned const collector_bits = 4;
unsigned const collector_count = 1 << collector_bits;
unsigned const counter_inc = 1 << (collector_bits * 2);
unsigned const is_current_inc = 1;
unsigned const back_link_inc = 2;
struct master;
struct collector;
struct local_collector
{
pcx_node* defer_head_;
pcx_node defer_tail_;
unsigned defer_size_;
};
struct thread_int
{
pcx_int::master* master_;
pcx_int::collector* collectors_;
unsigned recursion_count_;
unsigned is_acquired_;
unsigned collector_index_;
unsigned last_seen_collector_index_;
unsigned flush_tail_;
pcx_node* defer_head_;
pcx_node defer_tail_;
unsigned defer_size_;
unsigned promote_;
local_collector local_collectors_ [collector_count];
};
}
class pcx_thread : private pcx_int::thread_int
{
public:
static pcx_thread& get();
void acquire();
void release();
void defer(pcx_node* node, pcx_node::pcx_dtor_t dtor);
void flush();
void promote();
void quiescent();
void init();
void deinit();
private:
unsigned acquire_impl();
void release_impl(unsigned, unsigned);
void flush_impl();
void local_flush();
void quiescent_impl();
friend void init();
friend void deinit();
friend void thread_callback(bool);
};
namespace pcx_int
{
struct master
{
char pad0_ [64];
unsigned garbage_threshold_;
char pad1_ [64];
struct state_part
{
unsigned current_collector_ : collector_bits;
unsigned collector_tail_ : collector_bits;
unsigned outer_counter_ : word_bits - 2 * collector_bits;
};
union state
{
long whole_;
state_part part_;
};
state state_;
char pad2_ [64];
state state_copy_;
char pad3_ [64];
};
struct collector
{
char pad0_ [64];
pcx_node* defer_list_head_;
unsigned defer_list_size_;
char pad1_ [64];
struct state_part
{
unsigned is_current_ : 1;
unsigned back_link_ : 1;
unsigned pad_ : collector_bits * 2 - 2;
unsigned inner_counter_ : word_bits - 2 * collector_bits;
};
union state
{
long whole_;
state_part part_;
};
state state_;
char pad2_ [64];
};
__declspec(selectany)
master g_master;
__declspec(selectany)
collector g_collectors [collector_count];
__declspec(selectany, thread)
thread_int* g_thread_instance;
typedef void (__stdcall nt_tls_cb_t)(void*, unsigned long, void*);
nt_tls_cb_t on_tls_callback;
#pragma data_seg(push, old_seg)
#pragma data_seg(".CRT$XLB")
__declspec(selectany, dllexport)
nt_tls_cb_t* volatile p_thread_callback = on_tls_callback;
#pragma data_seg(pop, old_seg)
inline void __stdcall on_tls_callback(void*, unsigned long reason, void*)
{
if (1 == reason)
{
init();
thread_callback(true);
}
else if (0 == reason)
{
thread_callback(false);
deinit();
}
if (2 == reason)
{
thread_callback(true);
}
else if (3 == reason)
{
thread_callback(false);
}
}
}
inline void init()
{
using namespace pcx_int;
master& m = g_master;
m.garbage_threshold_ = 128;
m.state_.part_.current_collector_ = 0;
m.state_.part_.collector_tail_ = 0;
m.state_.part_.outer_counter_ = 0;
m.state_copy_.part_.current_collector_ = 0;
m.state_copy_.part_.collector_tail_ = 0;
m.state_copy_.part_.outer_counter_ = 0;
for (unsigned i = 0; i != collector_count; ++i)
{
collector& c = g_collectors[i];
c.defer_list_head_ = 0;
c.defer_list_size_ = 0;
c.state_.part_.is_current_ = 1;
c.state_.part_.back_link_ = 1;
c.state_.part_.inner_counter_ = 0;
}
g_collectors[0].state_.part_.back_link_ = 0;
}
inline void deinit()
{
using namespace pcx_int;
pcx_thread::get().release_impl(g_master.state_.part_.current_collector_, is_current_inc);
}
inline void thread_callback(bool init)
{
if (init)
{
g_thread_instance = RL_NEW pcx_thread ();
pcx_thread::get().init();
}
else
{
pcx_thread::get().deinit();
RL_DELETE(g_thread_instance);
g_thread_instance = 0;
}
}
inline pcx_thread& pcx_thread::get()
{
return static_cast<pcx_thread&>(*pcx_int::g_thread_instance);
}
inline unsigned pcx_thread::acquire_impl()
{
using namespace pcx_int;
long const prev =
_InterlockedExchangeAdd(
&master_->state_.whole_, counter_inc);
master::state_part u = {prev};
#ifdef PCX_DEBUG
std::ostringstream ss;
ss << "[PCX] thread " << this << " acquire " << u.current_collector_ << "\n";
OutputDebugStringA(ss.str().c_str());
#endif
if (u.current_collector_ == flush_tail_
&& local_collectors_[flush_tail_].defer_size_)
{
local_flush();
}
return u.current_collector_;
}
inline void pcx_thread::release_impl(unsigned index, unsigned count)
{
using namespace pcx_int;
collector& c = collectors_[index];
unsigned const prev =
_InterlockedExchangeAdd(
&c.state_.whole_, (unsigned)-(int)count);
#ifdef PCX_DEBUG
std::ostringstream ss;
ss << "[PCX] thread " << this << " release " << index << "\n";
OutputDebugStringA(ss.str().c_str());
#endif
if (0 == prev - count)
{
pcx_node* curr = c.defer_list_head_;
while (curr)
{
pcx_node* next = curr->pcx_next_;
curr->pcx_dtor_(curr);
curr = next;
}
c.defer_list_head_ = 0;
c.defer_list_size_ = 0;
c.state_.part_.back_link_ = 1;
c.state_.part_.is_current_ = 1;
long u;
if (index != collector_count - 1)
u = collector_count;
else
u = -(long)(collector_count * (collector_count - 1));
_InterlockedExchangeAdd(&master_->state_.whole_, u);
release_impl((index + 1) % collector_count, back_link_inc);
}
}
inline void pcx_thread::flush_impl()
{
using namespace pcx_int;
_mm_mfence();
master::state state = master_->state_;
last_seen_collector_index_ = state.part_.current_collector_;
collector& gc = collectors_[state.part_.current_collector_];
local_collector& lc = local_collectors_[state.part_.current_collector_];
lc.defer_head_->pcx_next_ = defer_tail_.pcx_next_;
lc.defer_head_ = defer_tail_.pcx_next_;
lc.defer_size_ += defer_size_;
defer_head_ = &defer_tail_;
defer_tail_.pcx_next_ = 0;
defer_size_ = 0;
if (master_->garbage_threshold_ < lc.defer_size_ || promote_)
{
master::state cmp;
master::state val;
do
{
cmp = master_->state_;
if (cmp.part_.current_collector_ != last_seen_collector_index_)
{
promote_ = 0;
return;
}
unsigned next_index = (last_seen_collector_index_ + 1) % collector_count;
if (cmp.part_.collector_tail_ == next_index)
return;
val = cmp;
val.part_.current_collector_ += 1;
val.part_.outer_counter_ = 0;
}
while (cmp.whole_ != _InterlockedCompareExchange(
(long*)&master_->state_.whole_, val.whole_, cmp.whole_));
last_seen_collector_index_ = val.part_.current_collector_;
promote_ = 0;
_InterlockedIncrement((long*)&master_->state_copy_.whole_);
_InterlockedExchangeAdd((long*)&gc.state_.whole_,
cmp.part_.outer_counter_ * counter_inc - is_current_inc);
}
}
__declspec(noinline)
inline void pcx_thread::local_flush()
{
using namespace pcx_int;
if (flush_tail_ == master_->state_.part_.collector_tail_)
return;
#ifdef PCX_DEBUG
std::ostringstream ss;
ss << "[PCX] thread " << this << " flush " << flush_tail_ << "\n";
OutputDebugStringA(ss.str().c_str());
#endif
local_collector& lc = local_collectors_[flush_tail_];
pcx_node* curr = lc.defer_tail_.pcx_next_;
while (curr)
{
#ifdef PCX_DEBUG
std::ostringstream ss;
ss << "[PCX] thread " << this << " destroy " << curr << "\n";
OutputDebugStringA(ss.str().c_str());
#endif
pcx_node* next = curr->pcx_next_;
curr->pcx_dtor_(curr);
curr = next;
}
lc.defer_head_ = &lc.defer_tail_;
lc.defer_tail_.pcx_next_ = 0;
lc.defer_size_ = 0;
flush_tail_ = (flush_tail_ + 1) % collector_count;
}
__declspec(noinline)
inline void pcx_thread::quiescent_impl()
{
using namespace pcx_int;
if (defer_size_)
flush_impl();
release_impl(collector_index_, counter_inc);
collector_index_ = acquire_impl();
}
inline void pcx_thread::acquire()
{
using namespace pcx_int;
recursion_count_ += 1;
if (1 != recursion_count_)
return;
if (is_acquired_)
return;
collector_index_ = acquire_impl();
last_seen_collector_index_ = collector_index_;
is_acquired_ = 1;
}
inline void pcx_thread::release()
{
using namespace pcx_int;
recursion_count_ -= 1;
if (0 == recursion_count_)
{
if (master_->state_copy_.part_.current_collector_ != collector_index_
|| promote_)
{
if (defer_size_)
flush_impl();
release_impl(collector_index_, counter_inc);
is_acquired_ = 0;
}
}
if (flush_tail_ != last_seen_collector_index_)
{
local_flush();
}
}
inline void pcx_thread::quiescent()
{
if (master_->state_copy_.part_.current_collector_ != collector_index_
|| promote_)
{
quiescent_impl();
}
if (flush_tail_ != last_seen_collector_index_)
{
local_flush();
}
}
inline void pcx_thread::defer(pcx_node* node, pcx_node::pcx_dtor_t dtor)
{
using namespace pcx_int;
node->pcx_next_ = 0;
node->pcx_dtor_ = dtor;
defer_head_->pcx_next_ = node;
defer_head_ = node;
defer_size_ += 1;
}
inline void pcx_thread::flush()
{
using namespace pcx_int;
if (recursion_count_)
return;
if (0 == is_acquired_)
return;
if (defer_size_)
flush_impl();
release_impl(collector_index_, counter_inc);
is_acquired_ = 0;
}
inline void pcx_thread::promote()
{
promote_ = 1;
}
inline void pcx_thread::init()
{
using namespace pcx_int;
master_ = &g_master;
collectors_ = g_collectors;
defer_head_ = &defer_tail_;
defer_tail_.pcx_next_ = 0;
for (unsigned i = 0; i != collector_count; ++i)
{
local_collectors_[i].defer_head_ = &local_collectors_[i].defer_tail_;
}
}
inline void pcx_thread::deinit()
{
flush();
}
}
@@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// ws_deque.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
@@ -0,0 +1,10 @@
#pragma once
#pragma warning (disable: 4201)
//#define RL_GC
#define RL_MSVC_OUTPUT
#include "../../relacy/pch.hpp"
#include "../../relacy/relacy_std.hpp"
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mutex_business_logic", "mutex_business_logic.vcproj", "{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.ActiveCfg = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.Build.0 = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.ActiveCfg = Release|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="mutex_business_logic"
ProjectGUID="{B03A7216-E196-44C6-8861-C77D90055512}"
RootNamespace="mutex_business_logic"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\mutex_business_logic.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,131 @@
#include "stdafx.h"
#include "../../relacy/relacy_std.hpp"
class business_logic
{
public:
typedef unsigned account_id_t;
typedef double balance_t;
business_logic()
{
pthread_rwlock_init(&accounts_guard, 0);
}
~business_logic()
{
pthread_rwlock_destroy(&accounts_guard);
}
bool add_account(account_id_t acc_id, balance_t balance)
{
pthread_rwlock_wrlock(&accounts_guard);
if (accounts.find(acc_id) != accounts.end())
{
pthread_rwlock_unlock(&accounts_guard);
return false;
}
accounts[acc_id].balance = balance;
pthread_rwlock_unlock(&accounts_guard);
return true;
}
bool transfer_balance(account_id_t acc_id1, account_id_t acc_id2, balance_t amount)
{
if (acc_id1 == acc_id2)
return true;
pthread_rwlock_rdlock(&accounts_guard);
if (accounts.find(acc_id1) == accounts.end()
|| accounts.find(acc_id2) == accounts.end())
{
pthread_rwlock_unlock(&accounts_guard);
return false;
}
account_info& acc1 = accounts[acc_id1];
account_info& acc2 = accounts[acc_id2];
if (acc_id1 > acc_id2)
{
pthread_mutex_lock(&acc1.mtx);
pthread_mutex_lock(&acc2.mtx);
}
else
{
pthread_mutex_lock(&acc2.mtx);
pthread_mutex_lock(&acc1.mtx);
}
pthread_rwlock_unlock(&accounts_guard);
acc1.balance -= amount;
acc2.balance += amount;
pthread_mutex_unlock(&acc1.mtx);
pthread_mutex_unlock(&acc2.mtx);
return true;
}
private:
struct account_info
{
balance_t balance;
pthread_mutex_t mtx;
account_info()
: balance()
{
pthread_mutex_init(&mtx, 0);
}
account_info(account_info const& acc)
: balance(acc.balance)
{
pthread_mutex_init(&mtx, 0);
}
~account_info()
{
pthread_mutex_destroy(&mtx);
}
};
typedef std::map<account_id_t, account_info> account_map_t;
account_map_t accounts;
pthread_rwlock_t accounts_guard;
};
struct business_logic_test : rl::test_suite<business_logic_test, 2>
{
business_logic bl;
static size_t const account_count = 4;
void before()
{
for (size_t i = 0; i != account_count; ++i)
{
bool rv = bl.add_account(i, i * 10.0);
RL_ASSERT(rv);
}
}
void thread(unsigned /*index*/)
{
business_logic::account_id_t acc1 = rl::rand(account_count);
business_logic::account_id_t acc2 = rl::rand(account_count);
bool rv = bl.transfer_balance(acc1, acc2, 1.0);
RL_ASSERT(rv);
}
};
int main()
{
rl::simulate<business_logic_test>();
}
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,14 @@
#pragma once
#ifdef NDEBUG
# define _SECURE_SCL 0
#endif
#define RL_MSVC_OUTPUT
//#define RL_DEBUGBREAK_ON_FAILURE
#include "../../relacy/pch.hpp"
#include "../../relacy/relacy_std.hpp"
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peterson", "peterson.vcproj", "{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.ActiveCfg = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.Build.0 = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.ActiveCfg = Release|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="peterson"
ProjectGUID="{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
RootNamespace="peterson"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\peterson.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "peterson", "peterson.vcproj", "{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.ActiveCfg = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.Build.0 = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.ActiveCfg = Release|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,200 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="peterson"
ProjectGUID="{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
RootNamespace="peterson"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\peterson.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,469 @@
#include "stdafx.h"
#include "../../relacy/relacy_std.hpp"
#include "../../relacy/windows.h"
struct peterson_mutex_test : rl::test_suite<peterson_mutex_test, 2>
{
std::atomic<int> flag0;
std::atomic<int> flag1;
std::atomic<int> turn;
rl::var<int> data;
void before()
{
flag0($) = 0;
flag1($) = 0;
turn($) = 0;
}
void thread(unsigned index)
{
if (0 == index)
{
flag0($).store(1);
turn($).store(1);
while (flag1($).load()
&& 1 == turn($).load());
data($) = 1;
flag0($).store(0);
}
else
{
flag1($).store(1);
turn($).store(0);
while (flag0($).load()
&& 0 == turn($).load());
data($) = 2;
flag1($).store(0);
}
}
};
struct peterson_mutex_test2 : rl::test_suite<peterson_mutex_test2, 2>
{
std::atomic<int> flag0;
std::atomic<int> flag1;
std::atomic<int> turn;
rl::var<int> data;
void before()
{
flag0($) = 0;
flag1($) = 0;
turn($) = 0;
}
void thread(unsigned index)
{
if (0 == index)
{
flag0.store(1, rl::memory_order_relaxed);
turn.exchange(1, rl::memory_order_acq_rel);
while (flag1.load(rl::memory_order_acquire)
&& 1 == turn.load(rl::memory_order_relaxed))
rl::yield(1, $);
data($) = 1;
flag0.store(0, rl::memory_order_release);
}
else
{
flag1.store(1, rl::memory_order_relaxed);
turn.exchange(0, rl::memory_order_acq_rel);
while (flag0.load(rl::memory_order_acquire)
&& 0 == turn.load(rl::memory_order_relaxed))
rl::yield(1, $);
data($) = 2;
flag1.store(0, rl::memory_order_release);
}
}
};
struct peterson_mutex_test3 : rl::test_suite<peterson_mutex_test3, 2>
{
std::atomic<int> flag0;
std::atomic<int> flag1;
std::atomic<int> turn;
rl::var<int> data;
void before()
{
flag0($) = 0;
flag1($) = 0;
turn($) = 0;
}
void thread(unsigned index)
{
if (0 == index)
{
flag0.store(1, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
turn.store(1, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag1.load(std::memory_order_acquire)
&& 1 == turn.load(std::memory_order_relaxed));
data($) = 1;
flag0.store(0, std::memory_order_release);
}
else
{
flag1.store(1, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
turn.store(0, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
while (flag0.load(std::memory_order_acquire)
&& 0 == turn.load(std::memory_order_relaxed));
data($) = 2;
flag1.store(0, std::memory_order_release);
}
}
};
// FAILS WITH DATA RACE
struct peterson_mutex_test4 : rl::test_suite<peterson_mutex_test4, 2>
{
std::atomic<int> flag0;
std::atomic<int> flag1;
std::atomic<int> turn;
rl::var<int> data;
void before()
{
flag0($) = 0;
flag1($) = 0;
turn($) = 0;
}
void thread(unsigned index)
{
if (0 == index)
{
flag0.exchange(1, rl::memory_order_acq_rel);
turn.store(1, rl::memory_order_release);
while (flag1.load(rl::memory_order_acquire)
&& 1 == turn.load(rl::memory_order_acquire))
rl::yield(1, $);
data($) = 1;
flag0.store(0, rl::memory_order_release);
}
else
{
flag1.exchange(1, rl::memory_order_acq_rel);
turn.store(0, rl::memory_order_release);
while (flag0.load(rl::memory_order_acquire)
&& 0 == turn.load(rl::memory_order_relaxed))
rl::yield(1, $);
data($) = 2;
flag1.store(0, rl::memory_order_release);
}
}
};
class eventcount
{
public:
typedef unsigned state_t;
eventcount()
{
state_.store(0, std::memory_order_relaxed);
sema_ = CreateSemaphore(0, 0, LONG_MAX, 0);
}
~eventcount()
{
CloseHandle(sema_);
}
state_t prepare()
{
return state_.fetch_add(waiters_inc, std::memory_order_seq_cst);
}
void retire()
{
state_.fetch_add((state_t)-(int)waiters_inc, std::memory_order_seq_cst);
}
void wait(state_t cmp)
{
WaitForSingleObject(sema_, INFINITE);
state_t cmp0 = state_.load(std::memory_order_seq_cst);
if ((cmp & generation_mask) == (cmp0 & generation_mask))
{
state_.fetch_add((state_t)-(int)waiters_inc, std::memory_order_seq_cst);
ReleaseSemaphore(sema_, 1, 0);
SwitchToThread();
}
}
void signal()
{
std::atomic_thread_fence(std::memory_order_seq_cst);
signal_relaxed();
}
void signal_relaxed()
{
state_t cmp = state_.load(std::memory_order_seq_cst);
if (0 == (cmp & waiters_mask))
return;
for (;;)
{
state_t xchg = (cmp & ~waiters_mask) + generation_inc;
if (state_.compare_exchange_weak(cmp, xchg, std::memory_order_seq_cst))
{
ReleaseSemaphore(sema_, cmp & waiters_mask, 0);
return;
}
if (0 == (cmp & waiters_mask))
return;
}
}
private:
std::atomic<state_t> state_;
HANDLE sema_;
static state_t const waiters_inc = 1;
static state_t const waiters_mask = (1 << 20) - 1;
static state_t const generation_inc = 1 << 20;
static state_t const generation_mask = ~waiters_mask;
eventcount(eventcount const&);
eventcount& operator = (eventcount const&);
};
class eventcount_blocking
{
public:
eventcount_blocking(eventcount& ec)
: ec_(ec)
{
cmp_ = ec_.prepare();
wait_ = false;
}
void wait()
{
RL_ASSERT(false == wait_);
wait_ = true;
ec_.wait(cmp_);
}
~eventcount_blocking()
{
if (false == wait_)
ec_.retire();
}
private:
eventcount& ec_;
eventcount::state_t cmp_;
bool wait_;
eventcount_blocking(eventcount_blocking const&);
eventcount_blocking& operator = (eventcount_blocking const&);
};
struct signaling_test : rl::test_suite<signaling_test, 6>
{
//rl::HANDLE var_wait_for_items;
//rl::CRITICAL_SECTION mtx_items_avail;
//std::atomic<unsigned> n_waiting_consumers;
//rl::var<unsigned> consumer_wait_generation;
//rl::var<unsigned> n_consumers_to_wakeup;
eventcount ec_;
static int const max_queue_length = 4;
int queue [max_queue_length];
int queue_head;
int queue_tail;
int queue_head_data;
int queue_tail_data;
void before()
{
//var_wait_for_items = rl::CreateEvent(0, 1, 0, 0, $);
//rl::InitializeCriticalSection(&mtx_items_avail, $);
//n_waiting_consumers($) = 0;
//consumer_wait_generation($) = 0;
//n_consumers_to_wakeup($) = 0;
for (int i = 0; i != max_queue_length; ++i)
queue[i] = 0;
queue_head = 0;
queue_tail = 0;
queue_head_data = 0;
queue_tail_data = 0;
}
void after()
{
//rl::CloseHandle(var_wait_for_items, $);
//rl::DeleteCriticalSection(&mtx_items_avail, $);
}
struct enqueue_desc
{
int pos;
void output(std::ostream& s) const
{
s << "enqueue " << pos;
}
};
void enqueue()
{
queue[queue_head++] = ++queue_head_data;
RL_HIST_IMPL(rl::ctx(), $, enqueue_desc) {queue_head - 1} RL_HIST_END();
signal();
}
void dequeue()
{
int my_pos = queue_tail++;
for (;;)
{
if (queue[my_pos])
{
RL_ASSERT(queue[my_pos] == my_pos + 1);
return;
}
wait(my_pos);
}
}
void signal()
{
ec_.signal();
/*
std::atomic_thread_fence($)(std::memory_order_seq_cst);
if (n_waiting_consumers($).load(std::memory_order_relaxed))
{
rl::EnterCriticalSection(&mtx_items_avail, $);
if (n_waiting_consumers($).load(std::memory_order_relaxed) > 0)
{
consumer_wait_generation($) += 1;
//RL_ASSERT(n_consumers_to_wakeup($) == 0);
n_consumers_to_wakeup($) = n_waiting_consumers($).load(std::memory_order_relaxed);
rl::SetEvent(var_wait_for_items, $);
}
rl::LeaveCriticalSection(&mtx_items_avail, $);
}
*/
}
void wait(int my_pos)
{
eventcount_blocking block (ec_);
if (queue[my_pos])
return;
block.wait();
/*
rl::EnterCriticalSection(&mtx_items_avail, $);
n_waiting_consumers($).store(n_waiting_consumers($).load(std::memory_order_relaxed) + 1, std::memory_order_relaxed);
std::atomic_thread_fence($)(std::memory_order_seq_cst);
while (0 == queue[my_pos])
{
unsigned my_generation = consumer_wait_generation($);
for (;;)
{
rl::LeaveCriticalSection(&mtx_items_avail, $);
rl::WaitForSingleObject(var_wait_for_items, rl::RL_INFINITE, $);
rl::EnterCriticalSection(&mtx_items_avail, $);
if (n_consumers_to_wakeup($) > 0 && consumer_wait_generation($) != my_generation)
break;
}
if (--n_consumers_to_wakeup($) == 0)
rl::ResetEvent(var_wait_for_items, $);
}
n_waiting_consumers($).store(n_waiting_consumers($).load(std::memory_order_relaxed) - 1, std::memory_order_relaxed);
rl::LeaveCriticalSection(&mtx_items_avail, $);
*/
}
void thread(unsigned index)
{
if (index < rl::test_suite<signaling_test, 6>::params::thread_count/2+1)
{
enqueue();
}
else
{
dequeue();
}
}
};
int main()
{
rl::test_params p;
//p.search_type = rl::fair_context_bound_scheduler_type;
p.search_type = rl::sched_bound;
//p.context_bound = 1;
//p.execution_depth_limit = 100;
//p.iteration_count = 5000;
//p.initial_state = "280572";
//rl::simulate<signaling_test>(p);
rl::simulate<peterson_mutex_test>();
rl::simulate<peterson_mutex_test2>(p);
rl::simulate<peterson_mutex_test3>();
rl::simulate<peterson_mutex_test4>(p);
}
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,14 @@
#pragma once
#ifdef NDEBUG
# define _SECURE_SCL 0
#endif
#define RL_MSVC_OUTPUT
//#define RL_DEBUGBREAK_ON_FAILURE
#include "../../relacy/pch.hpp"
#include "../../relacy/relacy_std.hpp"
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "proxy_collector", "proxy_collector.vcproj", "{31994C0C-3BAD-4F25-8BC8-3206FF349B29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{31994C0C-3BAD-4F25-8BC8-3206FF349B29}.Debug|Win32.ActiveCfg = Debug|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B29}.Debug|Win32.Build.0 = Debug|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B29}.Release|Win32.ActiveCfg = Release|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B29}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,291 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="proxy_collector"
ProjectGUID="{31994C0C-3BAD-4F25-8BC8-3206FF349B29}"
RootNamespace="ref_counting"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
BufferSecurityCheck="false"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Profile|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/Ob0"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
BufferSecurityCheck="false"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\proxy_collector.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "proxy_collector", "proxy_collector.vcproj", "{31994C0C-3BAD-4F25-8BC8-3206FF349B29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{31994C0C-3BAD-4F25-8BC8-3206FF349B29}.Debug|Win32.ActiveCfg = Debug|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B29}.Debug|Win32.Build.0 = Debug|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B29}.Release|Win32.ActiveCfg = Release|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B29}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,299 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="proxy_collector"
ProjectGUID="{31994C0C-3BAD-4F25-8BC8-3206FF349B29}"
RootNamespace="ref_counting"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
BufferSecurityCheck="false"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Profile|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/Ob0"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
WholeProgramOptimization="false"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
BufferSecurityCheck="false"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\original.hpp"
>
</File>
<File
RelativePath="..\proxy_collector.cpp"
>
</File>
<File
RelativePath="..\rtl.hpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,318 @@
#include "stdafx.h"
#include <stdint.h>
#include "../../relacy/relacy_std.hpp"
struct pc_sys_anchor;
struct pc_region;
struct pc_master;
typedef pc_region pc_node;
typedef void (pc_fp_dtor) (pc_region*);
struct pc_sys_anchor
{
int refcnt;
pc_region* region;
pc_sys_anchor()
{
}
pc_sys_anchor(int rc, pc_region* r = 0)
{
refcnt = rc;
region = r;
}
bool operator == (pc_sys_anchor const& right) const
{
return refcnt == right.refcnt
&& region == right.region;
}
pc_sys_anchor operator + (pc_sys_anchor const& right) const
{
pc_sys_anchor res;
res.refcnt = refcnt + right.refcnt;
res.region = (pc_region*)((intptr_t)region + (intptr_t)right.region);
return res;
}
pc_sys_anchor operator - (pc_sys_anchor const& right) const
{
pc_sys_anchor res;
res.refcnt = refcnt - right.refcnt;
res.region = (pc_region*)((intptr_t)region - (intptr_t)right.region);
return res;
}
};
std::ostream& operator << (std::ostream& s, pc_sys_anchor const& right)
{
return s << "{" << right.refcnt << "," << right.region << "}";
}
struct pc_region
{
std::atomic<pc_sys_anchor> next;
std::atomic<pc_region*> defer;
pc_region()
{
next($) = pc_sys_anchor(0, 0);
defer($) = 0;
}
void link(pc_region* next)
{
defer.store(next, rl::memory_order_relaxed);
}
void defer_node(pc_region* node)
{
pc_region* region = defer.exchange(node, rl::memory_order_release);
node->defer.store(region, rl::memory_order_relaxed);
}
};
struct pc_master
{
std::atomic<pc_sys_anchor> head;
pc_region stub_region;
pc_fp_dtor* fp_dtor;
pc_master(pc_fp_dtor* const dtor)
{
pc_sys_anchor src (0, &stub_region);
head.store(src, rl::memory_order_relaxed);
fp_dtor = dtor;
}
pc_region* acquire()
{
pc_sys_anchor cmp (head.load(rl::memory_order_relaxed));
pc_sys_anchor xchg;
do
{
xchg.refcnt = cmp.refcnt + 2;
xchg.region = cmp.region;
}
while (false == head.compare_exchange_weak(cmp, xchg, rl::memory_order_acquire));
return cmp.region;
}
void release(pc_region* region)
{
pc_sys_anchor prev = region->next.fetch_sub(2, rl::memory_order_acq_rel);
if (prev.refcnt == 3)
sys_dtor(region);
}
void mutate(pc_region* node)
{
pc_sys_anchor src (2, 0);
node->next.store(src, rl::memory_order_relaxed);
pc_sys_anchor xchg (0, node);
pc_sys_anchor cmp = head.load(rl::memory_order_relaxed);
while (false == head.compare_exchange_weak(cmp, xchg, std::memory_order_acq_rel));
pc_sys_anchor cmp2 = cmp.region->next.load(rl::memory_order_relaxed);
pc_sys_anchor xchg2;
do
{
xchg2 = pc_sys_anchor(cmp2.refcnt, node);
}
while (false == cmp.region->next.compare_exchange_weak(cmp2, xchg2, rl::memory_order_release));
pc_sys_anchor prev = cmp.region->next.fetch_add(cmp.refcnt + 1, rl::memory_order_acq_rel);
if (prev.refcnt == -cmp.refcnt)
sys_dtor(cmp.region);
}
void sys_dtor(pc_region* region)
{
int reset = 0;
pc_region* head = region;
pc_region* tail = region;
pc_sys_anchor nx = region->next.load(rl::memory_order_relaxed);
pc_region* next = nx.region;
while (next)
{
pc_sys_anchor prev = next->next.fetch_sub(2, rl::memory_order_acq_rel);
if (prev.refcnt != 3)
break;
tail = next;
nx = next->next.load(rl::memory_order_relaxed);
next = nx.region;
}
nx = tail->next.load(rl::memory_order_relaxed);
nx.region = 0;
tail->next.store(nx, rl::memory_order_relaxed);
while (head)
{
nx = head->next.load(rl::memory_order_relaxed);
pc_region* const next = nx.region;
pc_region* defer = head->defer.load(rl::memory_order_relaxed);
nx = head->next.load(rl::memory_order_relaxed);
RL_ASSERT(nx.refcnt == 1);
if (head != &stub_region)
{
head->defer.store(defer, rl::memory_order_relaxed);
defer = head;
}
else
{
reset = 1;
}
while (defer)
{
pc_region* const next = defer->defer.load(rl::memory_order_relaxed);
fp_dtor(defer);
defer = next;
}
head = next;
}
if (reset)
{
stub_region.defer.store(0, rl::memory_order_relaxed);
mutate(&stub_region);
}
}
};
struct foo_node
{
pc_node pcn;
std::atomic<foo_node*> next;
rl::var<int> data;
};
void foo_node_dtor(pc_node* pcn)
{
// yes, very fragile
foo_node* const n = (foo_node*)pcn;
delete n;
}
struct foo_list
{
std::atomic<foo_node*> head;
pc_master pc;
foo_list()
: head(0)
, pc(foo_node_dtor)
{
}
};
struct proxy_collector_test : rl::test_suite<proxy_collector_test, 4>
{
foo_list m_list;
void before()
{
m_list.head($) = 0;
}
void after()
{
foo_node* node = new foo_node;
m_list.pc.mutate(&node->pcn);
}
void thread(unsigned index)
{
if (index < 2)
{
pc_region* pcr = m_list.pc.acquire();
for (int i = 0; i != 4; ++i)
{
foo_node* node = m_list.head.load(rl::memory_order_acquire);
while (node)
{
foo_node* const next = node->next.load(rl::memory_order_acquire);
intptr_t volatile data = node->data($);
(void)data;
node = next;
}
if (2 == i)
{
m_list.pc.release(pcr);
pcr = m_list.pc.acquire();
}
}
m_list.pc.release(pcr);
}
else
{
pc_region* pcr = m_list.pc.acquire();
for (int i = 0; i != 4; ++i)
{
if (0 == (i % 2))
{
foo_node* node = new foo_node;
node->data($) = 1;
foo_node* cmp = m_list.head.load(rl::memory_order_relaxed);
do
{
node->next.store(cmp, rl::memory_order_relaxed);
}
while (false == m_list.head.compare_exchange_weak(cmp, node, rl::memory_order_release));
}
else
{
foo_node* node = m_list.head.load(rl::memory_order_acquire);
foo_node* next;
do
{
if (0 == node)
break;
next = node->next.load(rl::memory_order_relaxed);
}
while (false == m_list.head.compare_exchange_weak(node, next, rl::memory_order_acquire));
if (node)
{
//if (1 == i)
{
m_list.pc.mutate(&node->pcn);
}
//else
//{
// pcr->defer_node(&node->pcn);
//}
}
}
if (i % 2)
{
m_list.pc.release(pcr);
pcr = m_list.pc.acquire();
}
}
m_list.pc.release(pcr);
}
}
};
int main()
{
rl::test_params params;
params.iteration_count = 1000;
rl::simulate<proxy_collector_test>(params);
}
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,11 @@
#pragma once
#ifdef NDEBUG
# define _SECURE_SCL 0
#endif
#include "../../relacy/pch.hpp"
#include <sstream>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ref_counting", "ref_counting.vcproj", "{31994C0C-3BAD-4F25-8BC8-3206FF349B28}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{31994C0C-3BAD-4F25-8BC8-3206FF349B28}.Debug|Win32.ActiveCfg = Debug|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B28}.Debug|Win32.Build.0 = Debug|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B28}.Release|Win32.ActiveCfg = Release|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B28}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="ref_counting"
ProjectGUID="{31994C0C-3BAD-4F25-8BC8-3206FF349B28}"
RootNamespace="ref_counting"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
BufferSecurityCheck="false"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\ref_counting.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ref_counting", "ref_counting.vcproj", "{31994C0C-3BAD-4F25-8BC8-3206FF349B28}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{31994C0C-3BAD-4F25-8BC8-3206FF349B28}.Debug|Win32.ActiveCfg = Debug|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B28}.Debug|Win32.Build.0 = Debug|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B28}.Release|Win32.ActiveCfg = Release|Win32
{31994C0C-3BAD-4F25-8BC8-3206FF349B28}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="ref_counting"
ProjectGUID="{31994C0C-3BAD-4F25-8BC8-3206FF349B28}"
RootNamespace="ref_counting"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
InlineFunctionExpansion="2"
EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="1"
OmitFramePointers="true"
EnableFiberSafeOptimizations="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
BufferSecurityCheck="false"
EnableEnhancedInstructionSet="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\ref_counting.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,269 @@
#include "stdafx.h"
#include "../../relacy/relacy_std.hpp"
struct rc_object
{
std::atomic<int> rc;
rl::var<int> data;
void acquire()
{
rc.fetch_add(1, rl::memory_order_acquire);
}
void release()
{
if (1 == rc.fetch_sub(1, rl::memory_order_release))
{
rc.load(rl::memory_order_acquire);
data($) = 0;
delete this;
}
}
rc_object(int data)
: rc(1)
, data(data)
{
}
};
void post_to_channel(rl::atomic<rc_object*>& ch, rc_object* obj)
{
obj->acquire();
rl::backoff b;
for (;;)
{
rc_object* cmp = 0;
if (ch.compare_exchange_weak(cmp, obj, rl::memory_order_release))
break;
b.yield($);
}
}
rc_object* get_from_channel(rl::atomic<rc_object*>& ch)
{
return ch.exchange(0, rl::memory_order_acquire);
}
struct ref_counting_test : rl::test_suite<ref_counting_test, 2>
{
std::atomic<rc_object*> channel;
void before()
{
channel($) = 0;
}
void thread(unsigned index)
{
if (0 == index)
{
rc_object* obj = new rc_object (rand());
post_to_channel(channel, obj);
int data = obj->data($);
(void)data;
obj->release();
}
else if (1 == index)
{
rl::backoff b;
for (;;)
{
rc_object* obj = get_from_channel(channel);
if (obj)
{
int data = obj->data($);
(void)data;
obj->release();
break;
}
else
{
b.yield($);
}
}
}
}
};
struct ref_counting_test2 : rl::test_suite<ref_counting_test2, 3>
{
std::atomic<rc_object*> channel01;
std::atomic<rc_object*> channel02;
std::atomic<rc_object*> channel12;
std::atomic<rc_object*> channel21;
void before()
{
channel01($) = 0;
channel02($) = 0;
channel12($) = 0;
channel21($) = 0;
}
void thread(unsigned index)
{
if (0 == index)
{
{
rc_object* obj1 = new rc_object (rand());
post_to_channel(channel01, obj1);
volatile int data = obj1->data($);
(void)data;
obj1->release();
}
{
rc_object* obj2 = new rc_object (rand());
post_to_channel(channel02, obj2);
volatile int data = obj2->data($);
(void)data;
obj2->release();
}
}
else if (1 == index)
{
rl::backoff b;
bool ch0 = false;
bool ch2 = false;
while (!ch0 || !ch2)
{
{
rc_object* obj = get_from_channel(channel01);
if (obj)
{
post_to_channel(channel12, obj);
volatile int data = obj->data($);
(void)data;
obj->release();
ch0 = true;
}
else
{
b.yield($);
}
}
{
rc_object* obj = get_from_channel(channel21);
if (obj)
{
volatile int data = obj->data($);
(void)data;
obj->release();
ch2 = true;
}
else
{
b.yield($);
}
}
}
}
else
{
rl::backoff b;
bool ch0 = false;
bool ch1 = false;
while (!ch0 || !ch1)
{
{
rc_object* obj = get_from_channel(channel02);
if (obj)
{
post_to_channel(channel21, obj);
volatile int data = obj->data($);
(void)data;
obj->release();
ch0 = true;
}
else
{
b.yield($);
}
}
{
rc_object* obj = get_from_channel(channel12);
if (obj)
{
volatile int data = obj->data($);
(void)data;
obj->release();
ch1 = true;
}
else
{
b.yield($);
}
}
}
}
}
};
struct ref_counting_test3 : rl::test_suite<ref_counting_test3, 2>
{
std::atomic<rc_object*> channel;
void before()
{
channel($) = 0;
}
void thread(unsigned index)
{
if (0 == index)
{
rc_object* obj = new rc_object (rand());
post_to_channel(channel, obj);
volatile int data = obj->data($);
(void)data;
obj->release();
}
else if (1 == index)
{
rl::backoff b;
rc_object* obj = 0;
for (;;)
{
obj = get_from_channel(channel);
if (obj)
break;
else
b.yield($);
}
obj->acquire();
obj->release();
//volatile int data = obj->data($);
//(void)data;
obj->release();
}
}
};
int main()
{
rl::test_params params;
params.context_bound = 2;
params.iteration_count = 10000;
rl::simulate<ref_counting_test>(params);
std::cout << "count: " << params.stop_iteration << std::endl;
}
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,8 @@
#pragma once
#ifdef NDEBUG
# define _SECURE_SCL 0
#endif
#include "../../relacy/pch.hpp"
@@ -0,0 +1,11 @@
TARGET=smr
SRC=smr.cpp
HEADERS=stdafx.h
all: ${TARGET}
${TARGET}: Makefile ${SRC} ${HEADERS}
g++ ${SRC} -O3 -g -o ${TARGET}
clean:
rm ${TARGET}
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "smr", "smr.vcproj", "{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}.Debug|Win32.ActiveCfg = Debug|Win32
{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}.Debug|Win32.Build.0 = Debug|Win32
{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}.Release|Win32.ActiveCfg = Release|Win32
{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,199 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="smr"
ProjectGUID="{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}"
RootNamespace="smr"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\smr.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "smr", "smr.vcproj", "{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}.Debug|Win32.ActiveCfg = Debug|Win32
{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}.Debug|Win32.Build.0 = Debug|Win32
{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}.Release|Win32.ActiveCfg = Release|Win32
{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,199 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="smr"
ProjectGUID="{BC168133-5E3D-4691-BA15-8E0FD61DFDB5}"
RootNamespace="smr"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\smr.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,189 @@
#include "stdafx.h"
#include "../../relacy/relacy_std.hpp"
unsigned const thread_count = 3;
unsigned const node_count = 6;
struct smr_test : rl::test_suite<smr_test, thread_count>
{
struct node
{
std::atomic<node*> next_;
rl::var<int> data_;
};
std::atomic<node*> head_;
std::atomic<node*> hp_ [thread_count];
rl::var<node*> defer_ [thread_count][thread_count];
rl::var<int> defer_size_ [thread_count];
void before()
{
head_.store(0, std::memory_order_relaxed);
for (size_t i = 0; i != thread_count; ++i)
{
hp_[i].store(0, std::memory_order_relaxed);
VAR(defer_size_[i]) = 0;
for (size_t j = 0; j != thread_count; ++j)
VAR(defer_[i][j]) = 0;
}
}
void push(unsigned index, int data)
{
node* n = new node ();
n->VAR(data_) = data;
node* next = head_.load(std::memory_order_relaxed);
for (;;)
{
n->next_.store(next, rl::memory_order_relaxed);
if (head_.compare_exchange_weak(next, n, rl::memory_order_release))
break;
}
}
int pop(unsigned index)
{
node* n = 0;
for (;;)
{
n = smr_acquire(index, head_);
if (0 == n)
break;
node* next = n->next_.load(rl::memory_order_relaxed);
if (head_.compare_exchange_weak(n, next, rl::memory_order_acquire))
break;
smr_release(index);
}
smr_release(index);
if (n)
{
int data = n->VAR(data_);
smr_defer(index, n);
return data;
}
else
{
return 0;
}
}
void smr_pump(unsigned index)
{
node* hp [thread_count] = {};
for (size_t i = 0; i != thread_count; ++i)
{
hp[i] = hp_[i].load(std::memory_order_relaxed);
}
for (size_t i = 0; i != thread_count; ++i)
{
node* nn = VAR(defer_[index][i]);
if (nn)
{
for (size_t j = 0; j != thread_count; ++j)
{
if (nn == hp[j])
{
nn = 0;
break;
}
}
if (nn)
{
VAR(defer_[index][i]) = 0;
VAR(defer_size_[index]) -= 1;
delete nn;
}
}
}
}
void smr_defer(unsigned index, node* n)
{
std::atomic_thread_fence(std::memory_order_seq_cst);
smr_pump(index);
if (VAR(defer_size_[index]) == thread_count)
{
delete n;
}
else
{
bool found = false;
for (size_t i = 0; i != thread_count; ++i)
{
if (VAR(defer_[index][i]) == 0)
{
VAR(defer_[index][i]) = n;
found = true;
break;
}
}
RL_ASSERT(found);
VAR(defer_size_[index]) += 1;
}
}
node* smr_acquire(unsigned index, std::atomic<node*>& n)
{
node* v = 0;
for (;;)
{
v = n.load(std::memory_order_relaxed);
hp_[index].store(v, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
node* v2 = n.load(std::memory_order_acquire);
if (v2 == v)
break;
}
return v;
}
void smr_release(unsigned index)
{
hp_[index].store(0, std::memory_order_relaxed);
}
void thread(unsigned index)
{
for (unsigned i = 0; i != node_count; ++i)
{
push(index, index * thread_count + i + 1);
}
for (unsigned i = 0; i != node_count; ++i)
{
int data = pop(index);
RL_ASSERT(0 != data);
}
}
void after()
{
for (unsigned i = 0; i != ::thread_count; ++i)
{
smr_pump(i);
}
}
};
int main()
{
rl::test_params p;
//p.collect_history = true;
//p.output_history = true;
//p.initial_state = "991172";
p.iteration_count = 1000;
rl::simulate<smr_test>(p);
}
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,10 @@
#pragma once
#ifdef NDEBUG
# define _SECURE_SCL 0
#endif
#define RL_MSVC_OUTPUT
#include "../../relacy/pch.hpp"
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spsc_queue", "spsc_queue.vcproj", "{2F0B1A3B-27CA-47D4-A9D1-5EC66BB0A85B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2F0B1A3B-27CA-47D4-A9D1-5EC66BB0A85B}.Debug|Win32.ActiveCfg = Debug|Win32
{2F0B1A3B-27CA-47D4-A9D1-5EC66BB0A85B}.Debug|Win32.Build.0 = Debug|Win32
{2F0B1A3B-27CA-47D4-A9D1-5EC66BB0A85B}.Release|Win32.ActiveCfg = Release|Win32
{2F0B1A3B-27CA-47D4-A9D1-5EC66BB0A85B}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="spsc_queue"
ProjectGUID="{2F0B1A3B-27CA-47D4-A9D1-5EC66BB0A85B}"
RootNamespace="spsc_queue"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../.."
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../.."
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\spsc_queue.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spsc_queue", "spsc_queue.vcproj", "{D4756EE9-3953-4E17-B1B5-E89F853303C1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.ActiveCfg = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Debug|Win32.Build.0 = Debug|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.ActiveCfg = Release|Win32
{D4756EE9-3953-4E17-B1B5-E89F853303C1}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,200 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="spsc_queue"
ProjectGUID="{3F32C4FA-E451-42BC-9E65-74129120B6E4}"
RootNamespace="spsc_queue"
Keyword="Win32Proj"
TargetFrameworkVersion="131072"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
RandomizedBaseAddress="1"
DataExecutionPrevention="0"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\spsc_queue.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,202 @@
#include "stdafx.h"
#include "../../relacy/relacy_std.hpp"
template<typename T>
class nonblocking_spsc_queue
{
public:
nonblocking_spsc_queue()
{
node* n = new node ();
VAR(head) = n;
VAR(tail) = n;
}
~nonblocking_spsc_queue()
{
RL_ASSERT(VAR(head) == VAR(tail));
delete (node*)VAR(head);
}
void enqueue(T data)
{
node* n = new node (data);
VAR(head)->next.store(n, std::memory_order_release);
VAR(head) = n;
}
bool dequeue(T& data)
{
node* t = VAR(tail);
node* n = t->next.load(std::memory_order_acquire);
if (0 == n)
return false;
data = n->VAR(data);
delete t;
VAR(tail) = n;
return true;
}
private:
struct node
{
std::atomic<node*> next;
VAR_T(T) data;
node(T data = T())
: next(0)
, data(data)
{}
};
VAR_T(node*) head;
VAR_T(node*) tail;
};
struct nonblocking_spsc_queue_test : rl::test_suite<nonblocking_spsc_queue_test, 2>
{
nonblocking_spsc_queue<int> q;
void thread(unsigned thread_index)
{
if (0 == thread_index)
{
q.enqueue(11);
}
else
{
int data = 0;
while (false == q.dequeue(data))
{}
RL_ASSERT(11 == data);
}
}
};
class eventcount
{
public:
eventcount()
: count(0)
, waiters(0)
{}
void signal_relaxed()
{
unsigned cmp = count.load(std::memory_order_relaxed);
signal_impl(cmp);
}
void signal()
{
unsigned cmp = count.fetch_add(0, std::memory_order_seq_cst);
signal_impl(cmp);
}
unsigned get()
{
unsigned cmp = count.fetch_or(0x80000000, std::memory_order_acquire);
return cmp & 0x7FFFFFFF;
}
void wait(unsigned cmp)
{
unsigned ec = count.load(std::memory_order_seq_cst);
if (cmp == (ec & 0x7FFFFFFF))
{
guard.lock($);
ec = count.load(std::memory_order_seq_cst);
if (cmp == (ec & 0x7FFFFFFF))
{
waiters($) += 1;
cv.wait(guard, $);
}
guard.unlock($);
}
}
private:
std::atomic<unsigned> count;
VAR_T(unsigned) waiters;
std::mutex guard;
std::condition_variable cv;
void signal_impl(unsigned cmp)
{
if (cmp & 0x80000000)
{
guard.lock($);
while (false == count.compare_exchange_weak(cmp,
(cmp + 1) & 0x7FFFFFFF, std::memory_order_relaxed));
unsigned w = VAR(waiters);
VAR(waiters) = 0;
guard.unlock($);
if (w)
cv.notify_all($);
}
}
};
template<typename T>
class spsc_queue : nonblocking_spsc_queue<T>
{
public:
typedef nonblocking_spsc_queue<T> base_t;
void enqueue(T data)
{
base_t::enqueue(data);
ec.signal/*_relaxed*/();
}
T dequeue()
{
T data;
bool res = base_t::dequeue(data);
while (false == res)
{
int cmp = ec.get();
res = base_t::dequeue(data);
if (res)
break;
ec.wait(cmp);
res = base_t::dequeue(data);
if (res)
break;
}
return data;
}
private:
eventcount ec;
};
struct spsc_queue_test : rl::test_suite<spsc_queue_test, 2>
{
spsc_queue<int> q;
void thread(unsigned thread_index)
{
if (0 == thread_index)
{
q.enqueue(11);
}
else
{
int d = q.dequeue();
RL_ASSERT(11 == d);
}
}
};
int main()
{
rl::simulate<nonblocking_spsc_queue_test>();
rl::simulate<spsc_queue_test>();
}
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,13 @@
#pragma once
#ifdef NDEBUG
# define _SECURE_SCL 0
#endif
//#define RL_MSVC_OUTPUT
#include "../../relacy/pch.hpp"
#include "../../relacy/relacy_std.hpp"
@@ -0,0 +1,2 @@
lock-free stack
code contains several bugs: access to freed memory and ABA problem
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stack", "stack.vcproj", "{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}.Debug|Win32.ActiveCfg = Debug|Win32
{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}.Debug|Win32.Build.0 = Debug|Win32
{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}.Release|Win32.ActiveCfg = Release|Win32
{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,201 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="stack"
ProjectGUID="{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}"
RootNamespace="stack"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\stack.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stack", "stack.vcproj", "{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}.Debug|Win32.ActiveCfg = Debug|Win32
{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}.Debug|Win32.Build.0 = Debug|Win32
{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}.Release|Win32.ActiveCfg = Release|Win32
{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,196 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="stack"
ProjectGUID="{4D6D7FC3-66D1-4F80-B434-2FDCBBFBC9F5}"
RootNamespace="stack"
Keyword="Win32Proj"
TargetFrameworkVersion="0"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="0"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\stack.cpp"
>
</File>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,105 @@
#include "stdafx.h"
#include "../../relacy/relacy_std.hpp"
// TEST FAILS WITH "ACCESS TO FREED MEMORY"
class stack
{
public:
stack()
: head_(0)
{
}
void push(int data)
{
rl::var<node*> n = new node ();
n($)->data_($) = data;
node* next = head_.load(rl::memory_order_relaxed);
for (;;)
{
n($)->next_.store(next, rl::memory_order_relaxed);
if (head_.compare_exchange_weak(next, n($), rl::memory_order_release))
break;
}
}
int pop()
{
node* n = head_.load(rl::memory_order_relaxed);
for (;;)
{
if (0 == n)
break;
node* next = n->next_.load(rl::memory_order_relaxed);
if (head_.compare_exchange_weak(n, next, rl::memory_order_acquire))
break;
}
if (n)
{
int data = n->data_($);
delete n;
return data;
}
else
{
return 0;
}
}
private:
struct node
{
std::atomic<node*> next_;
rl::var<int> data_;
};
std::atomic<node*> head_;
stack(stack const&);
stack& operator = (stack const&);
};
struct stack_test : rl::test_suite<stack_test, 4>
{
stack s_;
int produced_count_;
int consumed_count_;
void before()
{
produced_count_ = 0;
consumed_count_ = 0;
}
void after()
{
typedef rl::test_suite<stack_test, 4> base_t;
RL_ASSERT(base_t::params::thread_count == produced_count_);
RL_ASSERT(base_t::params::thread_count == consumed_count_);
}
void thread(unsigned /*index*/)
{
s_.push(rand() + 1);
produced_count_ += 1;
int data = s_.pop();
RL_ASSERT(data);
consumed_count_ += 1;
}
};
int main()
{
rl::simulate<stack_test>();
}
@@ -0,0 +1,2 @@
#include "stdafx.h"
@@ -0,0 +1,8 @@
#pragma once
#ifdef NDEBUG
# define _SECURE_SCL 0
#endif
#include "../../relacy/pch.hpp"
@@ -0,0 +1,842 @@
#include "stdafx.h"
#include "../../relacy/windows.h"
/*
#define HANDLE rl::HANDLE
#define CreateSemaphoreA rl::RL_CreateSemaphore($)
#define CreateSemaphoreW rl::RL_CreateSemaphore($)
#ifndef CreateSemaphore
# define CreateSemaphore CreateSemaphoreW
#endif
//#define CRITICAL_SECTION rl::CRITICAL_SECTION
//#define InitializeCriticalSection rl::InitializeCriticalSection($)
#define CloseHandle rl::RL_CloseHandle($)
*/
#include <stddef.h>
#if defined(WIN32) && defined(_MSC_VER)
#include <windows.h>
#include <intrin.h>
class semaphore
{
public:
semaphore()
{
h_ = rl::CreateSemaphore(0, 0, LONG_MAX, 0, $);
}
~semaphore()
{
rl::CloseHandle(h_, $);
}
void wait()
{
rl::WaitForSingleObject(h_, rl::RL_INFINITE, $);
}
void post()
{
rl::ReleaseSemaphore(h_, 1, 0, $);
}
private:
rl::HANDLE h_;
semaphore(semaphore const&);
semaphore& operator = (semaphore const&);
};
class mutex
{
public:
mutex()
{
rl::InitializeCriticalSection(&cs_, $);
}
~mutex()
{
rl::DeleteCriticalSection(&cs_, $);
}
void lock()
{
rl::EnterCriticalSection(&cs_, $);
}
void unlock()
{
rl::LeaveCriticalSection(&cs_, $);
}
private:
rl::CRITICAL_SECTION cs_;
mutex(mutex const&);
mutex& operator = (mutex const&);
};
//void full_memory_fence()
//{
// _mm_mfence();
//}
//#define THREAD_LOCAL __declspec(thread)
#elif defined(POSIX) && defined(GCC)
#include <pthread.h>
#include <semaphore.h>
class semaphore
{
public:
semaphore()
{
sem_init(&sem_, 0, 0);
}
~semaphore()
{
sem_destroy(&sem_);
}
void wait()
{
sem_wait(&sem_);
}
void post()
{
sem_post(&sem_);
}
private:
sem_t sem_;
semaphore(semaphore const&);
semaphore& operator = (semaphore const&);
};
class mutex
{
public:
mutex()
{
pthread_mutex_init(&mutex_, 0);
}
~mutex()
{
pthread_mutex_destroy(&mutex_);
}
void lock()
{
pthread_mutex_lock(&mutex_);
}
void unlock()
{
pthread_mutex_unlock(&mutex_);
}
private:
pthread_mutex_t mutex_;
mutex(mutex const&);
mutex& operator = (mutex const&);
};
void full_memory_fence()
{
__sync_synchronize();
}
//#define THREAD_LOCAL __thread
#endif
class lock
{
public:
lock(mutex& m)
: m_(m)
{
m.lock();
}
~lock()
{
m_.unlock();
}
private:
mutex& m_;
lock(lock const&);
lock& operator = (lock const&);
};
/** simple single-threaded double-linked list
* nothing interesting
*/
class dlist
{
public:
struct node
{
rl::var<node*> prev_;
rl::var<node*> next_;
node()
{
prev_($) = 0;
next_($) = 0;
}
};
dlist()
{
reset();
}
void push(node* n)
{
size_t s = size_($).load(rl::memory_order_relaxed);
size_($).store(s + 1, rl::memory_order_relaxed);
n->next_($) = head_.next_($);
n->prev_($) = &head_;
head_.next_($)->prev_($) = n;
head_.next_($) = n;
}
node* pop()
{
if (size_($).load(rl::memory_order_relaxed) == 0)
return 0;
node* n = head_.next_($);
remove(n);
return n;
}
void remove(node* n)
{
size_t s = size_($).load(rl::memory_order_relaxed);
size_($).store(s - 1, rl::memory_order_relaxed);
n->prev_($)->next_($) = n->next_($);
n->next_($)->prev_($) = n->prev_($);
}
size_t size() const
{
return size_($).load(rl::memory_order_relaxed);
}
node* begin()
{
return head_.next_($);
}
void flush_to(dlist& target)
{
if (size_($).load(rl::memory_order_relaxed))
{
target.size_($).store(size_($).load(rl::memory_order_relaxed));
target.head_.next_($) = head_.next_($);
target.head_.next_($)->prev_($) = &target.head_;
target.tail_.prev_($) = tail_.prev_($);
target.tail_.prev_($)->next_($) = &target.tail_;
}
else
{
target.reset();
}
reset();
}
static bool not_last(node* n)
{
return n->next_($) != 0;
}
static node* get_next(node* n)
{
return n->next_($);
}
private:
rl::atomic<size_t> size_;
node head_;
node tail_;
void reset()
{
size_($) = 0;
head_.next_($) = &tail_;
head_.prev_($) = 0;
tail_.next_($) = 0;
tail_.prev_($) = &head_;
}
dlist(dlist const&);
dlist& operator = (dlist const&);
};
/** pre-thread descriptor for eventcount
*/
struct ec_thread
{
dlist::node node_;
semaphore sema_;
rl::var<unsigned> epoch_;
rl::atomic<bool> in_waitset_;
rl::var<bool> spurious_;
rl::var<void*> ctx_;
ec_thread()
{
epoch_($) = 0;
in_waitset_($) = false;
spurious_($) = false;
ctx_($) = 0;
}
~ec_thread()
{
if (spurious_($))
sema_.wait();
}
/*
static ec_thread* current()
{
static THREAD_LOCAL ec_thread* ec_thread_instance = 0;
ec_thread* instance = ec_thread_instance;
if (instance == 0)
{
instance = new ec_thread;
ec_thread_instance = instance;
}
return instance;
// instance must be destroyed in DllMain() callback
// or in pthread_key_create() callback
}
*/
private:
ec_thread(ec_thread const&);
ec_thread& operator = (ec_thread const&);
};
/** fine-grained eventcount implementation
*/
class eventcount
{
public:
eventcount()
{
epoch_($) = 0;
}
void prepare_wait(ec_thread* th = 0, void* ctx = 0)
{
RL_ASSERT(th);
// this is good place to pump previous spurious wakeup
if (th->spurious_($))
{
th->spurious_($) = false;
th->sema_.wait();
}
th->in_waitset_($).store(true, rl::memory_order_relaxed);
th->ctx_($) = ctx;
{
lock l (mtx_);
th->epoch_($) = epoch_($).load(rl::memory_order_relaxed);
waitset_.push(&th->node_);
}
rl::atomic_thread_fence($)(rl::memory_order_seq_cst);
}
void commit_wait(ec_thread* th = 0)
{
RL_ASSERT(th);
// this check is just an optimization
//if (th->epoch_($) == epoch_($).load(rl::memory_order_relaxed))
if (th->in_waitset_($).load(rl::memory_order_acquire))
th->sema_.wait();
else
cancel_wait(true, th); //!!! add 'th'
}
void cancel_wait(bool /*from_commit*/, ec_thread* th = 0)
{
RL_ASSERT(th);
// spurious wakeup will be pumped in the following prepare_wait()
th->spurious_($) = true;
// try to remove node from waitset
if (th->in_waitset_($).load(rl::memory_order_acquire))
{
lock l (mtx_);
if (th->in_waitset_($).load(rl::memory_order_relaxed))
{
// successfully removed from waitset,
// so there will be no spurious wakeup
th->in_waitset_($).store(false, rl::memory_order_relaxed);
th->spurious_($) = false;
waitset_.remove(&th->node_);
}
else
{
//if (from_commit)
//int volatile x = 0;
}
}
else
{
//RL_ASSERT(from_commit == false);
//if (from_commit)
// int volatile x = 0;
}
}
void notify_one()
{
rl::atomic_thread_fence($)(rl::memory_order_seq_cst);
notify_one_relaxed();
}
template<typename predicate_t>
void notify(predicate_t pred)
{
rl::atomic_thread_fence($)(rl::memory_order_seq_cst);
notify_relaxed(pred);
}
void notify_all()
{
rl::atomic_thread_fence($)(rl::memory_order_seq_cst);
notify_all_relaxed();
}
void notify_one_relaxed()
{
if (waitset_.size() == 0)
return;
dlist::node* n;
{
lock l (mtx_);
unsigned ep = epoch_($).load(rl::memory_order_relaxed);
epoch_($).store(ep + 1, rl::memory_order_relaxed);
n = waitset_.pop();
if (n)
to_ec_thread(n)->in_waitset_($).store(false, rl::memory_order_release);
}
if (n)
{
to_ec_thread(n)->sema_.post();
}
}
template<typename predicate_t>
void notify_relaxed(predicate_t pred)
{
if (waitset_.size() == 0)
return;
dlist temp;
{
lock l (mtx_);
unsigned ep = epoch_($).load(rl::memory_order_relaxed);
epoch_($).store(ep + 1, rl::memory_order_relaxed);
size_t size = waitset_.size();
size_t idx = 0;
dlist::node* n = waitset_.begin();
while (dlist::not_last(n))
{
dlist::node* next = dlist::get_next(n);
ec_thread* th = to_ec_thread(n);
if (pred(th->ctx_($), size, idx))
{
waitset_.remove(n);
temp.push(n);
th->in_waitset_($).store(false, rl::memory_order_release);
}
n = next;
idx += 1;
}
}
dlist::node* n = temp.begin();
while (dlist::not_last(n))
{
dlist::node* next = dlist::get_next(n);
to_ec_thread(n)->sema_.post();
n = next;
}
}
void notify_all_relaxed()
{
if (waitset_.size() == 0)
return;
dlist temp;
{
lock l (mtx_);
waitset_.flush_to(temp);
dlist::node* n = temp.begin();
while (dlist::not_last(n))
{
to_ec_thread(n)->in_waitset_($).store(false, rl::memory_order_release);
n = dlist::get_next(n);
}
unsigned ep = epoch_($).load(rl::memory_order_relaxed);
epoch_($).store(ep + 1, rl::memory_order_relaxed);
}
dlist::node* n = temp.begin();
while (dlist::not_last(n))
{
dlist::node* next = dlist::get_next(n);
to_ec_thread(n)->sema_.post();
n = next;
}
}
class wait_guard;
private:
mutex mtx_;
dlist waitset_;
rl::atomic<unsigned>epoch_;
ec_thread* to_ec_thread(dlist::node* n)
{
return (ec_thread*)((char*)n - offsetof(ec_thread, node_));
}
eventcount(eventcount const&);
eventcount& operator = (eventcount const&);
};
class eventcount::wait_guard
{
public:
wait_guard(eventcount& ec, ec_thread* th = 0, void* ctx = 0)
: ec_(ec)
, th_(th)
, wait_(false)
{
ec_.prepare_wait(th_, ctx);
}
void commit_wait()
{
assert(false == wait_);
wait_ = true;
ec_.commit_wait(th_);
}
~wait_guard()
{
if (false == wait_)
ec_.cancel_wait(false, th_);
}
private:
eventcount& ec_;
ec_thread* th_;
bool wait_;
wait_guard(wait_guard const&);
wait_guard& operator = (wait_guard const&);
};
struct scheduler
{
struct tbb_thread
{
ec_thread th;
};
eventcount ec_;
tbb_thread* threads_;
bool volatile is_permanently_open_;
void wait_while_pool_is_empty(tbb_thread* th)
{
if (is_permanently_open_)
return;
eventcount::wait_guard wait (ec_, &th->th);
if (pool_is_empty())
wait.commit_wait();
}
void notify_about_new_task_available()
{
ec_.notify_one_relaxed();
}
void notify_about_new_task_available_with_preference(tbb_thread* preference)
{
struct local
{
tbb_thread* preference_;
bool fired_;
bool operator () (void* ctx, size_t count, size_t idx)
{
tbb_thread* th = (tbb_thread*)ctx;
if (th == preference_)
{
fired_ = true;
return true;
}
else if (idx == count - 1 && fired_ == false)
{
return true;
}
else
{
return false;
}
}
}
pred = {preference};
ec_.notify_relaxed(pred);
}
void notify_about_list_of_tasks_available(size_t total_count, size_t preference_count, tbb_thread** preferences)
{
struct local
{
size_t remain_to_signal_;
size_t preference_count_;
tbb_thread** preferences_;
bool operator () (void* ctx, size_t count, size_t idx)
{
tbb_thread* th = (tbb_thread*)ctx;
size_t remain_in_waitset = count - idx;
if (remain_in_waitset <= remain_to_signal_)
{
return true;
}
else
{
for (size_t i = 0; i != preference_count_; ++i)
{
if (preferences_[i] == th)
{
remain_to_signal_ -= 1;
return true;
}
}
}
return false;
}
}
pred = {total_count, preference_count, preferences};
ec_.notify_relaxed(pred);
}
bool pool_is_empty()
{
return true;
}
};
struct queue
{
rl::atomic<int> producer_idx_;
rl::atomic<int> consumer_idx_;
rl::atomic<void*>* buffer_;
eventcount ec_;
queue()
{
producer_idx_($) = 0;
consumer_idx_($) = 0;
buffer_ = RL_NEW_ARR(rl::atomic<void*>, 10);
for (size_t i = 0; i != 10; ++i)
buffer_[i]($) = 0;
}
~queue()
{
RL_DELETE_ARR(buffer_);
}
void enqueue(void* data)
{
int idx = producer_idx_($).fetch_add(1) + 1; // atomic
buffer_[idx]($).store(data, rl::memory_order_relaxed);
struct local
{
int idx_;
bool operator () (void* ctx, size_t /*count*/, size_t /*idx*/)
{
return idx_ == (*(rl::var<int>*)ctx)($);
}
}
pred = {idx};
ec_.notify(pred); // not relaxed!!!
}
void* dequeue(ec_thread* th)
{
int idx = consumer_idx_($).fetch_add(1) + 1; // atomic
void* data = buffer_[idx]($).load(rl::memory_order_relaxed);
if (data)
return data;
for (;;)
{
rl::var<int> idxv (idx);
eventcount::wait_guard wait (ec_, th, &idxv);
data = buffer_[idx]($).load(rl::memory_order_relaxed);
if (data)
{
return data;
}
wait.commit_wait();
idxv($) = 0;
data = buffer_[idx]($).load(rl::memory_order_relaxed);
if (data)
{
return data;
}
rl::yield($, 1);
//RL_ASSERT(false);
}
}
};
class condition_variable
{
eventcount ec_;
public:
void wait(mutex& mtx, ec_thread* th)
{
eventcount::wait_guard wait (ec_, th);
mtx.unlock();
wait.commit_wait();
mtx.lock();
}
void signal()
{
ec_.notify_one();
}
void broadcast()
{
ec_.notify_all();
}
};
struct queue_test : rl::test_suite<queue_test, 4>
{
ec_thread threads_ [6];
queue q_;
void thread(unsigned index)
{
if (index < 2)
{
q_.enqueue((void*)(index*2+1));
q_.enqueue((void*)(index*2+2));
}
else
{
int data1 = (int)q_.dequeue(&threads_[index]);
RL_ASSERT(data1 >= 1 && data1 <= 6);
int data2 = (int)q_.dequeue(&threads_[index]);
RL_ASSERT(data2 >= 1 && data2 <= 6);
}
}
};
struct condvar_test : rl::test_suite<condvar_test, 3>
{
rl::var<int> stage;
condition_variable cv;
mutex mtx;
ec_thread th [3];
void before()
{
stage($) = 0;
}
void thread(unsigned index)
{
if (0 == index)
{
mtx.lock();
stage($) += 1;
cv.broadcast();
while (stage($) != 2)
cv.wait(mtx, &th[index]);
mtx.unlock();
}
else if (1 == index)
{
mtx.lock();
while (stage($) != 1)
cv.wait(mtx, &th[index]);
stage($) += 1;
cv.broadcast();
mtx.unlock();
}
else if (2 == index)
{
mtx.lock();
while (stage($) != 2)
cv.wait(mtx, &th[index]);
mtx.unlock();
}
}
};
int main()
{
rl::test_params p;
p.iteration_count = 100000000;
//p.initial_state = "30000000";
//p.search_type = rl::fair_context_bound_scheduler_type;
rl::simulate<queue_test>(p);
//rl::simulate<condvar_test>(p);
}
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eventcount", "eventcount.vcproj", "{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Debug|Win32.ActiveCfg = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Debug|Win32.Build.0 = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Release|Win32.ActiveCfg = Release|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,203 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="eventcount"
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}"
RootNamespace="eventcount"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
<File
RelativePath="..\eventcount.cpp"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eventcount", "eventcount.vcproj", "{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Debug|Win32.ActiveCfg = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Debug|Win32.Build.0 = Debug|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Release|Win32.ActiveCfg = Release|Win32
{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,203 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9,00"
Name="eventcount"
ProjectGUID="{ECB64178-A35E-4EB2-9EB0-BD72D6F7B6E5}"
RootNamespace="eventcount"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
Detect64BitPortabilityProblems="false"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
<File
RelativePath="..\eventcount.cpp"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,8 @@
// stdafx.cpp : source file that includes just the standard includes
// ws_deque.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
// TODO: reference any additional headers you need in STDAFX.H
// and not in this file
@@ -0,0 +1,6 @@
#pragma once
#include "../../relacy/pch.hpp"
#include "../../relacy/relacy_std.hpp"
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ws_deque", "ws_deque.vcproj", "{0B597F19-DEBB-4832-B520-9A93A286D595}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0B597F19-DEBB-4832-B520-9A93A286D595}.Debug|Win32.ActiveCfg = Debug|Win32
{0B597F19-DEBB-4832-B520-9A93A286D595}.Debug|Win32.Build.0 = Debug|Win32
{0B597F19-DEBB-4832-B520-9A93A286D595}.Release|Win32.ActiveCfg = Release|Win32
{0B597F19-DEBB-4832-B520-9A93A286D595}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
@@ -0,0 +1,205 @@
<?xml version="1.0" encoding="windows-1251"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8,00"
Name="ws_deque"
ProjectGUID="{0B597F19-DEBB-4832-B520-9A93A286D595}"
RootNamespace="ws_deque"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
UsePrecompiledHeader="2"
WarningLevel="4"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="1"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath="..\stdafx.cpp"
>
<FileConfiguration
Name="Debug|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
>
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"
ObjectFile="$(IntDir)\$(InputName)1.obj"
XMLDocumentationFileName="$(IntDir)\$(InputName)1.xdc"
/>
</FileConfiguration>
</File>
<File
RelativePath="..\stdafx.h"
>
</File>
<File
RelativePath="..\ws_deque.cpp"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
@@ -0,0 +1,20 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ws_deque", "ws_deque.vcproj", "{0B597F19-DEBB-4832-B520-9A93A286D595}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0B597F19-DEBB-4832-B520-9A93A286D595}.Debug|Win32.ActiveCfg = Debug|Win32
{0B597F19-DEBB-4832-B520-9A93A286D595}.Debug|Win32.Build.0 = Debug|Win32
{0B597F19-DEBB-4832-B520-9A93A286D595}.Release|Win32.ActiveCfg = Release|Win32
{0B597F19-DEBB-4832-B520-9A93A286D595}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Some files were not shown because too many files have changed in this diff Show More