<commit_before>// Copyright (C) 2013 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Clock.hpp>

#include <Nazara/Utility/SkeletalMesh.hpp>
#include <Nazara/Core/TaskScheduler.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/Config.hpp>
#include <Nazara/Utility/Mesh.hpp>
#include <Nazara/Utility/Skeleton.hpp>
#include <Nazara/Utility/VertexStruct.hpp>
#include <vector>
#include <Nazara/Utility/Debug.hpp>

namespace
{
	struct SkinningInfos
	{
		const NzJoint* joints;
		const NzMeshVertex* inputVertex;
		NzMeshVertex* outputVertex;
		const NzVertexWeight* vertexWeights;
		const NzWeight* weights;
	};

	void Skin_Position(const SkinningInfos& skinningInfos, unsigned int startVertex, unsigned int vertexCount)
	{
		const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex];
		NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex];

		unsigned int endVertex = startVertex + vertexCount - 1;
		for (unsigned int i = startVertex; i <= endVertex; ++i)
		{
			NzVector3f finalPosition(NzVector3f::Zero());

			unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size();
			for (unsigned int j = 0; j < weightCount; ++j)
			{
				const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]];

				NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix());
				mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix());
				mat *= weight.weight;

				finalPosition += mat.Transform(inputVertex->position);
			}

			outputVertex->position = finalPosition;
			outputVertex->uv = inputVertex->uv;

			inputVertex++;
			outputVertex++;
		}
	}

	void Skin_PositionNormal(const SkinningInfos& skinningInfos, unsigned int startVertex, unsigned int vertexCount)
	{
		const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex];
		NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex];

		unsigned int endVertex = startVertex + vertexCount - 1;
		for (unsigned int i = startVertex; i <= endVertex; ++i)
		{
			NzVector3f finalPosition(NzVector3f::Zero());
			NzVector3f finalNormal(NzVector3f::Zero());

			unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size();
			for (unsigned int j = 0; j < weightCount; ++j)
			{
				const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]];

				NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix());
				mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix());
				mat *= weight.weight;

				finalPosition += mat.Transform(inputVertex->position);
				finalNormal += mat.Transform(inputVertex->normal, 0.f);
			}

			finalNormal.Normalize();

			outputVertex->normal = finalNormal;
			outputVertex->position = finalPosition;
			outputVertex->uv = inputVertex->uv;

			inputVertex++;
			outputVertex++;
		}
	}

	void Skin_PositionNormalTangent(const SkinningInfos& skinningInfos, unsigned int startVertex, unsigned int vertexCount)
	{
		const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex];
		NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex];

		unsigned int endVertex = startVertex + vertexCount - 1;
		for (unsigned int i = startVertex; i <= endVertex; ++i)
		{
			NzVector3f finalPosition(NzVector3f::Zero());
			NzVector3f finalNormal(NzVector3f::Zero());
			NzVector3f finalTangent(NzVector3f::Zero());

			unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size();
			for (unsigned int j = 0; j < weightCount; ++j)
			{
				const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]];

				NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix());
				mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix());
				mat *= weight.weight;

				finalPosition += mat.Transform(inputVertex->position);
				finalNormal += mat.Transform(inputVertex->normal, 0.f);
				finalTangent += mat.Transform(inputVertex->tangent, 0.f);
			}

			finalNormal.Normalize();
			finalTangent.Normalize();

			outputVertex->normal = finalNormal;
			outputVertex->position = finalPosition;
			outputVertex->tangent = finalTangent;
			outputVertex->uv = inputVertex->uv;

			inputVertex++;
			outputVertex++;
		}
	}
}

struct NzSkeletalMeshImpl
{
	std::vector<NzVertexWeight> vertexWeights;
	std::vector<NzWeight> weights;
	NzCubef aabb;
	nzUInt8* bindPoseBuffer;
	NzIndexBufferConstRef indexBuffer;
	unsigned int vertexCount;
};

NzSkeletalMesh::NzSkeletalMesh(const NzMesh* parent) :
NzSubMesh(parent)
{
}

NzSkeletalMesh::~NzSkeletalMesh()
{
	Destroy();
}

bool NzSkeletalMesh::Create(unsigned int vertexCount, unsigned int weightCount)
{
	Destroy();

	#if NAZARA_UTILITY_SAFE
	if (vertexCount == 0)
	{
		NazaraError("Vertex count must be over 0");
		return false;
	}

	if (weightCount == 0)
	{
		NazaraError("Weight count must be over 0");
		return false;
	}
	#endif

	m_impl = new NzSkeletalMeshImpl;
	m_impl->bindPoseBuffer = new nzUInt8[vertexCount*sizeof(NzMeshVertex)];
	m_impl->vertexCount = vertexCount;
	m_impl->vertexWeights.resize(vertexCount);
	m_impl->weights.resize(weightCount);

	return true;
}

void NzSkeletalMesh::Destroy()
{
	if (m_impl)
	{
		if (m_impl->indexBuffer)
			m_impl->indexBuffer->RemoveResourceReference();

		delete[] m_impl->bindPoseBuffer;
		delete m_impl;
		m_impl = nullptr;
	}
}

void NzSkeletalMesh::Finish()
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return;
	}
	#endif

	// Rien à faire de particulier
}

const NzCubef& NzSkeletalMesh::GetAABB() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");

		static NzCubef dummy;
		return dummy;
	}
	#endif

	return m_impl->aabb;
}

nzAnimationType NzSkeletalMesh::GetAnimationType() const
{
	return nzAnimationType_Skeletal;
}

void* NzSkeletalMesh::GetBindPoseBuffer()
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return m_impl->bindPoseBuffer;
}

const void* NzSkeletalMesh::GetBindPoseBuffer() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return m_impl->bindPoseBuffer;
}

const NzIndexBuffer* NzSkeletalMesh::GetIndexBuffer() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return m_impl->indexBuffer;
}

unsigned int NzSkeletalMesh::GetVertexCount() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return 0;
	}
	#endif

	return m_impl->vertexCount;
}

NzVertexWeight* NzSkeletalMesh::GetVertexWeight(unsigned int vertexIndex)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return &m_impl->vertexWeights[vertexIndex];
}

const NzVertexWeight* NzSkeletalMesh::GetVertexWeight(unsigned int vertexIndex) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return &m_impl->vertexWeights[vertexIndex];
}

NzWeight* NzSkeletalMesh::GetWeight(unsigned int weightIndex)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return &m_impl->weights[weightIndex];
}

const NzWeight* NzSkeletalMesh::GetWeight(unsigned int weightIndex) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return &m_impl->weights[weightIndex];
}

unsigned int NzSkeletalMesh::GetWeightCount() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return 0;
	}
	#endif

	return m_impl->weights.size();
}

bool NzSkeletalMesh::IsAnimated() const
{
	return true;
}

bool NzSkeletalMesh::IsValid() const
{
	return m_impl != nullptr;
}

void NzSkeletalMesh::Skin(NzMeshVertex* outputBuffer) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return;
	}
	#endif

	Skin(outputBuffer, m_parent->GetSkeleton());
}

void NzSkeletalMesh::Skin(NzMeshVertex* outputBuffer, const NzSkeleton* skeleton) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return;
	}
	#endif

	SkinningInfos skinningInfos;
	skinningInfos.inputVertex = reinterpret_cast<const NzMeshVertex*>(m_impl->bindPoseBuffer);
	skinningInfos.outputVertex = outputBuffer;
	skinningInfos.joints = skeleton->GetJoints();
	skinningInfos.vertexWeights = &m_impl->vertexWeights[0];
	skinningInfos.weights = &m_impl->weights[0];

	#if NAZARA_UTILITY_MULTITHREADED_SKINNING
	unsigned int jointCount = skeleton->GetJointCount();
	for (unsigned int i = 0; i < jointCount; ++i)
		skinningInfos.joints[i].EnsureTransformMatrixUpdate();

	unsigned int workerCount = NzTaskScheduler::GetWorkerCount();

	std::ldiv_t div = std::ldiv(m_impl->vertexCount, workerCount); // Qui sait, peut-être que ça permet des optimisations plus efficaces
	for (unsigned int i = 0; i < workerCount; ++i)
		NzTaskScheduler::AddTask(Skin_PositionNormalTangent, skinningInfos, i*div.quot, (i == workerCount-1) ? div.quot + div.rem : div.quot);

	NzTaskScheduler::WaitForTasks();
	#else
	Skin_PositionNormalTangent(skinningInfos, 0, m_impl->vertexCount);
	#endif

	m_impl->aabb = skeleton->GetAABB();
}

void NzSkeletalMesh::SetIndexBuffer(const NzIndexBuffer* indexBuffer)
{
	m_impl->indexBuffer = indexBuffer;
}
<commit_msg>Fixed resource reference bug<commit_after>// Copyright (C) 2013 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp

#include <Nazara/Core/Clock.hpp>

#include <Nazara/Utility/SkeletalMesh.hpp>
#include <Nazara/Core/TaskScheduler.hpp>
#include <Nazara/Utility/BufferMapper.hpp>
#include <Nazara/Utility/Config.hpp>
#include <Nazara/Utility/Mesh.hpp>
#include <Nazara/Utility/Skeleton.hpp>
#include <Nazara/Utility/VertexStruct.hpp>
#include <vector>
#include <Nazara/Utility/Debug.hpp>

namespace
{
	struct SkinningInfos
	{
		const NzJoint* joints;
		const NzMeshVertex* inputVertex;
		NzMeshVertex* outputVertex;
		const NzVertexWeight* vertexWeights;
		const NzWeight* weights;
	};

	void Skin_Position(const SkinningInfos& skinningInfos, unsigned int startVertex, unsigned int vertexCount)
	{
		const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex];
		NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex];

		unsigned int endVertex = startVertex + vertexCount - 1;
		for (unsigned int i = startVertex; i <= endVertex; ++i)
		{
			NzVector3f finalPosition(NzVector3f::Zero());

			unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size();
			for (unsigned int j = 0; j < weightCount; ++j)
			{
				const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]];

				NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix());
				mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix());
				mat *= weight.weight;

				finalPosition += mat.Transform(inputVertex->position);
			}

			outputVertex->position = finalPosition;
			outputVertex->uv = inputVertex->uv;

			inputVertex++;
			outputVertex++;
		}
	}

	void Skin_PositionNormal(const SkinningInfos& skinningInfos, unsigned int startVertex, unsigned int vertexCount)
	{
		const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex];
		NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex];

		unsigned int endVertex = startVertex + vertexCount - 1;
		for (unsigned int i = startVertex; i <= endVertex; ++i)
		{
			NzVector3f finalPosition(NzVector3f::Zero());
			NzVector3f finalNormal(NzVector3f::Zero());

			unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size();
			for (unsigned int j = 0; j < weightCount; ++j)
			{
				const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]];

				NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix());
				mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix());
				mat *= weight.weight;

				finalPosition += mat.Transform(inputVertex->position);
				finalNormal += mat.Transform(inputVertex->normal, 0.f);
			}

			finalNormal.Normalize();

			outputVertex->normal = finalNormal;
			outputVertex->position = finalPosition;
			outputVertex->uv = inputVertex->uv;

			inputVertex++;
			outputVertex++;
		}
	}

	void Skin_PositionNormalTangent(const SkinningInfos& skinningInfos, unsigned int startVertex, unsigned int vertexCount)
	{
		const NzMeshVertex* inputVertex = &skinningInfos.inputVertex[startVertex];
		NzMeshVertex* outputVertex = &skinningInfos.outputVertex[startVertex];

		unsigned int endVertex = startVertex + vertexCount - 1;
		for (unsigned int i = startVertex; i <= endVertex; ++i)
		{
			NzVector3f finalPosition(NzVector3f::Zero());
			NzVector3f finalNormal(NzVector3f::Zero());
			NzVector3f finalTangent(NzVector3f::Zero());

			unsigned int weightCount = skinningInfos.vertexWeights[i].weights.size();
			for (unsigned int j = 0; j < weightCount; ++j)
			{
				const NzWeight& weight = skinningInfos.weights[skinningInfos.vertexWeights[i].weights[j]];

				NzMatrix4f mat(skinningInfos.joints[weight.jointIndex].GetInverseBindMatrix());
				mat.ConcatenateAffine(skinningInfos.joints[weight.jointIndex].GetTransformMatrix());
				mat *= weight.weight;

				finalPosition += mat.Transform(inputVertex->position);
				finalNormal += mat.Transform(inputVertex->normal, 0.f);
				finalTangent += mat.Transform(inputVertex->tangent, 0.f);
			}

			finalNormal.Normalize();
			finalTangent.Normalize();

			outputVertex->normal = finalNormal;
			outputVertex->position = finalPosition;
			outputVertex->tangent = finalTangent;
			outputVertex->uv = inputVertex->uv;

			inputVertex++;
			outputVertex++;
		}
	}
}

struct NzSkeletalMeshImpl
{
	std::vector<NzVertexWeight> vertexWeights;
	std::vector<NzWeight> weights;
	NzCubef aabb;
	nzUInt8* bindPoseBuffer;
	NzIndexBufferConstRef indexBuffer;
	unsigned int vertexCount;
};

NzSkeletalMesh::NzSkeletalMesh(const NzMesh* parent) :
NzSubMesh(parent)
{
}

NzSkeletalMesh::~NzSkeletalMesh()
{
	Destroy();
}

bool NzSkeletalMesh::Create(unsigned int vertexCount, unsigned int weightCount)
{
	Destroy();

	#if NAZARA_UTILITY_SAFE
	if (vertexCount == 0)
	{
		NazaraError("Vertex count must be over 0");
		return false;
	}

	if (weightCount == 0)
	{
		NazaraError("Weight count must be over 0");
		return false;
	}
	#endif

	m_impl = new NzSkeletalMeshImpl;
	m_impl->bindPoseBuffer = new nzUInt8[vertexCount*sizeof(NzMeshVertex)];
	m_impl->vertexCount = vertexCount;
	m_impl->vertexWeights.resize(vertexCount);
	m_impl->weights.resize(weightCount);

	return true;
}

void NzSkeletalMesh::Destroy()
{
	if (m_impl)
	{
		delete[] m_impl->bindPoseBuffer;
		delete m_impl;
		m_impl = nullptr;
	}
}

void NzSkeletalMesh::Finish()
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return;
	}
	#endif

	// Rien à faire de particulier
}

const NzCubef& NzSkeletalMesh::GetAABB() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");

		static NzCubef dummy;
		return dummy;
	}
	#endif

	return m_impl->aabb;
}

nzAnimationType NzSkeletalMesh::GetAnimationType() const
{
	return nzAnimationType_Skeletal;
}

void* NzSkeletalMesh::GetBindPoseBuffer()
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return m_impl->bindPoseBuffer;
}

const void* NzSkeletalMesh::GetBindPoseBuffer() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return m_impl->bindPoseBuffer;
}

const NzIndexBuffer* NzSkeletalMesh::GetIndexBuffer() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return m_impl->indexBuffer;
}

unsigned int NzSkeletalMesh::GetVertexCount() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return 0;
	}
	#endif

	return m_impl->vertexCount;
}

NzVertexWeight* NzSkeletalMesh::GetVertexWeight(unsigned int vertexIndex)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return &m_impl->vertexWeights[vertexIndex];
}

const NzVertexWeight* NzSkeletalMesh::GetVertexWeight(unsigned int vertexIndex) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return &m_impl->vertexWeights[vertexIndex];
}

NzWeight* NzSkeletalMesh::GetWeight(unsigned int weightIndex)
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return &m_impl->weights[weightIndex];
}

const NzWeight* NzSkeletalMesh::GetWeight(unsigned int weightIndex) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return nullptr;
	}
	#endif

	return &m_impl->weights[weightIndex];
}

unsigned int NzSkeletalMesh::GetWeightCount() const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return 0;
	}
	#endif

	return m_impl->weights.size();
}

bool NzSkeletalMesh::IsAnimated() const
{
	return true;
}

bool NzSkeletalMesh::IsValid() const
{
	return m_impl != nullptr;
}

void NzSkeletalMesh::Skin(NzMeshVertex* outputBuffer) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return;
	}
	#endif

	Skin(outputBuffer, m_parent->GetSkeleton());
}

void NzSkeletalMesh::Skin(NzMeshVertex* outputBuffer, const NzSkeleton* skeleton) const
{
	#if NAZARA_UTILITY_SAFE
	if (!m_impl)
	{
		NazaraError("Skeletal mesh not created");
		return;
	}
	#endif

	SkinningInfos skinningInfos;
	skinningInfos.inputVertex = reinterpret_cast<const NzMeshVertex*>(m_impl->bindPoseBuffer);
	skinningInfos.outputVertex = outputBuffer;
	skinningInfos.joints = skeleton->GetJoints();
	skinningInfos.vertexWeights = &m_impl->vertexWeights[0];
	skinningInfos.weights = &m_impl->weights[0];

	#if NAZARA_UTILITY_MULTITHREADED_SKINNING
	unsigned int jointCount = skeleton->GetJointCount();
	for (unsigned int i = 0; i < jointCount; ++i)
		skinningInfos.joints[i].EnsureTransformMatrixUpdate();

	unsigned int workerCount = NzTaskScheduler::GetWorkerCount();

	std::ldiv_t div = std::ldiv(m_impl->vertexCount, workerCount); // Qui sait, peut-être que ça permet des optimisations plus efficaces
	for (unsigned int i = 0; i < workerCount; ++i)
		NzTaskScheduler::AddTask(Skin_PositionNormalTangent, skinningInfos, i*div.quot, (i == workerCount-1) ? div.quot + div.rem : div.quot);

	NzTaskScheduler::WaitForTasks();
	#else
	Skin_PositionNormalTangent(skinningInfos, 0, m_impl->vertexCount);
	#endif

	m_impl->aabb = skeleton->GetAABB();
}

void NzSkeletalMesh::SetIndexBuffer(const NzIndexBuffer* indexBuffer)
{
	m_impl->indexBuffer = indexBuffer;
}
<|endoftext|>


<commit_before>/*  This file is part of the Vc library.

    Copyright (C) 2009 Matthias Kretz <kretz@kde.org>

    Vc is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Vc is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <Vc/float_v>
#include "benchmark.h"
#include <cstdio>

using namespace Vc;

static const int factor = 1000000;

int main()
{
    int blackHole = true;
    {
        Benchmark timer("SAXPY", 8. * float_v::Size * factor, "FLOP");
        for (int repetitions = 0; repetitions < 10; ++repetitions) {
            float_v alpha[4] = {
                float_v(repetitions + 0.2f),
                float_v(repetitions - 0.2f),
                float_v(repetitions + 0.1f),
                float_v(repetitions - 0.1f)
            };
            float_v x[4] = { 2.9f, 3.2f, 1.4f, 2.1f };
            float_v y[4] = { 1.2f, 0.2f, -1.4f, 4.3f };

            timer.Start();
            ///////////////////////////////////////

            for (int i = 0; i < factor; ++i) {
                    x[0] = alpha[0] * x[0] + y[0];
                    x[1] = alpha[1] * x[1] + y[1];
                    x[2] = alpha[2] * x[2] + y[2];
                    x[3] = alpha[3] * x[3] + y[3];
            }

            ///////////////////////////////////////
            timer.Stop();

            const int k = (x[0] < x[1]) && (x[2] < x[3]);
            blackHole &= k;
        }
        timer.Print(Benchmark::PrintAverage);
    }

    // reference
    {
        Benchmark timer("SAXPY (reference)", 8. * float_v::Size * factor, "FLOP");
        for (int repetitions = 0; repetitions < 10; ++repetitions) {
#ifdef USE_SSE
            __m128 tmp = _mm_set1_ps(static_cast<float>(repetitions));
            const __m128 oPoint2 = _mm_set1_ps(0.2f);
            const __m128 oPoint1 = _mm_set1_ps(0.1f);
            __m128 alpha[4] = {
                _mm_add_ps(tmp, oPoint2),
                _mm_sub_ps(tmp, oPoint2),
                _mm_add_ps(tmp, oPoint1),
                _mm_sub_ps(tmp, oPoint1)
            };
            __m128 x[4] = { _mm_set1_ps(2.9f), _mm_set1_ps(3.2f), _mm_set1_ps(1.4f), _mm_set1_ps(2.1f) };
            __m128 y[4] = { _mm_set1_ps(1.2f), _mm_set1_ps(0.2f), _mm_set1_ps(-1.4f), _mm_set1_ps(4.3f) };

            timer.Start();
            ///////////////////////////////////////

            for (int i = 0; i < factor; ++i) {
                    x[0] = _mm_add_ps(_mm_mul_ps(alpha[0], x[0]), y[0]);
                    x[1] = _mm_add_ps(_mm_mul_ps(alpha[1], x[1]), y[1]);
                    x[2] = _mm_add_ps(_mm_mul_ps(alpha[2], x[2]), y[2]);
                    x[3] = _mm_add_ps(_mm_mul_ps(alpha[3], x[3]), y[3]);
            }

            ///////////////////////////////////////
            timer.Stop();

            const int k = _mm_movemask_ps(_mm_add_ps(_mm_add_ps(x[0], x[1]), _mm_add_ps(x[2], x[3])));
            blackHole &= k;
#elif defined(ENABLE_LARRABEE)
            __m512 tmp = _mm512_set_1to16_ps(static_cast<float>(repetitions));
            const __m512 oPoint2 = _mm512_set_1to16_ps(0.2f);
            const __m512 oPoint1 = _mm512_set_1to16_ps(0.1f);
            __m512 alpha[4] = {
                _mm512_add_ps(tmp, oPoint2),
                _mm512_sub_ps(tmp, oPoint2),
                _mm512_add_ps(tmp, oPoint1),
                _mm512_sub_ps(tmp, oPoint1)
            };
            __m512 x[4] = { _mm512_set_1to16_ps(2.9f), _mm512_set_1to16_ps(3.2f), _mm512_set_1to16_ps(1.4f), _mm512_set_1to16_ps(2.1f) };
            __m512 y[4] = { _mm512_set_1to16_ps(1.2f), _mm512_set_1to16_ps(0.2f), _mm512_set_1to16_ps(-1.4f), _mm512_set_1to16_ps(4.3f) };

            timer.Start();
            ///////////////////////////////////////

            for (int i = 0; i < factor; ++i) {
                    x[0] = _mm512_madd132_ps(alpha[0], y[0], x[0]);
                    x[1] = _mm512_madd132_ps(alpha[1], y[1], x[1]);
                    x[2] = _mm512_madd132_ps(alpha[2], y[2], x[2]);
                    x[3] = _mm512_madd132_ps(alpha[3], y[3], x[3]);
            }

            ///////////////////////////////////////
            timer.Stop();

            const int k = _mm512_cmpeq_ps(_mm512_add_ps(x[0], x[1]), _mm512_add_ps(x[2], x[3]));
            blackHole &= k;
#else
            float alpha[4] = {
                float(repetitions + 0.2f),
                float(repetitions - 0.2f),
                float(repetitions + 0.1f),
                float(repetitions - 0.1f)
            };
            float x[4] = { 2.9f, 3.2f, 1.4f, 2.1f };
            float y[4] = { 1.2f, 0.2f, -1.4f, 4.3f };

            timer.Start();
            ///////////////////////////////////////

            for (int i = 0; i < factor; ++i) {
                    x[0] = alpha[0] * x[0] + y[0];
                    x[1] = alpha[1] * x[1] + y[1];
                    x[2] = alpha[2] * x[2] + y[2];
                    x[3] = alpha[3] * x[3] + y[3];
            }

            ///////////////////////////////////////
            timer.Stop();

            const int k = (x[0] < x[1]) && (x[2] < x[3]);
            blackHole &= k;
#endif
        }
        timer.Print(Benchmark::PrintAverage);
    }
    if (blackHole == 82934) {
        std::cout << std::endl;
    }
    return 0;
}
<commit_msg>force compiler to use as many registers as possible; better black hole that the compiler cannot optimize away; use random numbers to keep the compiler from optimizing too much<commit_after>/*  This file is part of the Vc library.

    Copyright (C) 2009 Matthias Kretz <kretz@kde.org>

    Vc is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as
    published by the Free Software Foundation, either version 3 of
    the License, or (at your option) any later version.

    Vc is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Vc.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <Vc/float_v>
#include "benchmark.h"
#include <cstdio>
#include <cstdlib>

using namespace Vc;

static const int factor = 1000000;

static float randomF(float min, float max)
{
    const float delta = max - min;
    return min + delta * rand() / RAND_MAX;
}

static float randomF12() { return randomF(1.f, 2.f); }

int main()
{
    int blackHole = true;
    {
        Benchmark timer("SAXPY", 8. * float_v::Size * factor, "FLOP");
        for (int repetitions = 0; repetitions < 10; ++repetitions) {
            const float_v alpha[4] = {
                float_v(repetitions + randomF(.1f, .2f)),
                float_v(repetitions - randomF(.1f, .2f)),
                float_v(repetitions + randomF(.1f, .2f)),
                float_v(repetitions - randomF(.1f, .2f))
            };
            float_v x[4] = { randomF12(), randomF12(), randomF12(), randomF12() };
            const float_v y[4] = { randomF12(), randomF12(), randomF12(), randomF12() };

            timer.Start();
            ///////////////////////////////////////

            for (int i = 0; i < factor; ++i) {
                    x[0] = alpha[0] * x[0] + y[0];
                    x[1] = alpha[1] * x[1] + y[1];
                    x[2] = alpha[2] * x[2] + y[2];
                    x[3] = alpha[3] * x[3] + y[3];
            }

            ///////////////////////////////////////
            timer.Stop();

            const int k = (x[0] < x[1]) && (x[2] < x[3]);
            blackHole &= k;
        }
        timer.Print(Benchmark::PrintAverage);
    }

    // reference
    {
        Benchmark timer("SAXPY (reference)", 8. * float_v::Size * factor, "FLOP");
        for (int repetitions = 0; repetitions < 10; ++repetitions) {
#ifdef USE_SSE
            __m128 tmp = _mm_set1_ps(static_cast<float>(repetitions));
            const __m128 oPoint2 = _mm_set_ps(randomF(.1f, .2f), randomF(.1f, .2f), randomF(.1f, .2f), randomF(.1f, .2f));
            const __m128 oPoint1 = _mm_set_ps(randomF(.1f, .2f), randomF(.1f, .2f), randomF(.1f, .2f), randomF(.1f, .2f));
            const __m128 alpha[4] = {
                _mm_add_ps(tmp, oPoint2),
                _mm_sub_ps(tmp, oPoint2),
                _mm_add_ps(tmp, oPoint1),
                _mm_sub_ps(tmp, oPoint1)
            };
            __m128 x[4] = { _mm_set_ps(randomF12(), randomF12(), randomF12(), randomF12()),
                _mm_set_ps(randomF12(), randomF12(), randomF12(), randomF12()),
                _mm_set_ps(randomF12(), randomF12(), randomF12(), randomF12()),
                _mm_set_ps(randomF12(), randomF12(), randomF12(), randomF12()) };
            const __m128 y[4] = { _mm_set_ps(randomF12(), randomF12(), randomF12(), randomF12()),
                _mm_set_ps(randomF12(), randomF12(), randomF12(), randomF12()),
                _mm_set_ps(randomF12(), randomF12(), randomF12(), randomF12()),
                _mm_set_ps(randomF12(), randomF12(), randomF12(), randomF12()) };

            // force the vectors to xmm registers, otherwise GCC decides to work on the stack and
            // lose half of the performance
            asm volatile("" ::
                    "x"(x[0]), "x"(x[1]), "x"(x[2]), "x"(x[3]),
                    "x"(y[0]), "x"(y[1]), "x"(y[2]), "x"(y[3]),
                    "x"(alpha[0]), "x"(alpha[1]), "x"(alpha[2]), "x"(alpha[3]));

            timer.Start();
            ///////////////////////////////////////

            for (int i = 0; i < factor; ++i) {
                    x[0] = _mm_add_ps(_mm_mul_ps(alpha[0], x[0]), y[0]);
                    x[1] = _mm_add_ps(_mm_mul_ps(alpha[1], x[1]), y[1]);
                    x[2] = _mm_add_ps(_mm_mul_ps(alpha[2], x[2]), y[2]);
                    x[3] = _mm_add_ps(_mm_mul_ps(alpha[3], x[3]), y[3]);
            }

            ///////////////////////////////////////
            timer.Stop();

            const int k = _mm_movemask_ps(_mm_add_ps(_mm_add_ps(x[0], x[1]), _mm_add_ps(x[2], x[3])));
            blackHole &= k;
#elif defined(ENABLE_LARRABEE)
            __m512 tmp = _mm512_set_1to16_ps(static_cast<float>(repetitions));
            const __m512 oPoint2 = _mm512_set_1to16_ps(randomF(.1f, .2f));
            const __m512 oPoint1 = _mm512_set_1to16_ps(randomF(.1f, .2f));
            const __m512 alpha[4] = {
                _mm512_add_ps(tmp, oPoint2),
                _mm512_sub_ps(tmp, oPoint2),
                _mm512_add_ps(tmp, oPoint1),
                _mm512_sub_ps(tmp, oPoint1)
            };
            __m512 x[4] = { _mm512_set_1to16_ps(randomF12()), _mm512_set_1to16_ps(randomF12()), _mm512_set_1to16_ps(randomF12()), _mm512_set_1to16_ps(randomF12()) };
            const __m512 y[4] = { _mm512_set_1to16_ps(randomF12()), _mm512_set_1to16_ps(randomF12()), _mm512_set_1to16_ps(randomF12()), _mm512_set_1to16_ps(randomF12()) };

            timer.Start();
            ///////////////////////////////////////

            for (int i = 0; i < factor; ++i) {
                    x[0] = _mm512_madd132_ps(alpha[0], y[0], x[0]);
                    x[1] = _mm512_madd132_ps(alpha[1], y[1], x[1]);
                    x[2] = _mm512_madd132_ps(alpha[2], y[2], x[2]);
                    x[3] = _mm512_madd132_ps(alpha[3], y[3], x[3]);
            }

            ///////////////////////////////////////
            timer.Stop();

            const int k = _mm512_cmpeq_ps(_mm512_add_ps(x[0], x[1]), _mm512_add_ps(x[2], x[3]));
            blackHole &= k;
#else
            const float alpha[4] = {
                float(repetitions + randomF(.1f, .2f)),
                float(repetitions - randomF(.1f, .2f)),
                float(repetitions + randomF(.1f, .2f)),
                float(repetitions - randomF(.1f, .2f))
            };
            float x[4] = { randomF12(), randomF12(), randomF12(), randomF12() };
            const float y[4] = { randomF12(), randomF12(), randomF12(), randomF12() };

            timer.Start();
            ///////////////////////////////////////

            for (int i = 0; i < factor; ++i) {
                    x[0] = alpha[0] * x[0] + y[0];
                    x[1] = alpha[1] * x[1] + y[1];
                    x[2] = alpha[2] * x[2] + y[2];
                    x[3] = alpha[3] * x[3] + y[3];
            }

            ///////////////////////////////////////
            timer.Stop();

            const int k = (x[0] < x[1]) && (x[2] < x[3]);
            blackHole &= k;
#endif
        }
        timer.Print(Benchmark::PrintAverage);
    }
    if (blackHole != 0) {
        std::cout << std::endl;
    }
    return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: XTempFile.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: mtg $ $Date: 2001-09-06 12:53:04 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _XTEMPFILE_HXX
#define _XTEMPFILE_HXX

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_
#include <com/sun/star/io/XOutputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XSEEKABLE_HPP_
#include <com/sun/star/io/XSeekable.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

class SvStream;
namespace utl { class TempFile; }

class XTempFile : public com::sun::star::io::XInputStream,
                  public com::sun::star::io::XOutputStream,
                  public com::sun::star::io::XSeekable,
                  public com::sun::star::beans::XPropertySet,
                  public cppu::OWeakObject
{
protected:
    ::utl::TempFile*    mpTempFile;
    ::osl::Mutex        maMutex;
    SvStream*           mpStream;
    void checkError () const;
    void checkConnected () const;

public:
    XTempFile ();
    virtual ~XTempFile ();

    // XInterface
    virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& aType )
        throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL acquire(  )
        throw ();
    virtual void SAL_CALL release(  )
        throw ();
    // XInputStream
    virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int32 SAL_CALL available(  )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL closeInput(  )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    // XOutputStream
    virtual void SAL_CALL writeBytes( const ::com::sun::star::uno::Sequence< sal_Int8 >& aData )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL flush(  )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL closeOutput(  )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    // XSeekable
    virtual void SAL_CALL seek( sal_Int64 location )
        throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getPosition(  )
        throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getLength(  )
        throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

    // XPropertySet
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(  )
        throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    static ::rtl::OUString getImplementationName ();
    static ::com::sun::star::uno::Sequence < ::rtl::OUString > getSupportedServiceNames();
    static ::com::sun::star::uno::Reference < com::sun::star::lang::XSingleServiceFactory > createServiceFactory( com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > const & rServiceFactory );
    virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & rServiceName)
        throw (com::sun::star::uno::RuntimeException);
};
#endif
<commit_msg>INTEGRATION: CWS mav05 (1.4.80); FILE MERGED 2003/07/07 13:54:18 mav 1.4.80.2: #i15929# allow to close temporary file explicitly 2003/06/23 09:20:58 mav 1.4.80.1: #i15929# extend temporary file service<commit_after>/*************************************************************************
 *
 *  $RCSfile: XTempFile.hxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: kz $ $Date: 2003-09-11 10:31:46 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Martin Gallwey (gallwey@sun.com)
 *
 *
 ************************************************************************/
#ifndef _XTEMPFILE_HXX
#define _XTEMPFILE_HXX

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_
#include <com/sun/star/io/XOutputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XSEEKABLE_HPP_
#include <com/sun/star/io/XSeekable.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XSTREAM_HPP_
#include <com/sun/star/io/XStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XTRUNCATE_HPP_
#include <com/sun/star/io/XTruncate.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSINGLESERVICEFACTORY_HPP_
#include <com/sun/star/lang/XSingleServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_BEANS_XPROPERTYSET_HPP_
#include <com/sun/star/beans/XPropertySet.hpp>
#endif
#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

class SvStream;
namespace utl { class TempFile; }

class XTempFile : public com::sun::star::io::XInputStream,
                  public com::sun::star::io::XOutputStream,
                  public com::sun::star::io::XSeekable,
                  public com::sun::star::io::XStream,
                  public com::sun::star::io::XTruncate,
                  public com::sun::star::beans::XPropertySet,
                  public cppu::OWeakObject
{
protected:
    ::utl::TempFile*    mpTempFile;
    ::osl::Mutex        maMutex;
    SvStream*           mpStream;
    sal_Bool            mbRemoveFile;
    sal_Bool            mbInClosed;
    sal_Bool            mbOutClosed;

    void checkError () const;
    void checkConnected () const;

public:
    XTempFile ();
    virtual ~XTempFile ();

    // XInterface
    virtual ::com::sun::star::uno::Any SAL_CALL queryInterface( const ::com::sun::star::uno::Type& aType )
        throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL acquire(  )
        throw ();
    virtual void SAL_CALL release(  )
        throw ();
    // XInputStream
    virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int32 SAL_CALL available(  )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL closeInput(  )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    // XOutputStream
    virtual void SAL_CALL writeBytes( const ::com::sun::star::uno::Sequence< sal_Int8 >& aData )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL flush(  )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL closeOutput(  )
        throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    // XSeekable
    virtual void SAL_CALL seek( sal_Int64 location )
        throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getPosition(  )
        throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual sal_Int64 SAL_CALL getLength(  )
        throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

    // XStream
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream(  )
        throw (::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > SAL_CALL getOutputStream(  )
        throw (::com::sun::star::uno::RuntimeException);

    // XTruncate
    virtual void SAL_CALL truncate()
        throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);

    // XPropertySet
    virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo(  )
        throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener )
        throw (::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException);
    static ::rtl::OUString getImplementationName ();
    static ::com::sun::star::uno::Sequence < ::rtl::OUString > getSupportedServiceNames();
    static ::com::sun::star::uno::Reference < com::sun::star::lang::XSingleServiceFactory > createServiceFactory( com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > const & rServiceFactory );
    virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & rServiceName)
        throw (com::sun::star::uno::RuntimeException);
};
#endif
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <unsupported/Eigen/MatrixFunctions>

double binom(int n, int k)
{
  double res = 1;
  for (int i=0; i<k; i++)
    res = res * (n-k+i+1) / (i+1);
  return res;
}

template <typename Derived, typename OtherDerived>
double relerr(const MatrixBase<Derived>& A, const MatrixBase<OtherDerived>& B)
{
  return std::sqrt((A - B).cwiseAbs2().sum() / std::min(A.cwiseAbs2().sum(), B.cwiseAbs2().sum()));
}

template <typename T>
T expfn(T x, int)
{
  return std::exp(x);
}

template <typename T>
void test2dRotation(double tol)
{
  Matrix<T,2,2> A, B, C;
  T angle;

  A << 0, 1, -1, 0;
  for (int i=0; i<=20; i++)
  {
    angle = static_cast<T>(pow(10, i / 5. - 2));
    B << cos(angle), sin(angle), -sin(angle), cos(angle);

    ei_matrix_function(angle*A, expfn, &C);
    std::cout << "test2dRotation: i = " << i << "   error funm = " << relerr(C, B);
    VERIFY(C.isApprox(B, static_cast<T>(tol)));

    C = ei_matrix_exponential(angle*A);
    std::cout << "   error expm = " << relerr(C, B) << "\n";
    VERIFY(C.isApprox(B, static_cast<T>(tol)));
  }
}

template <typename T>
void test2dHyperbolicRotation(double tol)
{
  Matrix<std::complex<T>,2,2> A, B, C;
  std::complex<T> imagUnit(0,1);
  T angle, ch, sh;

  for (int i=0; i<=20; i++)
  {
    angle = static_cast<T>((i-10) / 2.0);
    ch = std::cosh(angle);
    sh = std::sinh(angle);
    A << 0, angle*imagUnit, -angle*imagUnit, 0;
    B << ch, sh*imagUnit, -sh*imagUnit, ch;

    ei_matrix_function(A, expfn, &C);
    std::cout << "test2dHyperbolicRotation: i = " << i << "   error funm = " << relerr(C, B);
    VERIFY(C.isApprox(B, static_cast<T>(tol)));

    C = ei_matrix_exponential(A);
    std::cout << "   error expm = " << relerr(C, B) << "\n";
    VERIFY(C.isApprox(B, static_cast<T>(tol)));
  }
}

template <typename T>
void testPascal(double tol)
{
  for (int size=1; size<20; size++)
  {
    Matrix<T,Dynamic,Dynamic> A(size,size), B(size,size), C(size,size);
    A.setZero();
    for (int i=0; i<size-1; i++)
      A(i+1,i) = static_cast<T>(i+1);
    B.setZero();
    for (int i=0; i<size; i++)
      for (int j=0; j<=i; j++)
    B(i,j) = static_cast<T>(binom(i,j));

    ei_matrix_function(A, expfn, &C);
    std::cout << "testPascal: size = " << size << "   error funm = " << relerr(C, B);
    VERIFY(C.isApprox(B, static_cast<T>(tol)));

    C = ei_matrix_exponential(A);
    std::cout << "   error expm = " << relerr(C, B) << "\n";
    VERIFY(C.isApprox(B, static_cast<T>(tol)));
  }
}

template<typename MatrixType>
void randomTest(const MatrixType& m, double tol)
{
  /* this test covers the following files:
     Inverse.h
  */
  int rows = m.rows();
  int cols = m.cols();
  MatrixType m1(rows, cols), m2(rows, cols), m3(rows, cols),
             identity = MatrixType::Identity(rows, rows);

  typedef typename NumTraits<typename ei_traits<MatrixType>::Scalar>::Real RealScalar;

  for(int i = 0; i < g_repeat; i++) {
    m1 = MatrixType::Random(rows, cols);

    ei_matrix_function(m1, expfn, &m2);
    ei_matrix_function(-m1, expfn, &m3);
    std::cout << "randomTest: error funm = " << relerr(identity, m2 * m3);
    VERIFY(identity.isApprox(m2 * m3, static_cast<RealScalar>(tol)));

    m2 = ei_matrix_exponential(m1) * ei_matrix_exponential(-m1);
    std::cout << "   error expm = " << relerr(identity, m2) << "\n";
    VERIFY(identity.isApprox(m2, static_cast<RealScalar>(tol)));
  }
}

void test_matrix_exponential()
{
  CALL_SUBTEST_2(test2dRotation<double>(1e-13));
  CALL_SUBTEST_1(test2dRotation<float>(1e-5));
  CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14));
  CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
  CALL_SUBTEST_6(testPascal<float>(1e-6));
  CALL_SUBTEST_5(testPascal<double>(1e-15));
  CALL_SUBTEST_2(randomTest(Matrix2d(), 1e-13));
  CALL_SUBTEST_7(randomTest(Matrix<double,3,3,RowMajor>(), 1e-13));
  CALL_SUBTEST_3(randomTest(Matrix4cd(), 1e-13));
  CALL_SUBTEST_4(randomTest(MatrixXd(8,8), 1e-13));
  CALL_SUBTEST_1(randomTest(Matrix2f(), 1e-4));
  CALL_SUBTEST_5(randomTest(Matrix3cf(), 1e-4));
  CALL_SUBTEST_1(randomTest(Matrix4f(), 1e-4));
  CALL_SUBTEST_6(randomTest(MatrixXf(8,8), 1e-4));
}
<commit_msg>Update matrix_exponential test after API change in ei_matrix_function Apologies for forgetting this yesterday and not testing properly.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Jitse Niesen <jitse@maths.leeds.ac.uk>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"
#include <unsupported/Eigen/MatrixFunctions>

double binom(int n, int k)
{
  double res = 1;
  for (int i=0; i<k; i++)
    res = res * (n-k+i+1) / (i+1);
  return res;
}

template <typename Derived, typename OtherDerived>
double relerr(const MatrixBase<Derived>& A, const MatrixBase<OtherDerived>& B)
{
  return std::sqrt((A - B).cwiseAbs2().sum() / std::min(A.cwiseAbs2().sum(), B.cwiseAbs2().sum()));
}

template <typename T>
T expfn(T x, int)
{
  return std::exp(x);
}

template <typename T>
void test2dRotation(double tol)
{
  Matrix<T,2,2> A, B, C;
  T angle;

  A << 0, 1, -1, 0;
  for (int i=0; i<=20; i++)
  {
    angle = static_cast<T>(pow(10, i / 5. - 2));
    B << cos(angle), sin(angle), -sin(angle), cos(angle);

    C = ei_matrix_function(angle*A, expfn);
    std::cout << "test2dRotation: i = " << i << "   error funm = " << relerr(C, B);
    VERIFY(C.isApprox(B, static_cast<T>(tol)));

    C = ei_matrix_exponential(angle*A);
    std::cout << "   error expm = " << relerr(C, B) << "\n";
    VERIFY(C.isApprox(B, static_cast<T>(tol)));
  }
}

template <typename T>
void test2dHyperbolicRotation(double tol)
{
  Matrix<std::complex<T>,2,2> A, B, C;
  std::complex<T> imagUnit(0,1);
  T angle, ch, sh;

  for (int i=0; i<=20; i++)
  {
    angle = static_cast<T>((i-10) / 2.0);
    ch = std::cosh(angle);
    sh = std::sinh(angle);
    A << 0, angle*imagUnit, -angle*imagUnit, 0;
    B << ch, sh*imagUnit, -sh*imagUnit, ch;

    C = ei_matrix_function(A, expfn);
    std::cout << "test2dHyperbolicRotation: i = " << i << "   error funm = " << relerr(C, B);
    VERIFY(C.isApprox(B, static_cast<T>(tol)));

    C = ei_matrix_exponential(A);
    std::cout << "   error expm = " << relerr(C, B) << "\n";
    VERIFY(C.isApprox(B, static_cast<T>(tol)));
  }
}

template <typename T>
void testPascal(double tol)
{
  for (int size=1; size<20; size++)
  {
    Matrix<T,Dynamic,Dynamic> A(size,size), B(size,size), C(size,size);
    A.setZero();
    for (int i=0; i<size-1; i++)
      A(i+1,i) = static_cast<T>(i+1);
    B.setZero();
    for (int i=0; i<size; i++)
      for (int j=0; j<=i; j++)
    B(i,j) = static_cast<T>(binom(i,j));

    C = ei_matrix_function(A, expfn);
    std::cout << "testPascal: size = " << size << "   error funm = " << relerr(C, B);
    VERIFY(C.isApprox(B, static_cast<T>(tol)));

    C = ei_matrix_exponential(A);
    std::cout << "   error expm = " << relerr(C, B) << "\n";
    VERIFY(C.isApprox(B, static_cast<T>(tol)));
  }
}

template<typename MatrixType>
void randomTest(const MatrixType& m, double tol)
{
  /* this test covers the following files:
     Inverse.h
  */
  int rows = m.rows();
  int cols = m.cols();
  MatrixType m1(rows, cols), m2(rows, cols), m3(rows, cols),
             identity = MatrixType::Identity(rows, rows);

  typedef typename NumTraits<typename ei_traits<MatrixType>::Scalar>::Real RealScalar;

  for(int i = 0; i < g_repeat; i++) {
    m1 = MatrixType::Random(rows, cols);

    m2 = ei_matrix_function(m1, expfn) * ei_matrix_function(-m1, expfn);
    std::cout << "randomTest: error funm = " << relerr(identity, m2 * m3);
    VERIFY(identity.isApprox(m2, static_cast<RealScalar>(tol)));

    m2 = ei_matrix_exponential(m1) * ei_matrix_exponential(-m1);
    std::cout << "   error expm = " << relerr(identity, m2) << "\n";
    VERIFY(identity.isApprox(m2, static_cast<RealScalar>(tol)));
  }
}

void test_matrix_exponential()
{
  CALL_SUBTEST_2(test2dRotation<double>(1e-13));
  CALL_SUBTEST_1(test2dRotation<float>(1e-5));
  CALL_SUBTEST_2(test2dHyperbolicRotation<double>(1e-14));
  CALL_SUBTEST_1(test2dHyperbolicRotation<float>(1e-5));
  CALL_SUBTEST_6(testPascal<float>(1e-6));
  CALL_SUBTEST_5(testPascal<double>(1e-15));
  CALL_SUBTEST_2(randomTest(Matrix2d(), 1e-13));
  CALL_SUBTEST_7(randomTest(Matrix<double,3,3,RowMajor>(), 1e-13));
  CALL_SUBTEST_3(randomTest(Matrix4cd(), 1e-13));
  CALL_SUBTEST_4(randomTest(MatrixXd(8,8), 1e-13));
  CALL_SUBTEST_1(randomTest(Matrix2f(), 1e-4));
  CALL_SUBTEST_5(randomTest(Matrix3cf(), 1e-4));
  CALL_SUBTEST_1(randomTest(Matrix4f(), 1e-4));
  CALL_SUBTEST_6(randomTest(MatrixXf(8,8), 1e-4));
}
<|endoftext|>


<commit_before>#include "SysConfig.h"
#if(HAS_STD_LIGHTS)

// Includes
#include <Arduino.h>
#include "CLights.h"
#include "CPin.h"
#include "NCommManager.h"
#include "NVehicleManager.h"
#include "PinDefinitions.h"

namespace
{
	CPin light( "light", PIN_STANDARD_LIGHTS, CPin::kAnalog, CPin::kOutput );
}

void CLights::Initialize()
{
	NVehicleManager::m_capabilityBitmask |= ( 1 << LIGHTS_CAPABLE );

	light.Reset();
	light.Write( 0 );
}

void CLights::Update( CCommand& commandIn )
{
	// Check for messages
	if( !NCommManager::m_isCommandAvailable )
	{
		return;
	}

	// Handle messages
	if( commandIn.Equals( "ligt" ) )
	{
		// 0 - 255
		int value = commandIn.m_arguments[1];
		light.Write( value );

		// LIGT - Light toggle
		Serial.print( F( "LIGT:" ) );
		Serial.print( value );
		Serial.print( ';' );

		// LIGP - Light percentage
		Serial.print( F( "LIGP:" ) );
		Serial.print( commandIn.m_arguments[1] / 255.0f );
		Serial.println( ';' );
	}
}

#endif
<commit_msg>Updated Trident's light class to match the new light map updates<commit_after>#include "SysConfig.h"
#if(HAS_STD_LIGHTS)

// Includes
#include <Arduino.h>
#include "CLights.h"
#include "CPin.h"
#include "NCommManager.h"
#include "NVehicleManager.h"
#include "PinDefinitions.h"

namespace
{
	CPin light( "light", PIN_STANDARD_LIGHTS, CPin::kAnalog, CPin::kOutput );
}

void CLights::Initialize()
{
	NVehicleManager::m_capabilityBitmask |= ( 1 << LIGHTS_CAPABLE );

	light.Reset();
	light.Write( 0 );
}

void CLights::Update( CCommand& commandIn )
{
	// Check for messages
	if( !NCommManager::m_isCommandAvailable )
	{
		return;
	}

	// Handle messages
	if( commandIn.Equals( "ligt" ) )
	{
		// Should be between 0-255, with 255 being full brightness
		int value = commandIn.m_arguments[1];

		// Bounds corrections
		if( value < 0 )
		{
			value = 0;
		}
		if( value > 255 )
		{
			value = 255;
		}

		light.Write( value );

		Serial.print( F( "LIGT:" ) );
		Serial.print( value );
		Serial.print( ';' );
	}
}

#endif
<|endoftext|>


<commit_before>//===-- tsan_rtl_thread.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_placement_new.h"
#include "tsan_rtl.h"
#include "tsan_mman.h"
#include "tsan_platform.h"
#include "tsan_report.h"
#include "tsan_sync.h"

namespace __tsan {

// ThreadContext implementation.

ThreadContext::ThreadContext(int tid)
  : ThreadContextBase(tid)
  , thr()
  , sync()
  , epoch0()
  , epoch1() {
}

#ifndef TSAN_GO
ThreadContext::~ThreadContext() {
}
#endif

void ThreadContext::OnDead() {
  sync.Reset();
}

void ThreadContext::OnJoined(void *arg) {
  ThreadState *caller_thr = static_cast<ThreadState *>(arg);
  AcquireImpl(caller_thr, 0, &sync);
  sync.Reset();
}

struct OnCreatedArgs {
  ThreadState *thr;
  uptr pc;
};

void ThreadContext::OnCreated(void *arg) {
  thr = 0;
  if (tid == 0)
    return;
  OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
  args->thr->fast_state.IncrementEpoch();
  // Can't increment epoch w/o writing to the trace as well.
  TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
  ReleaseImpl(args->thr, 0, &sync);
#ifdef TSAN_GO
  creation_stack.ObtainCurrent(args->thr, args->pc);
#else
  creation_stack_id = CurrentStackId(args->thr, args->pc);
#endif
  if (reuse_count == 0)
    StatInc(args->thr, StatThreadMaxTid);
}

void ThreadContext::OnReset() {
  sync.Reset();
  FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event));
  //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace));
}

struct OnStartedArgs {
  ThreadState *thr;
  uptr stk_addr;
  uptr stk_size;
  uptr tls_addr;
  uptr tls_size;
};

void ThreadContext::OnStarted(void *arg) {
  OnStartedArgs *args = static_cast<OnStartedArgs*>(arg);
  thr = args->thr;
  // RoundUp so that one trace part does not contain events
  // from different threads.
  epoch0 = RoundUp(epoch1 + 1, kTracePartSize);
  epoch1 = (u64)-1;
  new(thr) ThreadState(CTX(), tid, unique_id,
      epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
#ifndef TSAN_GO
  thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
  thr->shadow_stack_pos = thr->shadow_stack;
  thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize;
#else
  // Setup dynamic shadow stack.
  const int kInitStackSize = 8;
  thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
      kInitStackSize * sizeof(uptr));
  thr->shadow_stack_pos = thr->shadow_stack;
  thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
#endif
#ifndef TSAN_GO
  AllocatorThreadStart(thr);
#endif
  thr->fast_synch_epoch = epoch0;
  AcquireImpl(thr, 0, &sync);
  thr->fast_state.SetHistorySize(flags()->history_size);
  const uptr trace = (epoch0 / kTracePartSize) % TraceParts();
  Trace *thr_trace = ThreadTrace(thr->tid);
  thr_trace->headers[trace].epoch0 = epoch0;
  StatInc(thr, StatSyncAcquire);
  sync.Reset();
  DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
          "tls_addr=%zx tls_size=%zx\n",
          tid, (uptr)epoch0, args->stk_addr, args->stk_size,
          args->tls_addr, args->tls_size);
  thr->is_alive = true;
}

void ThreadContext::OnFinished() {
  if (!detached) {
    thr->fast_state.IncrementEpoch();
    // Can't increment epoch w/o writing to the trace as well.
    TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
    ReleaseImpl(thr, 0, &sync);
  }
  epoch1 = thr->fast_state.epoch();

#ifndef TSAN_GO
  AllocatorThreadFinish(thr);
#endif
  thr->~ThreadState();
  StatAggregate(CTX()->stat, thr->stat);
  thr = 0;
}

#ifndef TSAN_GO
struct ThreadLeak {
  ThreadContext *tctx;
  int count;
};

static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
  Vector<ThreadLeak> &leaks = *(Vector<ThreadLeak>*)arg;
  ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
  if (tctx->detached || tctx->status != ThreadStatusFinished)
    return;
  for (uptr i = 0; i < leaks.Size(); i++) {
    if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) {
      leaks[i].count++;
      return;
    }
  }
  ThreadLeak leak = {tctx, 1};
  leaks.PushBack(leak);
}
#endif

#ifndef TSAN_GO
static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
  if (tctx->tid == 0) {
    Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
  } else {
    Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
      " created at:\n", tctx->tid, tctx->name);
    PrintStack(SymbolizeStackId(tctx->creation_stack_id));
  }
  for (uptr i = 0; i < set->Size(); i++) {
    Printf("  Ignore was enabled at:\n");
    PrintStack(SymbolizeStackId(set->At(i)));
  }
  Die();
}

static void ThreadCheckIgnore(ThreadState *thr) {
  if (thr->ignore_reads_and_writes)
    ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set);
  if (thr->ignore_sync)
    ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set);
}
#else
static void ThreadCheckIgnore(ThreadState *thr) {}
#endif

void ThreadFinalize(ThreadState *thr) {
  CHECK_GT(thr->in_rtl, 0);
  ThreadCheckIgnore(thr);
#ifndef TSAN_GO
  if (!flags()->report_thread_leaks)
    return;
  ThreadRegistryLock l(CTX()->thread_registry);
  Vector<ThreadLeak> leaks(MBlockScopedBuf);
  CTX()->thread_registry->RunCallbackForEachThreadLocked(
      MaybeReportThreadLeak, &leaks);
  for (uptr i = 0; i < leaks.Size(); i++) {
    ScopedReport rep(ReportTypeThreadLeak);
    rep.AddThread(leaks[i].tctx);
    rep.SetCount(leaks[i].count);
    OutputReport(CTX(), rep);
  }
#endif
}

int ThreadCount(ThreadState *thr) {
  CHECK_GT(thr->in_rtl, 0);
  Context *ctx = CTX();
  uptr result;
  ctx->thread_registry->GetNumberOfThreads(0, 0, &result);
  return (int)result;
}

int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
  CHECK_GT(thr->in_rtl, 0);
  StatInc(thr, StatThreadCreate);
  Context *ctx = CTX();
  OnCreatedArgs args = { thr, pc };
  int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args);
  DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
  StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads());
  return tid;
}

void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
  Context *ctx = CTX();
  CHECK_GT(thr->in_rtl, 0);
  uptr stk_addr = 0;
  uptr stk_size = 0;
  uptr tls_addr = 0;
  uptr tls_size = 0;
  GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);

  if (tid) {
    if (stk_addr && stk_size)
      MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);

    if (tls_addr && tls_size) {
      // Check that the thr object is in tls;
      const uptr thr_beg = (uptr)thr;
      const uptr thr_end = (uptr)thr + sizeof(*thr);
      CHECK_GE(thr_beg, tls_addr);
      CHECK_LE(thr_beg, tls_addr + tls_size);
      CHECK_GE(thr_end, tls_addr);
      CHECK_LE(thr_end, tls_addr + tls_size);
      // Since the thr object is huge, skip it.
      MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
      MemoryRangeImitateWrite(thr, /*pc=*/ 2,
          thr_end, tls_addr + tls_size - thr_end);
    }
  }

  ThreadRegistry *tr = ctx->thread_registry;
  OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
  tr->StartThread(tid, os_id, &args);

  tr->Lock();
  thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
  tr->Unlock();
}

void ThreadFinish(ThreadState *thr) {
  CHECK_GT(thr->in_rtl, 0);
  ThreadCheckIgnore(thr);
  StatInc(thr, StatThreadFinish);
  if (thr->stk_addr && thr->stk_size)
    DontNeedShadowFor(thr->stk_addr, thr->stk_size);
  if (thr->tls_addr && thr->tls_size)
    DontNeedShadowFor(thr->tls_addr, thr->tls_size);
  thr->is_alive = false;
  Context *ctx = CTX();
  ctx->thread_registry->FinishThread(thr->tid);
}

static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
  uptr uid = (uptr)arg;
  if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
    tctx->user_id = 0;
    return true;
  }
  return false;
}

int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
  CHECK_GT(thr->in_rtl, 0);
  Context *ctx = CTX();
  int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
  DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
  return res;
}

void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
  CHECK_GT(thr->in_rtl, 0);
  CHECK_GT(tid, 0);
  CHECK_LT(tid, kMaxTid);
  DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
  Context *ctx = CTX();
  ctx->thread_registry->JoinThread(tid, thr);
}

void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
  CHECK_GT(thr->in_rtl, 0);
  CHECK_GT(tid, 0);
  CHECK_LT(tid, kMaxTid);
  Context *ctx = CTX();
  ctx->thread_registry->DetachThread(tid);
}

void ThreadSetName(ThreadState *thr, const char *name) {
  CHECK_GT(thr->in_rtl, 0);
  CTX()->thread_registry->SetThreadName(thr->tid, name);
}

void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
                       uptr size, bool is_write) {
  if (size == 0)
    return;

  u64 *shadow_mem = (u64*)MemToShadow(addr);
  DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n",
      thr->tid, (void*)pc, (void*)addr,
      (int)size, is_write);

#if TSAN_DEBUG
  if (!IsAppMem(addr)) {
    Printf("Access to non app mem %zx\n", addr);
    DCHECK(IsAppMem(addr));
  }
  if (!IsAppMem(addr + size - 1)) {
    Printf("Access to non app mem %zx\n", addr + size - 1);
    DCHECK(IsAppMem(addr + size - 1));
  }
  if (!IsShadowMem((uptr)shadow_mem)) {
    Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
    DCHECK(IsShadowMem((uptr)shadow_mem));
  }
  if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) {
    Printf("Bad shadow addr %p (%zx)\n",
               shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1);
    DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1)));
  }
#endif

  StatInc(thr, StatMopRange);

  if (*shadow_mem == kShadowRodata) {
    // Access to .rodata section, no races here.
    // Measurements show that it can be 10-20% of all memory accesses.
    StatInc(thr, StatMopRangeRodata);
    return;
  }

  FastState fast_state = thr->fast_state;
  if (fast_state.GetIgnoreBit())
    return;

  fast_state.IncrementEpoch();
  thr->fast_state = fast_state;
  TraceAddEvent(thr, fast_state, EventTypeMop, pc);

  bool unaligned = (addr % kShadowCell) != 0;

  // Handle unaligned beginning, if any.
  for (; addr % kShadowCell && size; addr++, size--) {
    int const kAccessSizeLog = 0;
    Shadow cur(fast_state);
    cur.SetWrite(is_write);
    cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
        shadow_mem, cur);
  }
  if (unaligned)
    shadow_mem += kShadowCnt;
  // Handle middle part, if any.
  for (; size >= kShadowCell; addr += kShadowCell, size -= kShadowCell) {
    int const kAccessSizeLog = 3;
    Shadow cur(fast_state);
    cur.SetWrite(is_write);
    cur.SetAddr0AndSizeLog(0, kAccessSizeLog);
    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
        shadow_mem, cur);
    shadow_mem += kShadowCnt;
  }
  // Handle ending, if any.
  for (; size; addr++, size--) {
    int const kAccessSizeLog = 0;
    Shadow cur(fast_state);
    cur.SetWrite(is_write);
    cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
        shadow_mem, cur);
  }
}

}  // namespace __tsan
<commit_msg>tsan: clarify "thread ended with ignores enabled" message<commit_after>//===-- tsan_rtl_thread.cc ------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_placement_new.h"
#include "tsan_rtl.h"
#include "tsan_mman.h"
#include "tsan_platform.h"
#include "tsan_report.h"
#include "tsan_sync.h"

namespace __tsan {

// ThreadContext implementation.

ThreadContext::ThreadContext(int tid)
  : ThreadContextBase(tid)
  , thr()
  , sync()
  , epoch0()
  , epoch1() {
}

#ifndef TSAN_GO
ThreadContext::~ThreadContext() {
}
#endif

void ThreadContext::OnDead() {
  sync.Reset();
}

void ThreadContext::OnJoined(void *arg) {
  ThreadState *caller_thr = static_cast<ThreadState *>(arg);
  AcquireImpl(caller_thr, 0, &sync);
  sync.Reset();
}

struct OnCreatedArgs {
  ThreadState *thr;
  uptr pc;
};

void ThreadContext::OnCreated(void *arg) {
  thr = 0;
  if (tid == 0)
    return;
  OnCreatedArgs *args = static_cast<OnCreatedArgs *>(arg);
  args->thr->fast_state.IncrementEpoch();
  // Can't increment epoch w/o writing to the trace as well.
  TraceAddEvent(args->thr, args->thr->fast_state, EventTypeMop, 0);
  ReleaseImpl(args->thr, 0, &sync);
#ifdef TSAN_GO
  creation_stack.ObtainCurrent(args->thr, args->pc);
#else
  creation_stack_id = CurrentStackId(args->thr, args->pc);
#endif
  if (reuse_count == 0)
    StatInc(args->thr, StatThreadMaxTid);
}

void ThreadContext::OnReset() {
  sync.Reset();
  FlushUnneededShadowMemory(GetThreadTrace(tid), TraceSize() * sizeof(Event));
  //!!! FlushUnneededShadowMemory(GetThreadTraceHeader(tid), sizeof(Trace));
}

struct OnStartedArgs {
  ThreadState *thr;
  uptr stk_addr;
  uptr stk_size;
  uptr tls_addr;
  uptr tls_size;
};

void ThreadContext::OnStarted(void *arg) {
  OnStartedArgs *args = static_cast<OnStartedArgs*>(arg);
  thr = args->thr;
  // RoundUp so that one trace part does not contain events
  // from different threads.
  epoch0 = RoundUp(epoch1 + 1, kTracePartSize);
  epoch1 = (u64)-1;
  new(thr) ThreadState(CTX(), tid, unique_id,
      epoch0, args->stk_addr, args->stk_size, args->tls_addr, args->tls_size);
#ifndef TSAN_GO
  thr->shadow_stack = &ThreadTrace(thr->tid)->shadow_stack[0];
  thr->shadow_stack_pos = thr->shadow_stack;
  thr->shadow_stack_end = thr->shadow_stack + kShadowStackSize;
#else
  // Setup dynamic shadow stack.
  const int kInitStackSize = 8;
  thr->shadow_stack = (uptr*)internal_alloc(MBlockShadowStack,
      kInitStackSize * sizeof(uptr));
  thr->shadow_stack_pos = thr->shadow_stack;
  thr->shadow_stack_end = thr->shadow_stack + kInitStackSize;
#endif
#ifndef TSAN_GO
  AllocatorThreadStart(thr);
#endif
  thr->fast_synch_epoch = epoch0;
  AcquireImpl(thr, 0, &sync);
  thr->fast_state.SetHistorySize(flags()->history_size);
  const uptr trace = (epoch0 / kTracePartSize) % TraceParts();
  Trace *thr_trace = ThreadTrace(thr->tid);
  thr_trace->headers[trace].epoch0 = epoch0;
  StatInc(thr, StatSyncAcquire);
  sync.Reset();
  DPrintf("#%d: ThreadStart epoch=%zu stk_addr=%zx stk_size=%zx "
          "tls_addr=%zx tls_size=%zx\n",
          tid, (uptr)epoch0, args->stk_addr, args->stk_size,
          args->tls_addr, args->tls_size);
  thr->is_alive = true;
}

void ThreadContext::OnFinished() {
  if (!detached) {
    thr->fast_state.IncrementEpoch();
    // Can't increment epoch w/o writing to the trace as well.
    TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
    ReleaseImpl(thr, 0, &sync);
  }
  epoch1 = thr->fast_state.epoch();

#ifndef TSAN_GO
  AllocatorThreadFinish(thr);
#endif
  thr->~ThreadState();
  StatAggregate(CTX()->stat, thr->stat);
  thr = 0;
}

#ifndef TSAN_GO
struct ThreadLeak {
  ThreadContext *tctx;
  int count;
};

static void MaybeReportThreadLeak(ThreadContextBase *tctx_base, void *arg) {
  Vector<ThreadLeak> &leaks = *(Vector<ThreadLeak>*)arg;
  ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
  if (tctx->detached || tctx->status != ThreadStatusFinished)
    return;
  for (uptr i = 0; i < leaks.Size(); i++) {
    if (leaks[i].tctx->creation_stack_id == tctx->creation_stack_id) {
      leaks[i].count++;
      return;
    }
  }
  ThreadLeak leak = {tctx, 1};
  leaks.PushBack(leak);
}
#endif

#ifndef TSAN_GO
static void ReportIgnoresEnabled(ThreadContext *tctx, IgnoreSet *set) {
  if (tctx->tid == 0) {
    Printf("ThreadSanitizer: main thread finished with ignores enabled\n");
  } else {
    Printf("ThreadSanitizer: thread T%d %s finished with ignores enabled,"
      " created at:\n", tctx->tid, tctx->name);
    PrintStack(SymbolizeStackId(tctx->creation_stack_id));
  }
  Printf("  One of the following ignores was not ended"
      " (in order of probability)\n");
  for (uptr i = 0; i < set->Size(); i++) {
    Printf("  Ignore was enabled at:\n");
    PrintStack(SymbolizeStackId(set->At(i)));
  }
  Die();
}

static void ThreadCheckIgnore(ThreadState *thr) {
  if (thr->ignore_reads_and_writes)
    ReportIgnoresEnabled(thr->tctx, &thr->mop_ignore_set);
  if (thr->ignore_sync)
    ReportIgnoresEnabled(thr->tctx, &thr->sync_ignore_set);
}
#else
static void ThreadCheckIgnore(ThreadState *thr) {}
#endif

void ThreadFinalize(ThreadState *thr) {
  CHECK_GT(thr->in_rtl, 0);
  ThreadCheckIgnore(thr);
#ifndef TSAN_GO
  if (!flags()->report_thread_leaks)
    return;
  ThreadRegistryLock l(CTX()->thread_registry);
  Vector<ThreadLeak> leaks(MBlockScopedBuf);
  CTX()->thread_registry->RunCallbackForEachThreadLocked(
      MaybeReportThreadLeak, &leaks);
  for (uptr i = 0; i < leaks.Size(); i++) {
    ScopedReport rep(ReportTypeThreadLeak);
    rep.AddThread(leaks[i].tctx);
    rep.SetCount(leaks[i].count);
    OutputReport(CTX(), rep);
  }
#endif
}

int ThreadCount(ThreadState *thr) {
  CHECK_GT(thr->in_rtl, 0);
  Context *ctx = CTX();
  uptr result;
  ctx->thread_registry->GetNumberOfThreads(0, 0, &result);
  return (int)result;
}

int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
  CHECK_GT(thr->in_rtl, 0);
  StatInc(thr, StatThreadCreate);
  Context *ctx = CTX();
  OnCreatedArgs args = { thr, pc };
  int tid = ctx->thread_registry->CreateThread(uid, detached, thr->tid, &args);
  DPrintf("#%d: ThreadCreate tid=%d uid=%zu\n", thr->tid, tid, uid);
  StatSet(thr, StatThreadMaxAlive, ctx->thread_registry->GetMaxAliveThreads());
  return tid;
}

void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
  Context *ctx = CTX();
  CHECK_GT(thr->in_rtl, 0);
  uptr stk_addr = 0;
  uptr stk_size = 0;
  uptr tls_addr = 0;
  uptr tls_size = 0;
  GetThreadStackAndTls(tid == 0, &stk_addr, &stk_size, &tls_addr, &tls_size);

  if (tid) {
    if (stk_addr && stk_size)
      MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);

    if (tls_addr && tls_size) {
      // Check that the thr object is in tls;
      const uptr thr_beg = (uptr)thr;
      const uptr thr_end = (uptr)thr + sizeof(*thr);
      CHECK_GE(thr_beg, tls_addr);
      CHECK_LE(thr_beg, tls_addr + tls_size);
      CHECK_GE(thr_end, tls_addr);
      CHECK_LE(thr_end, tls_addr + tls_size);
      // Since the thr object is huge, skip it.
      MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
      MemoryRangeImitateWrite(thr, /*pc=*/ 2,
          thr_end, tls_addr + tls_size - thr_end);
    }
  }

  ThreadRegistry *tr = ctx->thread_registry;
  OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
  tr->StartThread(tid, os_id, &args);

  tr->Lock();
  thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
  tr->Unlock();
}

void ThreadFinish(ThreadState *thr) {
  CHECK_GT(thr->in_rtl, 0);
  ThreadCheckIgnore(thr);
  StatInc(thr, StatThreadFinish);
  if (thr->stk_addr && thr->stk_size)
    DontNeedShadowFor(thr->stk_addr, thr->stk_size);
  if (thr->tls_addr && thr->tls_size)
    DontNeedShadowFor(thr->tls_addr, thr->tls_size);
  thr->is_alive = false;
  Context *ctx = CTX();
  ctx->thread_registry->FinishThread(thr->tid);
}

static bool FindThreadByUid(ThreadContextBase *tctx, void *arg) {
  uptr uid = (uptr)arg;
  if (tctx->user_id == uid && tctx->status != ThreadStatusInvalid) {
    tctx->user_id = 0;
    return true;
  }
  return false;
}

int ThreadTid(ThreadState *thr, uptr pc, uptr uid) {
  CHECK_GT(thr->in_rtl, 0);
  Context *ctx = CTX();
  int res = ctx->thread_registry->FindThread(FindThreadByUid, (void*)uid);
  DPrintf("#%d: ThreadTid uid=%zu tid=%d\n", thr->tid, uid, res);
  return res;
}

void ThreadJoin(ThreadState *thr, uptr pc, int tid) {
  CHECK_GT(thr->in_rtl, 0);
  CHECK_GT(tid, 0);
  CHECK_LT(tid, kMaxTid);
  DPrintf("#%d: ThreadJoin tid=%d\n", thr->tid, tid);
  Context *ctx = CTX();
  ctx->thread_registry->JoinThread(tid, thr);
}

void ThreadDetach(ThreadState *thr, uptr pc, int tid) {
  CHECK_GT(thr->in_rtl, 0);
  CHECK_GT(tid, 0);
  CHECK_LT(tid, kMaxTid);
  Context *ctx = CTX();
  ctx->thread_registry->DetachThread(tid);
}

void ThreadSetName(ThreadState *thr, const char *name) {
  CHECK_GT(thr->in_rtl, 0);
  CTX()->thread_registry->SetThreadName(thr->tid, name);
}

void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
                       uptr size, bool is_write) {
  if (size == 0)
    return;

  u64 *shadow_mem = (u64*)MemToShadow(addr);
  DPrintf2("#%d: MemoryAccessRange: @%p %p size=%d is_write=%d\n",
      thr->tid, (void*)pc, (void*)addr,
      (int)size, is_write);

#if TSAN_DEBUG
  if (!IsAppMem(addr)) {
    Printf("Access to non app mem %zx\n", addr);
    DCHECK(IsAppMem(addr));
  }
  if (!IsAppMem(addr + size - 1)) {
    Printf("Access to non app mem %zx\n", addr + size - 1);
    DCHECK(IsAppMem(addr + size - 1));
  }
  if (!IsShadowMem((uptr)shadow_mem)) {
    Printf("Bad shadow addr %p (%zx)\n", shadow_mem, addr);
    DCHECK(IsShadowMem((uptr)shadow_mem));
  }
  if (!IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1))) {
    Printf("Bad shadow addr %p (%zx)\n",
               shadow_mem + size * kShadowCnt / 8 - 1, addr + size - 1);
    DCHECK(IsShadowMem((uptr)(shadow_mem + size * kShadowCnt / 8 - 1)));
  }
#endif

  StatInc(thr, StatMopRange);

  if (*shadow_mem == kShadowRodata) {
    // Access to .rodata section, no races here.
    // Measurements show that it can be 10-20% of all memory accesses.
    StatInc(thr, StatMopRangeRodata);
    return;
  }

  FastState fast_state = thr->fast_state;
  if (fast_state.GetIgnoreBit())
    return;

  fast_state.IncrementEpoch();
  thr->fast_state = fast_state;
  TraceAddEvent(thr, fast_state, EventTypeMop, pc);

  bool unaligned = (addr % kShadowCell) != 0;

  // Handle unaligned beginning, if any.
  for (; addr % kShadowCell && size; addr++, size--) {
    int const kAccessSizeLog = 0;
    Shadow cur(fast_state);
    cur.SetWrite(is_write);
    cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
        shadow_mem, cur);
  }
  if (unaligned)
    shadow_mem += kShadowCnt;
  // Handle middle part, if any.
  for (; size >= kShadowCell; addr += kShadowCell, size -= kShadowCell) {
    int const kAccessSizeLog = 3;
    Shadow cur(fast_state);
    cur.SetWrite(is_write);
    cur.SetAddr0AndSizeLog(0, kAccessSizeLog);
    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
        shadow_mem, cur);
    shadow_mem += kShadowCnt;
  }
  // Handle ending, if any.
  for (; size; addr++, size--) {
    int const kAccessSizeLog = 0;
    Shadow cur(fast_state);
    cur.SetWrite(is_write);
    cur.SetAddr0AndSizeLog(addr & (kShadowCell - 1), kAccessSizeLog);
    MemoryAccessImpl(thr, addr, kAccessSizeLog, is_write, false,
        shadow_mem, cur);
  }
}

}  // namespace __tsan
<|endoftext|>