<commit_before>#include <GarrysMod/Lua/Interface.h>
#include <GarrysMod/Lua/LuaInterface.h>
#include <SymbolFinder.hpp>
#include <MologieDetours/detours.h>
#include <stdexcept>
#include <string>
#include <stdint.h>
#include <stdio.h>
#include <sha1.h>

#if defined _WIN32

#define snprintf _snprintf

#define FASTCALL __fastcall
#define THISCALL __thiscall

#define SERVER_BINARY "server.dll"

#define ADDORUPDATEFILE_SYM reinterpret_cast<const uint8_t *>( "\x55\x8B\xEC\x83\xEC\x18\x53\x56\x8B\x75\x08\x83\xC6\x04\x83\x7E" )
#define ADDORUPDATEFILE_SYMLEN 16

#elif defined __linux || defined __APPLE__

#define CDECL __attribute__((cdecl))

#if defined __linux

#define SERVER_BINARY "garrysmod/bin/server_srv.so"

#define SYMBOL_PREFIX "@"

#else

#define SERVER_BINARY "garrysmod/bin/server.dylib"

#define SYMBOL_PREFIX "@_"

#endif

#define ADDORUPDATEFILE_SYM reinterpret_cast<const uint8_t *>( SYMBOL_PREFIX "_ZN12GModDataPack15AddOrUpdateFileEP7LuaFileb" )
#define ADDORUPDATEFILE_SYMLEN 0

#endif

GarrysMod::Lua::ILuaInterface *lua = NULL;

class GModDataPack;

struct LuaFile
{
	uint32_t skip;
	const char *path;
};

#if defined _WIN32

typedef void ( THISCALL *AddOrUpdateFile_t ) ( GModDataPack *self, LuaFile *file, bool force );

#elif defined __linux || defined __APPLE__

typedef void ( CDECL *AddOrUpdateFile_t ) ( GModDataPack *self, LuaFile *file, bool force );

#endif

AddOrUpdateFile_t AddOrUpdateFile = NULL;
MologieDetours::Detour<AddOrUpdateFile_t> *AddOrUpdateFile_d = NULL;

#if defined _WIN32

void FASTCALL AddOrUpdateFile_h( GModDataPack *self, void *, LuaFile *file, bool b )

#elif defined __linux || defined __APPLE__

void CDECL AddOrUpdateFile_h( GModDataPack *self, LuaFile *file, bool b )

#endif

{
	lua->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB );
	if( lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
	{
		lua->GetField( -1, "hook" );
		if( lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
		{
			lua->GetField( -1, "Run" );
			if( lua->IsType( -1, GarrysMod::Lua::Type::FUNCTION ) )
			{
				lua->PushString( "AddOrUpdateCSLuaFile" );

				lua->PushString( file->path );
				lua->PushBool( b );

				if( lua->PCall( 3, 1, 0 ) != 0 )
				{
					lua->Msg( "[luapack_internal] %s\n", lua->GetString( ) );
					lua->Pop( 3 );
					return AddOrUpdateFile( self, file, b );
				}

				if( lua->IsType( -1, GarrysMod::Lua::Type::BOOL ) && lua->GetBool( ) )
				{
					lua->Pop( 3 );
					return;
				}

				lua->Pop( 1 );
			}
			else
			{
				lua->Pop( 1 );
			}
		}

		lua->Pop( 1 );
	}

	lua->Pop( 1 );
	return AddOrUpdateFile( self, file, b );
}

#define HASHER_METATABLE "SHA1"
#define HASHER_TYPE 31

#define THROW_ERROR( error ) ( LUA->ThrowError( error ), 0 )
#define LUA_ERROR( ) THROW_ERROR( LUA->GetString( ) )

#define GET_USERDATA( index ) reinterpret_cast<GarrysMod::Lua::UserData *>( LUA->GetUserdata( index ) )
#define GET_HASHER( index ) reinterpret_cast<sha1_context *>( GET_USERDATA( index )->data )
#define VALIDATE_HASHER( hasher ) if( hasher == 0 ) return THROW_ERROR( HASHER_METATABLE " object is not valid" )

LUA_FUNCTION_STATIC( hasher__new )
{
	try
	{
		sha1_context *context = new sha1_context;
		sha1_starts( context );

		void *luadata = LUA->NewUserdata( sizeof( GarrysMod::Lua::UserData ) );
		GarrysMod::Lua::UserData *userdata = reinterpret_cast<GarrysMod::Lua::UserData *>( luadata );
		userdata->data = context;
		userdata->type = HASHER_TYPE;

		LUA->CreateMetaTableType( HASHER_METATABLE, HASHER_TYPE );
		LUA->SetMetaTable( -2 );

		return 1;
	}
	catch( std::exception &e )
	{
		LUA->PushString( e.what( ) );
	}

	return LUA_ERROR( );
}

LUA_FUNCTION_STATIC( hasher__gc )
{
	LUA->CheckType( 1, HASHER_TYPE );

	GarrysMod::Lua::UserData *userdata = GET_USERDATA( 1 );
	sha1_context *hasher = reinterpret_cast<sha1_context *>( userdata->data );
	VALIDATE_HASHER( hasher );

	userdata->data = 0;

	delete hasher;
	return 0;
}

LUA_FUNCTION_STATIC( hasher_update )
{
	LUA->CheckType( 1, HASHER_TYPE );
	LUA->CheckType( 2, GarrysMod::Lua::Type::STRING );

	sha1_context *hasher = GET_HASHER( 1 );
	VALIDATE_HASHER( hasher );

	uint32_t len = 0;
	const uint8_t *data = reinterpret_cast<const uint8_t *>( LUA->GetString( 2, &len ) );

	sha1_update( hasher, data, len );

	return 0;
}

LUA_FUNCTION_STATIC( hasher_final )
{
	LUA->CheckType( 1, HASHER_TYPE );

	sha1_context *hasher = GET_HASHER( 1 );
	VALIDATE_HASHER( hasher );

	uint8_t digest[20];
	sha1_finish( hasher, digest );

	LUA->PushString( reinterpret_cast<const char *>( digest ), sizeof( digest ) );
	return 1;
}

static void SubstituteChar( std::string &path, char part, char sub )
{
	size_t pos = path.find( part );
	while( pos != path.npos )
	{
		path.erase( pos, 1 );
		path.insert( pos, 1, sub );
		pos = path.find( part, pos + 1 );
	}
}

static void RemovePart( std::string &path, const char *part )
{
	size_t len = strlen( part ), pos = path.find( part );
	while( pos != path.npos )
	{
		path.erase( pos, len );
		pos = path.find( part, pos );
	}
}

static bool HasWhitelistedExtension( const std::string &path )
{
	size_t extstart = path.find( '.' );
	if( extstart != path.npos )
	{
		size_t lastslash = path.find( '/' );
		if( lastslash != path.npos && lastslash > extstart )
			return false;

		std::string ext = path.substr( extstart + 1 );
		return ext == "txt" || ext == "dat" || ext == "lua";
	}

	return false;
}

static bool Rename( const char *f, const char *t )
{
	std::string from = "garrysmod/";
	from += f;
	if( !HasWhitelistedExtension( from ) )
		return false;

	std::string to = "garrysmod/";
	to += t;
	if( !HasWhitelistedExtension( to ) )
		return false;

	SubstituteChar( from, '\\', '/' );
	RemovePart( from, "../" );
	RemovePart( from, "./" );

	SubstituteChar( to, '\\', '/' );
	RemovePart( to, "../" );
	RemovePart( to, "./" );

	return rename( from.c_str( ), to.c_str( ) ) == 0;
}

LUA_FUNCTION_STATIC( luapack_rename )
{
	LUA->CheckType( 1, GarrysMod::Lua::Type::STRING );
	LUA->CheckType( 2, GarrysMod::Lua::Type::STRING );

	LUA->PushBool( Rename( LUA->GetString( 1 ), LUA->GetString( 2 ) ) );
	return 1;
}

GMOD_MODULE_OPEN( )
{
	lua = reinterpret_cast<GarrysMod::Lua::ILuaInterface *>( LUA );

	try
	{
		lua->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB );

		lua->GetField( -1, "luapack" );
		if( !lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
			throw std::runtime_error( "luapack table not found" );

		lua->PushCFunction( luapack_rename );
		lua->SetField( -2, "Rename" );

		lua->PushCFunction( hasher__new );
		lua->SetField( -2, HASHER_METATABLE );

		LUA->CreateMetaTableType( HASHER_METATABLE, HASHER_TYPE );

		LUA->Push( -1 );
		LUA->SetField( -2, "__index" );

		LUA->PushCFunction( hasher__gc );
		LUA->SetField( -2, "__gc" );

		LUA->PushCFunction( hasher_update );
		LUA->SetField( -2, "Update" );

		LUA->PushCFunction( hasher_final );
		LUA->SetField( -2, "Final" );

		SymbolFinder symfinder;

		AddOrUpdateFile = reinterpret_cast<AddOrUpdateFile_t>( symfinder.ResolveOnBinary( SERVER_BINARY, ADDORUPDATEFILE_SYM, ADDORUPDATEFILE_SYMLEN ) );
		if( AddOrUpdateFile == NULL )
			throw std::runtime_error( "GModDataPack::AddOrUpdateFile detour failed" );

		AddOrUpdateFile_d = new MologieDetours::Detour<AddOrUpdateFile_t>( AddOrUpdateFile, reinterpret_cast<AddOrUpdateFile_t>( AddOrUpdateFile_h ) );

		AddOrUpdateFile = AddOrUpdateFile_d->GetOriginalFunction( );

		lua->Msg( "[luapack_internal] GModDataPack::AddOrUpdateFile detoured.\n" );

		return 0;
	}
	catch( std::exception &e )
	{
		LUA->PushString( e.what( ) );
	}

	return LUA_ERROR( );
}

GMOD_MODULE_CLOSE( )
{
	delete AddOrUpdateFile_d;
	return 0;
}<commit_msg>Wrong std::string find function used. Replaced with correct one.<commit_after>#include <GarrysMod/Lua/Interface.h>
#include <GarrysMod/Lua/LuaInterface.h>
#include <SymbolFinder.hpp>
#include <MologieDetours/detours.h>
#include <stdexcept>
#include <string>
#include <stdint.h>
#include <stdio.h>
#include <sha1.h>

#if defined _WIN32

#define snprintf _snprintf

#define FASTCALL __fastcall
#define THISCALL __thiscall

#define SERVER_BINARY "server.dll"

#define ADDORUPDATEFILE_SYM reinterpret_cast<const uint8_t *>( "\x55\x8B\xEC\x83\xEC\x18\x53\x56\x8B\x75\x08\x83\xC6\x04\x83\x7E" )
#define ADDORUPDATEFILE_SYMLEN 16

#elif defined __linux || defined __APPLE__

#define CDECL __attribute__((cdecl))

#if defined __linux

#define SERVER_BINARY "garrysmod/bin/server_srv.so"

#define SYMBOL_PREFIX "@"

#else

#define SERVER_BINARY "garrysmod/bin/server.dylib"

#define SYMBOL_PREFIX "@_"

#endif

#define ADDORUPDATEFILE_SYM reinterpret_cast<const uint8_t *>( SYMBOL_PREFIX "_ZN12GModDataPack15AddOrUpdateFileEP7LuaFileb" )
#define ADDORUPDATEFILE_SYMLEN 0

#endif

GarrysMod::Lua::ILuaInterface *lua = NULL;

class GModDataPack;

struct LuaFile
{
	uint32_t skip;
	const char *path;
};

#if defined _WIN32

typedef void ( THISCALL *AddOrUpdateFile_t ) ( GModDataPack *self, LuaFile *file, bool force );

#elif defined __linux || defined __APPLE__

typedef void ( CDECL *AddOrUpdateFile_t ) ( GModDataPack *self, LuaFile *file, bool force );

#endif

AddOrUpdateFile_t AddOrUpdateFile = NULL;
MologieDetours::Detour<AddOrUpdateFile_t> *AddOrUpdateFile_d = NULL;

#if defined _WIN32

void FASTCALL AddOrUpdateFile_h( GModDataPack *self, void *, LuaFile *file, bool b )

#elif defined __linux || defined __APPLE__

void CDECL AddOrUpdateFile_h( GModDataPack *self, LuaFile *file, bool b )

#endif

{
	lua->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB );
	if( lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
	{
		lua->GetField( -1, "hook" );
		if( lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
		{
			lua->GetField( -1, "Run" );
			if( lua->IsType( -1, GarrysMod::Lua::Type::FUNCTION ) )
			{
				lua->PushString( "AddOrUpdateCSLuaFile" );

				lua->PushString( file->path );
				lua->PushBool( b );

				if( lua->PCall( 3, 1, 0 ) != 0 )
				{
					lua->Msg( "[luapack_internal] %s\n", lua->GetString( ) );
					lua->Pop( 3 );
					return AddOrUpdateFile( self, file, b );
				}

				if( lua->IsType( -1, GarrysMod::Lua::Type::BOOL ) && lua->GetBool( ) )
				{
					lua->Pop( 3 );
					return;
				}

				lua->Pop( 1 );
			}
			else
			{
				lua->Pop( 1 );
			}
		}

		lua->Pop( 1 );
	}

	lua->Pop( 1 );
	return AddOrUpdateFile( self, file, b );
}

#define HASHER_METATABLE "SHA1"
#define HASHER_TYPE 31

#define THROW_ERROR( error ) ( LUA->ThrowError( error ), 0 )
#define LUA_ERROR( ) THROW_ERROR( LUA->GetString( ) )

#define GET_USERDATA( index ) reinterpret_cast<GarrysMod::Lua::UserData *>( LUA->GetUserdata( index ) )
#define GET_HASHER( index ) reinterpret_cast<sha1_context *>( GET_USERDATA( index )->data )
#define VALIDATE_HASHER( hasher ) if( hasher == 0 ) return THROW_ERROR( HASHER_METATABLE " object is not valid" )

LUA_FUNCTION_STATIC( hasher__new )
{
	try
	{
		sha1_context *context = new sha1_context;
		sha1_starts( context );

		void *luadata = LUA->NewUserdata( sizeof( GarrysMod::Lua::UserData ) );
		GarrysMod::Lua::UserData *userdata = reinterpret_cast<GarrysMod::Lua::UserData *>( luadata );
		userdata->data = context;
		userdata->type = HASHER_TYPE;

		LUA->CreateMetaTableType( HASHER_METATABLE, HASHER_TYPE );
		LUA->SetMetaTable( -2 );

		return 1;
	}
	catch( std::exception &e )
	{
		LUA->PushString( e.what( ) );
	}

	return LUA_ERROR( );
}

LUA_FUNCTION_STATIC( hasher__gc )
{
	LUA->CheckType( 1, HASHER_TYPE );

	GarrysMod::Lua::UserData *userdata = GET_USERDATA( 1 );
	sha1_context *hasher = reinterpret_cast<sha1_context *>( userdata->data );
	VALIDATE_HASHER( hasher );

	userdata->data = 0;

	delete hasher;
	return 0;
}

LUA_FUNCTION_STATIC( hasher_update )
{
	LUA->CheckType( 1, HASHER_TYPE );
	LUA->CheckType( 2, GarrysMod::Lua::Type::STRING );

	sha1_context *hasher = GET_HASHER( 1 );
	VALIDATE_HASHER( hasher );

	uint32_t len = 0;
	const uint8_t *data = reinterpret_cast<const uint8_t *>( LUA->GetString( 2, &len ) );

	sha1_update( hasher, data, len );

	return 0;
}

LUA_FUNCTION_STATIC( hasher_final )
{
	LUA->CheckType( 1, HASHER_TYPE );

	sha1_context *hasher = GET_HASHER( 1 );
	VALIDATE_HASHER( hasher );

	uint8_t digest[20];
	sha1_finish( hasher, digest );

	LUA->PushString( reinterpret_cast<const char *>( digest ), sizeof( digest ) );
	return 1;
}

static void SubstituteChar( std::string &path, char part, char sub )
{
	size_t pos = path.find( part );
	while( pos != path.npos )
	{
		path.erase( pos, 1 );
		path.insert( pos, 1, sub );
		pos = path.find( part, pos + 1 );
	}
}

static void RemovePart( std::string &path, const char *part )
{
	size_t len = strlen( part ), pos = path.find( part );
	while( pos != path.npos )
	{
		path.erase( pos, len );
		pos = path.find( part, pos );
	}
}

static bool HasWhitelistedExtension( const std::string &path )
{
	size_t extstart = path.rfind( '.' );
	if( extstart != path.npos )
	{
		size_t lastslash = path.rfind( '/' );
		if( lastslash != path.npos && lastslash > extstart )
			return false;

		std::string ext = path.substr( extstart + 1 );
		return ext == "txt" || ext == "dat" || ext == "lua";
	}

	return false;
}

static bool Rename( const char *f, const char *t )
{
	std::string from = "garrysmod/";
	from += f;
	if( !HasWhitelistedExtension( from ) )
		return false;

	std::string to = "garrysmod/";
	to += t;
	if( !HasWhitelistedExtension( to ) )
		return false;

	SubstituteChar( from, '\\', '/' );
	RemovePart( from, "../" );
	RemovePart( from, "./" );

	SubstituteChar( to, '\\', '/' );
	RemovePart( to, "../" );
	RemovePart( to, "./" );

	return rename( from.c_str( ), to.c_str( ) ) == 0;
}

LUA_FUNCTION_STATIC( luapack_rename )
{
	LUA->CheckType( 1, GarrysMod::Lua::Type::STRING );
	LUA->CheckType( 2, GarrysMod::Lua::Type::STRING );

	LUA->PushBool( Rename( LUA->GetString( 1 ), LUA->GetString( 2 ) ) );
	return 1;
}

GMOD_MODULE_OPEN( )
{
	lua = reinterpret_cast<GarrysMod::Lua::ILuaInterface *>( LUA );

	try
	{
		lua->PushSpecial( GarrysMod::Lua::SPECIAL_GLOB );

		lua->GetField( -1, "luapack" );
		if( !lua->IsType( -1, GarrysMod::Lua::Type::TABLE ) )
			throw std::runtime_error( "luapack table not found" );

		lua->PushCFunction( luapack_rename );
		lua->SetField( -2, "Rename" );

		lua->PushCFunction( hasher__new );
		lua->SetField( -2, HASHER_METATABLE );

		LUA->CreateMetaTableType( HASHER_METATABLE, HASHER_TYPE );

		LUA->Push( -1 );
		LUA->SetField( -2, "__index" );

		LUA->PushCFunction( hasher__gc );
		LUA->SetField( -2, "__gc" );

		LUA->PushCFunction( hasher_update );
		LUA->SetField( -2, "Update" );

		LUA->PushCFunction( hasher_final );
		LUA->SetField( -2, "Final" );

		SymbolFinder symfinder;

		AddOrUpdateFile = reinterpret_cast<AddOrUpdateFile_t>( symfinder.ResolveOnBinary( SERVER_BINARY, ADDORUPDATEFILE_SYM, ADDORUPDATEFILE_SYMLEN ) );
		if( AddOrUpdateFile == NULL )
			throw std::runtime_error( "GModDataPack::AddOrUpdateFile detour failed" );

		AddOrUpdateFile_d = new MologieDetours::Detour<AddOrUpdateFile_t>( AddOrUpdateFile, reinterpret_cast<AddOrUpdateFile_t>( AddOrUpdateFile_h ) );

		AddOrUpdateFile = AddOrUpdateFile_d->GetOriginalFunction( );

		lua->Msg( "[luapack_internal] GModDataPack::AddOrUpdateFile detoured.\n" );

		return 0;
	}
	catch( std::exception &e )
	{
		LUA->PushString( e.what( ) );
	}

	return LUA_ERROR( );
}

GMOD_MODULE_CLOSE( )
{
	delete AddOrUpdateFile_d;
	return 0;
}<|endoftext|>


<commit_before>#include "verify.hpp"
#include <iostream>
#include "sta_util.hpp"
#include "util.hpp"

#define RELATIVE_EPSILON 1.e-5
#define ABSOLUTE_EPSILON 1.e-13

using std::cout;
using std::endl;

using tatum::NodeId;
using tatum::DomainId;
using tatum::LevelId;
using tatum::TimingGraph;
using tatum::NodeType;

bool verify_arr_tag(float arr_time, float vpr_arr_time, NodeId node_id, DomainId domain, const std::set<NodeId>& clock_gen_fanout_nodes, std::streamsize num_width);

bool verify_req_tag(float req_time, float vpr_req_time, NodeId node_id, DomainId domain, const std::set<NodeId>& const_gen_fanout_nodes, std::streamsize num_width);

int verify_analyzer(const TimingGraph& tg, const tatum::SetupTimingAnalyzer& analyzer, const VprArrReqTimes& expected_arr_req_times, const std::set<NodeId>& const_gen_fanout_nodes, const std::set<NodeId>& clock_gen_fanout_nodes) {
    //expected_arr_req_times.print();

    //std::cout << "Verifying Calculated Timing Against VPR" << std::endl;
    std::ios_base::fmtflags saved_flags = std::cout.flags();
    std::streamsize prec = std::cout.precision();
    std::streamsize width = std::cout.width();

    std::streamsize num_width = 10;
    std::cout.precision(3);
    std::cout << std::scientific;
    std::cout << std::setw(10);
    int arr_reqs_verified = 0;
    bool error = false;

    /*
     * Check from VPR to Tatum results
     */
    for(const DomainId domain : expected_arr_req_times.clocks()) {

        int arrival_nodes_checked = 0; //Count number of nodes checked
        int required_nodes_checked = 0; //Count number of nodes checked

        //Arrival check by level
        for(const LevelId ilevel : tg.levels()){
            //std::cout << "LEVEL " << ilevel << std::endl;
            for(const NodeId node_id : tg.level_nodes(ilevel)) {
                //std::cout << "Verifying node: " << node_id << " Launch: " << src_domain << " Capture: " << sink_domain << std::endl;
                const auto& node_data_tags = analyzer.get_setup_data_tags(node_id);
                float vpr_arr_time = expected_arr_req_times.get_arr_time(domain, node_id);

                //Check arrival
                auto data_tag_iter = node_data_tags.find_tag_by_clock_domain(domain);
                if(data_tag_iter == node_data_tags.end()) {
                    //Did not find a matching data tag

                    //See if there is an associated clock tag.
                    //Note that VPR doesn't handle seperate clock tags, but we place
                    //clock arrivals on FF_SINK and FF_SOURCE nodes from the clock network,
                    //so even if such a clock tag exists we don't want to compare it to VPR
                    if(tg.node_type(node_id) != NodeType::FF_SINK && tg.node_type(node_id) != NodeType::FF_SOURCE) {
                        const auto& node_clock_tags = analyzer.get_setup_clock_tags(node_id);
                        auto clock_tag_iter = node_clock_tags.find_tag_by_clock_domain(domain);
                        if(clock_tag_iter != node_clock_tags.end()) {
                            error |= verify_arr_tag(clock_tag_iter->arr_time().value(), vpr_arr_time, node_id, domain, clock_gen_fanout_nodes, num_width);

                        } else if(!isnan(vpr_arr_time)) {
                            error = true;
                            std::cout << "Node: " << node_id << " Clk: " << domain << std::endl;
                            std::cout << "\tERROR Found no arrival-time tag, but VPR arrival time was ";
                            std::cout << std::setw(num_width) << vpr_arr_time << " (expected NAN)" << std::endl;
                        } else {
                            TATUM_ASSERT(isnan(vpr_arr_time));
                        }
                    }
                } else {
                    error |= verify_arr_tag(data_tag_iter->arr_time().value(), vpr_arr_time, node_id, domain, clock_gen_fanout_nodes, num_width);
                }
                arr_reqs_verified ++;
                arrival_nodes_checked++;
            }
        }
        //Since we walk our version of the graph make sure we see the same number of nodes as VPR
        TATUM_ASSERT(arrival_nodes_checked == (int) expected_arr_req_times.get_num_nodes());

        //Required check by level (in reverse)
        for(const LevelId level_id : tg.levels()) {
            for(const NodeId node_id : tg.level_nodes(level_id)) {

                const auto& node_data_tags = analyzer.get_setup_data_tags(node_id);
                float vpr_req_time = expected_arr_req_times.get_req_time(domain, node_id);
                //Check Required time
                auto data_tag_iter = node_data_tags.find_tag_by_clock_domain(domain);
                if(data_tag_iter == node_data_tags.end()) {
                    //See if there is an associated clock tag.
                    //Note that VPR doesn't handle seperate clock tags, but we place
                    //clock arrivals on FF_SINK and FF_SOURCE nodes from the clock network,
                    //so even if such a clock tag exists we don't want to compare it to VPR
                    if(tg.node_type(node_id) != NodeType::FF_SINK && tg.node_type(node_id) != NodeType::FF_SOURCE) {
                        const auto& node_clock_tags = analyzer.get_setup_clock_tags(node_id);
                        auto clock_tag_iter = node_clock_tags.find_tag_by_clock_domain(domain);
                        if(clock_tag_iter != node_clock_tags.end()) {
                            error |= verify_req_tag(clock_tag_iter->req_time().value(), vpr_req_time, node_id, domain, const_gen_fanout_nodes, num_width);
                        } else if(!isnan(vpr_req_time)) {
                            error = true;
                            std::cout << "Node: " << node_id << " Clk: " << domain  << std::endl;
                            std::cout << "\tERROR Found no required-time tag, but VPR required time was " << std::setw(num_width);
                            std::cout << vpr_req_time << " (expected NAN)" << std::endl;
                        }
                    }
                } else {
                    error |= verify_req_tag(data_tag_iter->req_time().value(), vpr_req_time, node_id, domain, const_gen_fanout_nodes, num_width);

                }
                arr_reqs_verified++;
                required_nodes_checked++;
            }
        }
        TATUM_ASSERT(required_nodes_checked == (int) expected_arr_req_times.get_num_nodes());
    }

    /*
     * Check from Tatum to VPR
     */

    //Check by level
//#ifdef CHECK_TATUM_TO_VPR_DIFFERENCES
#if 0
    for(int ilevel = 0; ilevel <tg.num_levels(); ilevel++) {
        //std::cout << "LEVEL " << ilevel << std::endl;
        for(NodeId node_id : tg.level(ilevel)) {
            for(const TimingTag& data_tag : analyzer.data_tags(node_id)) {
                //Arrival
                float arr_time = data_tag.arr_time().value();
                float vpr_arr_time = expected_arr_req_times.get_arr_time(data_tag.clock_domain(), node_id);
                verify_arr_tag(arr_time, vpr_arr_time, node_id, data_tag.clock_domain(), clock_gen_fanout_nodes, num_width);

                //Required
                float req_time = data_tag.req_time().value();
                float vpr_req_time = expected_arr_req_times.get_req_time(data_tag.clock_domain(), node_id);
                verify_req_tag(req_time, vpr_req_time, node_id, data_tag.clock_domain(), const_gen_fanout_nodes, num_width);
            }
        }
    }
#endif

    if(error) {
        std::cout << "Timing verification FAILED!" << std::endl;
        exit(1);
    } else {
        //std::cout << "Timing verification SUCCEEDED" << std::endl;
    }

    std::cout.flags(saved_flags);
    std::cout.precision(prec);
    std::cout.width(width);
    return arr_reqs_verified;
}

bool verify_arr_tag(float arr_time, float vpr_arr_time, NodeId node_id, DomainId domain, const std::set<NodeId>& clock_gen_fanout_nodes, std::streamsize num_width) {
    bool error = false;
    float arr_abs_err = fabs(arr_time - vpr_arr_time);
    float arr_rel_err = relative_error(arr_time, vpr_arr_time);
    if(isnan(arr_time) && isnan(arr_time) != isnan(vpr_arr_time)) {
        error = true;
        cout << "Node: " << node_id << " Clk: " << domain;
        cout << " Calc_Arr: " << std::setw(num_width) << arr_time;
        cout << " VPR_Arr: " << std::setw(num_width) << vpr_arr_time << endl;
        cout << "\tERROR Calculated arrival time was nan and didn't match VPR." << endl;
    } else if (!isnan(arr_time) && isnan(vpr_arr_time)) {
        if(clock_gen_fanout_nodes.count(node_id)) {
            //Pass, clock gen fanout can be NAN in VPR but have a value here,
            //since (unlike VPR) we explictly track clock arrivals as tags
        } else {
            error = true;
            cout << "Node: " << node_id << " Clk: " << domain;
            cout << " Calc_Arr: " << std::setw(num_width) << arr_time;
            cout << " VPR_Arr: " << std::setw(num_width) << vpr_arr_time << endl;
            cout << "\tERROR Calculated arrival time was not nan but VPR expected nan." << endl;
        }
    } else if (isnan(arr_time) && isnan(vpr_arr_time)) {
        //They agree, pass
    } else if(arr_rel_err > RELATIVE_EPSILON && arr_abs_err > ABSOLUTE_EPSILON) {
        error = true;
        cout << "Node: " << node_id << " Clk: " << domain;
        cout << " Calc_Arr: " << std::setw(num_width) << arr_time;
        cout << " VPR_Arr: " << std::setw(num_width) << vpr_arr_time << endl;
        cout << "\tERROR arrival time abs, rel errs: " << std::setw(num_width) << arr_abs_err;
        cout << ", " << std::setw(num_width) << arr_rel_err << endl;
    } else {
        TATUM_ASSERT(!isnan(arr_rel_err) && !isnan(arr_abs_err));
        TATUM_ASSERT(arr_rel_err < RELATIVE_EPSILON || arr_abs_err < ABSOLUTE_EPSILON);
    }
    return error;
}

bool verify_req_tag(float req_time, float vpr_req_time, NodeId node_id, DomainId domain, const std::set<NodeId>& const_gen_fanout_nodes, std::streamsize num_width) {
    bool error = false;
    float req_abs_err = fabs(req_time - vpr_req_time);
    float req_rel_err = relative_error(req_time, vpr_req_time);
    if(isnan(req_time) && isnan(req_time) != isnan(vpr_req_time)) {
        error = true;
        cout << "Node: " << node_id << " Clk: " << domain;
        cout << " Calc_Req: " << std::setw(num_width) << req_time;
        cout << " VPR_Req: " << std::setw(num_width) << vpr_req_time << endl;
        cout << "\tERROR Calculated required time was nan and didn't match VPR." << endl;
    } else if (!isnan(req_time) && isnan(vpr_req_time)) {
        if (const_gen_fanout_nodes.count(node_id)) {
            //VPR doesn't propagate required times along paths sourced by constant generators
            //but we do, so ignore such errors
#if 0
            cout << "Node: " << node_id << " Clk: " << domain;
            cout << " Calc_Req: " << std::setw(num_width) << req_time;
            cout << " VPR_Req: " << std::setw(num_width) << vpr_req_time << endl;
            cout << "\tOK since " << node_id << " in fanout of Constant Generator" << endl;
#endif
        } else {
            error = true;
            cout << "Node: " << node_id << " Clk: " << domain;
            cout << " Calc_Req: " << std::setw(num_width) << req_time;
            cout << " VPR_Req: " << std::setw(num_width) << vpr_req_time << endl;
            cout << "\tERROR Calculated required time was not nan but VPR expected nan." << endl;
        }

    } else if (isnan(req_time) && isnan(vpr_req_time)) {
        //They agree, pass
    } else if(req_rel_err > RELATIVE_EPSILON && req_abs_err > ABSOLUTE_EPSILON) {
        error = true;
        cout << "Node: " << node_id << " Clk: " << domain;
        cout << " Calc_Req: " << std::setw(num_width) << req_time;
        cout << " VPR_Req: " << std::setw(num_width) << vpr_req_time << endl;
        cout << "\tERROR required time abs, rel errs: " << std::setw(num_width) << req_abs_err;
        cout << ", " << std::setw(num_width) << req_rel_err << endl;
    } else {
        TATUM_ASSERT(!isnan(req_rel_err) && !isnan(req_abs_err));
        TATUM_ASSERT(req_rel_err < RELATIVE_EPSILON || req_abs_err < ABSOLUTE_EPSILON);
    }
    return error;
}
<commit_msg>Relax verification to allow for Tatum to report a time when VPR reports NAN<commit_after>#include "verify.hpp"
#include <iostream>
#include "sta_util.hpp"
#include "util.hpp"

#define RELATIVE_EPSILON 1.e-5
#define ABSOLUTE_EPSILON 1.e-13

using std::cout;
using std::endl;

using tatum::NodeId;
using tatum::DomainId;
using tatum::LevelId;
using tatum::TimingGraph;
using tatum::NodeType;

bool verify_arr_tag(float arr_time, float vpr_arr_time, NodeId node_id, DomainId domain, const std::set<NodeId>& clock_gen_fanout_nodes, std::streamsize num_width);

bool verify_req_tag(float req_time, float vpr_req_time, NodeId node_id, DomainId domain, const std::set<NodeId>& const_gen_fanout_nodes, std::streamsize num_width);

int verify_analyzer(const TimingGraph& tg, const tatum::SetupTimingAnalyzer& analyzer, const VprArrReqTimes& expected_arr_req_times, const std::set<NodeId>& const_gen_fanout_nodes, const std::set<NodeId>& clock_gen_fanout_nodes) {
    //expected_arr_req_times.print();

    //std::cout << "Verifying Calculated Timing Against VPR" << std::endl;
    std::ios_base::fmtflags saved_flags = std::cout.flags();
    std::streamsize prec = std::cout.precision();
    std::streamsize width = std::cout.width();

    std::streamsize num_width = 10;
    std::cout.precision(3);
    std::cout << std::scientific;
    std::cout << std::setw(10);
    int arr_reqs_verified = 0;
    bool error = false;

    /*
     * Check from VPR to Tatum results
     */
    for(const DomainId domain : expected_arr_req_times.clocks()) {

        int arrival_nodes_checked = 0; //Count number of nodes checked
        int required_nodes_checked = 0; //Count number of nodes checked

        //Arrival check by level
        for(const LevelId ilevel : tg.levels()){
            //std::cout << "LEVEL " << ilevel << std::endl;
            for(const NodeId node_id : tg.level_nodes(ilevel)) {
                //std::cout << "Verifying node: " << node_id << " Launch: " << src_domain << " Capture: " << sink_domain << std::endl;
                const auto& node_data_tags = analyzer.get_setup_data_tags(node_id);
                float vpr_arr_time = expected_arr_req_times.get_arr_time(domain, node_id);

                //Check arrival
                auto data_tag_iter = node_data_tags.find_tag_by_clock_domain(domain);
                if(data_tag_iter == node_data_tags.end()) {
                    //Did not find a matching data tag

                    //See if there is an associated clock tag.
                    //Note that VPR doesn't handle seperate clock tags, but we place
                    //clock arrivals on FF_SINK and FF_SOURCE nodes from the clock network,
                    //so even if such a clock tag exists we don't want to compare it to VPR
                    if(tg.node_type(node_id) != NodeType::FF_SINK && tg.node_type(node_id) != NodeType::FF_SOURCE) {
                        const auto& node_clock_tags = analyzer.get_setup_clock_tags(node_id);
                        auto clock_tag_iter = node_clock_tags.find_tag_by_clock_domain(domain);
                        if(clock_tag_iter != node_clock_tags.end()) {
                            error |= verify_arr_tag(clock_tag_iter->arr_time().value(), vpr_arr_time, node_id, domain, clock_gen_fanout_nodes, num_width);

                        } else if(!isnan(vpr_arr_time)) {
                            error = true;
                            std::cout << "Node: " << node_id << " Clk: " << domain << std::endl;
                            std::cout << "\tERROR Found no arrival-time tag, but VPR arrival time was ";
                            std::cout << std::setw(num_width) << vpr_arr_time << " (expected NAN)" << std::endl;
                        } else {
                            TATUM_ASSERT(isnan(vpr_arr_time));
                        }
                    }
                } else {
                    error |= verify_arr_tag(data_tag_iter->arr_time().value(), vpr_arr_time, node_id, domain, clock_gen_fanout_nodes, num_width);
                }
                arr_reqs_verified ++;
                arrival_nodes_checked++;
            }
        }
        //Since we walk our version of the graph make sure we see the same number of nodes as VPR
        TATUM_ASSERT(arrival_nodes_checked == (int) expected_arr_req_times.get_num_nodes());

        //Required check by level (in reverse)
        for(const LevelId level_id : tg.levels()) {
            for(const NodeId node_id : tg.level_nodes(level_id)) {

                const auto& node_data_tags = analyzer.get_setup_data_tags(node_id);
                float vpr_req_time = expected_arr_req_times.get_req_time(domain, node_id);
                //Check Required time
                auto data_tag_iter = node_data_tags.find_tag_by_clock_domain(domain);
                if(data_tag_iter == node_data_tags.end()) {
                    //See if there is an associated clock tag.
                    //Note that VPR doesn't handle seperate clock tags, but we place
                    //clock arrivals on FF_SINK and FF_SOURCE nodes from the clock network,
                    //so even if such a clock tag exists we don't want to compare it to VPR
                    if(tg.node_type(node_id) != NodeType::FF_SINK && tg.node_type(node_id) != NodeType::FF_SOURCE) {
                        const auto& node_clock_tags = analyzer.get_setup_clock_tags(node_id);
                        auto clock_tag_iter = node_clock_tags.find_tag_by_clock_domain(domain);
                        if(clock_tag_iter != node_clock_tags.end()) {
                            error |= verify_req_tag(clock_tag_iter->req_time().value(), vpr_req_time, node_id, domain, const_gen_fanout_nodes, num_width);
                        } else if(!isnan(vpr_req_time)) {
                            error = true;
                            std::cout << "Node: " << node_id << " Clk: " << domain  << std::endl;
                            std::cout << "\tERROR Found no required-time tag, but VPR required time was " << std::setw(num_width);
                            std::cout << vpr_req_time << " (expected NAN)" << std::endl;
                        }
                    }
                } else {
                    error |= verify_req_tag(data_tag_iter->req_time().value(), vpr_req_time, node_id, domain, const_gen_fanout_nodes, num_width);

                }
                arr_reqs_verified++;
                required_nodes_checked++;
            }
        }
        TATUM_ASSERT(required_nodes_checked == (int) expected_arr_req_times.get_num_nodes());
    }

    /*
     * Check from Tatum to VPR
     */

    //Check by level
//#ifdef CHECK_TATUM_TO_VPR_DIFFERENCES
#if 0
    for(int ilevel = 0; ilevel <tg.num_levels(); ilevel++) {
        //std::cout << "LEVEL " << ilevel << std::endl;
        for(NodeId node_id : tg.level(ilevel)) {
            for(const TimingTag& data_tag : analyzer.data_tags(node_id)) {
                //Arrival
                float arr_time = data_tag.arr_time().value();
                float vpr_arr_time = expected_arr_req_times.get_arr_time(data_tag.clock_domain(), node_id);
                verify_arr_tag(arr_time, vpr_arr_time, node_id, data_tag.clock_domain(), clock_gen_fanout_nodes, num_width);

                //Required
                float req_time = data_tag.req_time().value();
                float vpr_req_time = expected_arr_req_times.get_req_time(data_tag.clock_domain(), node_id);
                verify_req_tag(req_time, vpr_req_time, node_id, data_tag.clock_domain(), const_gen_fanout_nodes, num_width);
            }
        }
    }
#endif

    if(error) {
        std::cout << "Timing verification FAILED!" << std::endl;
        exit(1);
    } else {
        //std::cout << "Timing verification SUCCEEDED" << std::endl;
    }

    std::cout.flags(saved_flags);
    std::cout.precision(prec);
    std::cout.width(width);
    return arr_reqs_verified;
}

bool verify_arr_tag(float arr_time, float vpr_arr_time, NodeId node_id, DomainId domain, const std::set<NodeId>& clock_gen_fanout_nodes, std::streamsize num_width) {
    bool error = false;
    float arr_abs_err = fabs(arr_time - vpr_arr_time);
    float arr_rel_err = relative_error(arr_time, vpr_arr_time);
    if(isnan(arr_time) && isnan(arr_time) != isnan(vpr_arr_time)) {
        error = true;
        cout << "Node: " << node_id << " Clk: " << domain;
        cout << " Calc_Arr: " << std::setw(num_width) << arr_time;
        cout << " VPR_Arr: " << std::setw(num_width) << vpr_arr_time << endl;
        cout << "\tERROR Calculated arrival time was nan and didn't match VPR." << endl;
    } else if (!isnan(arr_time) && isnan(vpr_arr_time)) {
        if(clock_gen_fanout_nodes.count(node_id)) {
            //Pass, clock gen fanout can be NAN in VPR but have a value here,
            //since (unlike VPR) we explictly track clock arrivals as tags
        } else {
            //We allow tatum results to be non-NAN when VPR is NAN
            //
            //This occurs in some cases (such as applying clock tags to primary outputs)
            //which are cuased by the differeing analysis methods
#if 0
            error = true;
            cout << "Node: " << node_id << " Clk: " << domain;
            cout << " Calc_Arr: " << std::setw(num_width) << arr_time;
            cout << " VPR_Arr: " << std::setw(num_width) << vpr_arr_time << endl;
            cout << "\tERROR Calculated arrival time was not nan but VPR expected nan." << endl;
#endif
        }
    } else if (isnan(arr_time) && isnan(vpr_arr_time)) {
        //They agree, pass
    } else if(arr_rel_err > RELATIVE_EPSILON && arr_abs_err > ABSOLUTE_EPSILON) {
        error = true;
        cout << "Node: " << node_id << " Clk: " << domain;
        cout << " Calc_Arr: " << std::setw(num_width) << arr_time;
        cout << " VPR_Arr: " << std::setw(num_width) << vpr_arr_time << endl;
        cout << "\tERROR arrival time abs, rel errs: " << std::setw(num_width) << arr_abs_err;
        cout << ", " << std::setw(num_width) << arr_rel_err << endl;
    } else {
        TATUM_ASSERT(!isnan(arr_rel_err) && !isnan(arr_abs_err));
        TATUM_ASSERT(arr_rel_err < RELATIVE_EPSILON || arr_abs_err < ABSOLUTE_EPSILON);
    }
    return error;
}

bool verify_req_tag(float req_time, float vpr_req_time, NodeId node_id, DomainId domain, const std::set<NodeId>& const_gen_fanout_nodes, std::streamsize num_width) {
    bool error = false;
    float req_abs_err = fabs(req_time - vpr_req_time);
    float req_rel_err = relative_error(req_time, vpr_req_time);
    if(isnan(req_time) && isnan(req_time) != isnan(vpr_req_time)) {
        error = true;
        cout << "Node: " << node_id << " Clk: " << domain;
        cout << " Calc_Req: " << std::setw(num_width) << req_time;
        cout << " VPR_Req: " << std::setw(num_width) << vpr_req_time << endl;
        cout << "\tERROR Calculated required time was nan and didn't match VPR." << endl;
    } else if (!isnan(req_time) && isnan(vpr_req_time)) {
        if (const_gen_fanout_nodes.count(node_id)) {
            //VPR doesn't propagate required times along paths sourced by constant generators
            //but we do, so ignore such errors
#if 0
            cout << "Node: " << node_id << " Clk: " << domain;
            cout << " Calc_Req: " << std::setw(num_width) << req_time;
            cout << " VPR_Req: " << std::setw(num_width) << vpr_req_time << endl;
            cout << "\tOK since " << node_id << " in fanout of Constant Generator" << endl;
#endif
        } else {
            error = true;
            cout << "Node: " << node_id << " Clk: " << domain;
            cout << " Calc_Req: " << std::setw(num_width) << req_time;
            cout << " VPR_Req: " << std::setw(num_width) << vpr_req_time << endl;
            cout << "\tERROR Calculated required time was not nan but VPR expected nan." << endl;
        }

    } else if (isnan(req_time) && isnan(vpr_req_time)) {
        //They agree, pass
    } else if(req_rel_err > RELATIVE_EPSILON && req_abs_err > ABSOLUTE_EPSILON) {
        error = true;
        cout << "Node: " << node_id << " Clk: " << domain;
        cout << " Calc_Req: " << std::setw(num_width) << req_time;
        cout << " VPR_Req: " << std::setw(num_width) << vpr_req_time << endl;
        cout << "\tERROR required time abs, rel errs: " << std::setw(num_width) << req_abs_err;
        cout << ", " << std::setw(num_width) << req_rel_err << endl;
    } else {
        TATUM_ASSERT(!isnan(req_rel_err) && !isnan(req_abs_err));
        TATUM_ASSERT(req_rel_err < RELATIVE_EPSILON || req_abs_err < ABSOLUTE_EPSILON);
    }
    return error;
}
<|endoftext|>


<commit_before>#include "commonOptions.h"
#include "Option.h"

namespace commonOptions {

bool& hasError() {
	static bool error{false};
	return error;
}

void print() {
	auto allOptions = getRootSection()->getVariables();
	for (auto b : allOptions) {
		b->print();
	}
}
void printShellCompl() {
	auto allOptions = getRootSection()->getVariables();
	for (auto b : allOptions) {
		b->printShellCompl();
	}
}

/**
 * This is a very simple command line parser
 * It can parse stuff like
 * --option
 * --option value
 * --opiton=value
 *
 *  it will ignore everything else on the command line. This is needed because boost::
 *  program_options is handling unknown options very badly
 */
bool parse(int argc, char const* const* argv) {
	std::map<std::string, std::string> options;

	for (int i(1); i<argc; ++i) {
		std::string arg = argv[i];
		if (0 == arg.compare(0, 2, "--")) {
			arg = arg.substr(2); // cut of first two symbols
		} else {
			arg = "__command__" + arg;
		}
		std::string key   = arg;
		std::string value = "true";

		size_t equalSignPos = arg.find("=");
		if (equalSignPos != std::string::npos) {
			key   = arg.substr(0, equalSignPos);
			value = arg.substr(equalSignPos+1);
		} else if (has_key(key) and get_option(key)->isListType()) {
			if (i+1 < argc) {
				value = argv[++i];
				while (i+1 < argc) {
					value += std::string(", ") + argv[++i];
				}
			}
			value = "[" + value + "]";
		} else if (i+1 < argc && std::string(argv[i+1]).compare(0, 2, "--" ) != 0) {
			value = argv[++i];
		}
		auto description = get_description(key);
		description->changeDefaultValue(value, 1);
	}
/*	if (commands.size() >= 1) {
		auto cmdDescription = get_description("__command__" + commands[0]);
		cmdDescription->changeDefaultValue("true", 1);

		commands.erase(commands.begin());
		auto filesDescription = get_description("__files__");
		filesDescription->changeDefaultValue(serializer::yaml::writeAsString(commands), 1);
	}*/

	if (argc == 2 && std::string(argv[1]) == "__completion") {
		printShellCompl();
		exit(0);
	}

	return not hasError();
}

void loadFile(std::string const& _file) {
	std::map<std::string, std::string> options;

	serializer::yaml::read(_file, options);

	for (auto o : options) {
		auto desc = get_description(o.first);
		desc->changeValue(o.second);
		desc->defaultValueActive = false;
	}
	Singleton::getInstance().signal_load();
}

/** if _includingSections is empty, include them all
 */
void saveFile(std::string const& _file, std::vector<std::string> const& _includingSections) {
	std::map<std::string, std::string> options;

	std::set<Section*> allSections;

	std::queue<Section*> sectionsToProcess;

	// collecting all sections (to remove duplicates)
	for (auto const& sectName : _includingSections) {
		sectionsToProcess.push(get_section(sectName));
	}
	if (_includingSections.empty()) {
		sectionsToProcess.push(getRootSection());
	}
	while (not sectionsToProcess.empty()) {
		auto sect = sectionsToProcess.front();
		sectionsToProcess.pop();
		allSections.insert(sect);
		for (auto& child : sect->getChildren()) {
			sectionsToProcess.push(&child.second);
		}
	}

	// Serialize all OptionDescriptions (if they don't have default value)
	for (auto section : allSections) {
		auto fullName = section->fullName();

		for (auto const& description : section->getDescriptions()) {
			auto name = fullName + description.second->optionName;
			if (not description.second->defaultValueActive) {
				auto const* d = description.second.get();
				options[name] = d->value;
			}
		}
	}
	serializer::yaml::write(_file, options);
}

Section* get_section(std::string const& _str) {
	auto path = splitPath(_str);
	Section* section = getRootSection();
	for (auto const& p : path) {
		section = section->accessChild(p);
	}
	return section;
}

Section* getRootSection() {
	static Section singleton;
	return &singleton;
}

auto getUnmatchedParameters() -> std::vector<std::string> {
	std::vector<std::string> missing;

	std::set<std::string> available;
	auto variables = commonOptions::getRootSection()->getVariables();
	for (auto v : variables) {
		available.insert(v->getSectionName() + v->getName());
	}

	auto descriptions = commonOptions::getRootSection()->getAllDescriptions();
	for (auto const& d : descriptions) {
		if (available.count(d.first) == 0) {
			missing.push_back(d.first);
		}
	}
	return missing;
}
}
<commit_msg>more strict on default values<commit_after>#include "commonOptions.h"
#include "Option.h"

namespace commonOptions {

bool& hasError() {
	static bool error{false};
	return error;
}

void print() {
	auto allOptions = getRootSection()->getVariables();
	for (auto b : allOptions) {
		b->print();
	}
}
void printShellCompl() {
	auto allOptions = getRootSection()->getVariables();
	for (auto b : allOptions) {
		b->printShellCompl();
	}
}

/**
 * This is a very simple command line parser
 * It can parse stuff like
 * --option
 * --option value
 * --opiton=value
 *
 *  it will ignore everything else on the command line. This is needed because boost::
 *  program_options is handling unknown options very badly
 */
bool parse(int argc, char const* const* argv) {
	std::map<std::string, std::string> options;

	for (int i(1); i<argc; ++i) {
		std::string arg = argv[i];
		if (0 == arg.compare(0, 2, "--")) {
			arg = arg.substr(2); // cut of first two symbols
		} else {
			arg = "__command__" + arg;
		}
		std::string key   = arg;
		std::string value = "true";

		size_t equalSignPos = arg.find("=");
		if (equalSignPos != std::string::npos) {
			key   = arg.substr(0, equalSignPos);
			value = arg.substr(equalSignPos+1);
		} else if (has_key(key) and get_option(key)->isListType()) {
			if (i+1 < argc) {
				value = argv[++i];
				while (i+1 < argc) {
					value += std::string(", ") + argv[++i];
				}
			}
			value = "[" + value + "]";
		} else if (i+1 < argc && std::string(argv[i+1]).compare(0, 2, "--" ) != 0) {
			value = argv[++i];
		}
		auto description = get_description(key);
		description->changeDefaultValue(value, 1);
	}
/*	if (commands.size() >= 1) {
		auto cmdDescription = get_description("__command__" + commands[0]);
		cmdDescription->changeDefaultValue("true", 1);

		commands.erase(commands.begin());
		auto filesDescription = get_description("__files__");
		filesDescription->changeDefaultValue(serializer::yaml::writeAsString(commands), 1);
	}*/

	if (argc == 2 && std::string(argv[1]) == "__completion") {
		printShellCompl();
		exit(0);
	}

	return not hasError();
}

void loadFile(std::string const& _file) {
	std::map<std::string, std::string> options;

	serializer::yaml::read(_file, options);

	for (auto o : options) {
		auto desc = get_description(o.first);
		desc->changeValue(o.second);
		desc->defaultValueActive = false;
	}
	Singleton::getInstance().signal_load();
}

/** if _includingSections is empty, include them all
 */
void saveFile(std::string const& _file, std::vector<std::string> const& _includingSections) {
	std::map<std::string, std::string> options;

	std::set<Section*> allSections;

	std::queue<Section*> sectionsToProcess;

	// collecting all sections (to remove duplicates)
	for (auto const& sectName : _includingSections) {
		sectionsToProcess.push(get_section(sectName));
	}
	if (_includingSections.empty()) {
		sectionsToProcess.push(getRootSection());
	}
	while (not sectionsToProcess.empty()) {
		auto sect = sectionsToProcess.front();
		sectionsToProcess.pop();
		allSections.insert(sect);
		for (auto& child : sect->getChildren()) {
			sectionsToProcess.push(&child.second);
		}
	}

	// Serialize all OptionDescriptions (if they don't have default value)
	for (auto section : allSections) {
		auto fullName = section->fullName();

		for (auto const& description : section->getDescriptions()) {
			auto name = fullName + description.second->optionName;
			if (not description.second->defaultValueActive) {
				auto const* d = description.second.get();
				// TODO hack, if value looks like default value, don't save it
				if (description.second->defaultValue != d->value) {
					options[name] = d->value;
				}
			}
		}
	}
	serializer::yaml::write(_file, options);
}

Section* get_section(std::string const& _str) {
	auto path = splitPath(_str);
	Section* section = getRootSection();
	for (auto const& p : path) {
		section = section->accessChild(p);
	}
	return section;
}

Section* getRootSection() {
	static Section singleton;
	return &singleton;
}

auto getUnmatchedParameters() -> std::vector<std::string> {
	std::vector<std::string> missing;

	std::set<std::string> available;
	auto variables = commonOptions::getRootSection()->getVariables();
	for (auto v : variables) {
		available.insert(v->getSectionName() + v->getName());
	}

	auto descriptions = commonOptions::getRootSection()->getAllDescriptions();
	for (auto const& d : descriptions) {
		if (available.count(d.first) == 0) {
			missing.push_back(d.first);
		}
	}
	return missing;
}
}
<|endoftext|>


<commit_before>#include "thread_manager.h"
#include "core_manager.h"
#include "config.h"
#include "log.h"
#include "transport.h"
#include "simulator.h"
#include "network.h"
#include "message_types.h"
#include "core.h"

#define LOG_DEFAULT_RANK -1
#define LOG_DEFAULT_MODULE THREAD_MANAGER

ThreadManager::ThreadManager(CoreManager *core_manager)
   : m_core_manager(core_manager)
{
   Config *config = Config::getSingleton();

   m_master = config->getCurrentProcessNum() == 0;

   if (m_master)
   {
      m_thread_state.resize(config->getTotalCores());
      m_thread_state[0].running = true;
      m_thread_state[config->getMCPCoreNum()].running = true;
      LOG_PRINT("%d", config->getMCPCoreNum());
   }
}

ThreadManager::~ThreadManager()
{
   if (m_master)
   {
      m_thread_state[0].running = false;
      m_thread_state[Config::getSingleton()->getMCPCoreNum()].running = false;

      for (UInt32 i = 0; i < m_thread_state.size(); i++)
         LOG_ASSERT_WARNING(!m_thread_state[i].running, "*WARNING* Thread %d still active when ThreadManager destructs!", i);
   }
}

void ThreadManager::onThreadStart(SInt32 core_id)
{
   m_core_manager->initializeThread(core_id);
}

void ThreadManager::onThreadExit()
{
   // send message to master process to update thread state
   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();
   SInt32 msg[4] = { LCP_MESSAGE_THREAD_EXIT, m_core_manager->getCurrentCoreID(), 0, 0 };
   LOG_PRINT("onThreadExit msg: { %d, %d, %u, %u }", msg[0], msg[1], msg[2], msg[3]);
   globalNode->globalSend(0, msg, sizeof(msg));

   m_core_manager->terminateThread();
}

void ThreadManager::masterOnThreadExit(SInt32 core_id, UInt64 time)
{
   LOG_PRINT("masterOnThreadExit : %d %llu", core_id, time);
   assert(m_thread_state[core_id].running);
   m_thread_state[core_id].running = false;

   wakeUpWaiter(core_id);
}

/*
  Thread spawning occurs in the following steps:

  1. A message is sent from requestor to the master thread manager.
  2. The master thread manager finds the destination core and sends a message to its host process.
  3. The host process spawns the new thread and returns an ack to the master thread manager.
  4. The master thread manager replies to the requestor with the id of the dest core.
*/

SInt32 ThreadManager::spawnThread(void (*func)(void*), void *arg)
{
   LOG_PRINT("spawnThread with func: %p and arg: %p", func, arg);

   // step 1
   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();
   Core *core = m_core_manager->getCurrentCore();

   ThreadSpawnRequest req = { LCP_MESSAGE_THREAD_SPAWN_REQUEST_FROM_REQUESTER,
                              func, arg, core->getId(), -1 };

   globalNode->globalSend(0, &req, sizeof(req));

   NetPacket pkt = core->getNetwork()->netRecvType(LCP_SPAWN_THREAD_REPLY_FROM_MASTER_TYPE);
   LOG_ASSERT_ERROR(pkt.length == sizeof(SInt32), "*ERROR* Unexpected reply size.");

   SInt32 core_id = *((SInt32*)pkt.data);
   LOG_PRINT("Thread spawned on core: %d", core_id);

   return *((SInt32*)pkt.data);
}

void ThreadManager::masterSpawnThread(ThreadSpawnRequest *req)
{
   LOG_PRINT("masterSpawnThread with req: { %p, %p, %d, %d }", req->func, req->arg, req->requester, req->core_id);
   // step 2

   // find core to use
   // FIXME: Load balancing?
   for (SInt32 i = 0; i < (SInt32)m_thread_state.size(); i++)
   {
      if (!m_thread_state[i].running)
      {
         req->core_id = i;
         break;
      }
   }

   LOG_ASSERT_ERROR(req->core_id != -1, "*ERROR* No cores available for spawnThread request.");

   // spawn process on child
   SInt32 dest_proc = Config::getSingleton()->getProcessNumForCore(req->core_id);
   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();

   req->msg_type = LCP_MESSAGE_THREAD_SPAWN_REQUEST_FROM_MASTER;

   globalNode->globalSend(dest_proc, req, sizeof(*req));
   m_thread_state[req->core_id].running = true;
}

void ThreadManager::slaveSpawnThread(ThreadSpawnRequest *req)
{
   LOG_PRINT("slaveSpawnThread with req: { %p, %p, %d, %d }", req->func, req->arg, req->requester, req->core_id);
   // step 3

   ThreadSpawnRequest *req_cpy = new ThreadSpawnRequest(*req);

   Thread *t = Thread::create(spawnedThreadFunc, req_cpy);
   t->run();

   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();
   req->msg_type = LCP_MESSAGE_THREAD_SPAWN_REPLY_FROM_SLAVE;
   globalNode->globalSend(0, req, sizeof(*req));
}

void ThreadManager::masterSpawnThreadReply(ThreadSpawnRequest *req)
{
   LOG_PRINT("masterSpawnThreadReply with req: { %p, %p, %d, %d }", req->func, req->arg, req->requester, req->core_id);
   // step 4

   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();

   NetPacket pkt(0 /*time*/, LCP_SPAWN_THREAD_REPLY_FROM_MASTER_TYPE,
                 0 /*sender*/, req->requester, sizeof(SInt32), &req->core_id);
   Byte *buffer = pkt.makeBuffer();
   globalNode->send(req->requester, buffer, pkt.bufferSize());
   delete [] buffer;
}

void ThreadManager::spawnedThreadFunc(void *vpreq)
{
   ThreadSpawnRequest *req = (ThreadSpawnRequest*) vpreq;
   LOG_PRINT("spawnedThreadFunc with req: { %p, %p, %d, %d }", req->func, req->arg, req->requester, req->core_id);

   Sim()->getThreadManager()->onThreadStart(req->core_id);

   req->func(req->arg);

   Sim()->getThreadManager()->onThreadExit();

   delete req;
}

void ThreadManager::joinThread(SInt32 core_id)
{
   // Obtain the object that allows us to communicate to other processes
   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();

   // create a condition variable to wait for the reply
   ThreadJoinRequest msg;
   msg.core_id = core_id;
   msg.sender = m_core_manager->getCurrentCoreID();

   // Send the message to the master process
   globalNode->globalSend(0, &msg, sizeof(msg));

   // Wait for reply
   Core *core = m_core_manager->getCurrentCore();
   NetPacket pkt = core->getNetwork()->netRecvType(LCP_JOIN_THREAD_REPLY);
}

void ThreadManager::masterJoinThread(ThreadJoinRequest *req)
{
   LOG_PRINT("masterJoinThread called.");
   //FIXME: fill in the proper time

   LOG_ASSERT_ERROR(m_thread_state[req->core_id].waiter == -1,
                    "*ERROR* Multiple threads joining on thread: %d", req->core_id);
   m_thread_state[req->core_id].waiter = req->sender;

   // Core not running, so the thread must have joined
   if(m_thread_state[req->core_id].running == false)
   {
      LOG_PRINT("Not running, sending reply.");
      wakeUpWaiter(req->core_id);
   }
}

void ThreadManager::wakeUpWaiter(SInt32 core_id)
{
   if (m_thread_state[core_id].waiter != -1)
   {
      Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();
      NetPacket pkt(0 /*time*/, LCP_JOIN_THREAD_REPLY,
                    0 /*sender*/, m_thread_state[core_id].waiter, 0, NULL);
      Byte *buffer = pkt.makeBuffer();
      globalNode->send(m_thread_state[core_id].waiter, buffer, pkt.bufferSize());
      delete [] buffer;

      m_thread_state[core_id].waiter = -1;
   }
}
<commit_msg>[thread_manager] Send spawn thread reply from spawned thread (not slave LCP). This ensure thread has started by the time SpawnThread returns.<commit_after>#include "thread_manager.h"
#include "core_manager.h"
#include "config.h"
#include "log.h"
#include "transport.h"
#include "simulator.h"
#include "network.h"
#include "message_types.h"
#include "core.h"

#define LOG_DEFAULT_RANK -1
#define LOG_DEFAULT_MODULE THREAD_MANAGER

ThreadManager::ThreadManager(CoreManager *core_manager)
   : m_core_manager(core_manager)
{
   Config *config = Config::getSingleton();

   m_master = config->getCurrentProcessNum() == 0;

   if (m_master)
   {
      m_thread_state.resize(config->getTotalCores());
      m_thread_state[0].running = true;
      m_thread_state[config->getMCPCoreNum()].running = true;
      LOG_PRINT("%d", config->getMCPCoreNum());
   }
}

ThreadManager::~ThreadManager()
{
   if (m_master)
   {
      m_thread_state[0].running = false;
      m_thread_state[Config::getSingleton()->getMCPCoreNum()].running = false;

      for (UInt32 i = 0; i < m_thread_state.size(); i++)
         LOG_ASSERT_WARNING(!m_thread_state[i].running, "*WARNING* Thread %d still active when ThreadManager destructs!", i);
   }
}

void ThreadManager::onThreadStart(SInt32 core_id)
{
   m_core_manager->initializeThread(core_id);
}

void ThreadManager::onThreadExit()
{
   // send message to master process to update thread state
   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();
   SInt32 msg[4] = { LCP_MESSAGE_THREAD_EXIT, m_core_manager->getCurrentCoreID(), 0, 0 };
   LOG_PRINT("onThreadExit msg: { %d, %d, %u, %u }", msg[0], msg[1], msg[2], msg[3]);
   globalNode->globalSend(0, msg, sizeof(msg));

   m_core_manager->terminateThread();
}

void ThreadManager::masterOnThreadExit(SInt32 core_id, UInt64 time)
{
   LOG_PRINT("masterOnThreadExit : %d %llu", core_id, time);
   assert(m_thread_state[core_id].running);
   m_thread_state[core_id].running = false;

   wakeUpWaiter(core_id);
}

/*
  Thread spawning occurs in the following steps:

  1. A message is sent from requestor to the master thread manager.
  2. The master thread manager finds the destination core and sends a message to its host process.
  3. The host process spawns the new thread and returns an ack to the master thread manager.
  4. The master thread manager replies to the requestor with the id of the dest core.
*/

SInt32 ThreadManager::spawnThread(void (*func)(void*), void *arg)
{
   LOG_PRINT("spawnThread with func: %p and arg: %p", func, arg);

   // step 1
   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();
   Core *core = m_core_manager->getCurrentCore();

   ThreadSpawnRequest req = { LCP_MESSAGE_THREAD_SPAWN_REQUEST_FROM_REQUESTER,
                              func, arg, core->getId(), -1 };

   globalNode->globalSend(0, &req, sizeof(req));

   NetPacket pkt = core->getNetwork()->netRecvType(LCP_SPAWN_THREAD_REPLY_FROM_MASTER_TYPE);
   LOG_ASSERT_ERROR(pkt.length == sizeof(SInt32), "*ERROR* Unexpected reply size.");

   SInt32 core_id = *((SInt32*)pkt.data);
   LOG_PRINT("Thread spawned on core: %d", core_id);

   return *((SInt32*)pkt.data);
}

void ThreadManager::masterSpawnThread(ThreadSpawnRequest *req)
{
   LOG_PRINT("masterSpawnThread with req: { %p, %p, %d, %d }", req->func, req->arg, req->requester, req->core_id);
   // step 2

   // find core to use
   // FIXME: Load balancing?
   for (SInt32 i = 0; i < (SInt32)m_thread_state.size(); i++)
   {
      if (!m_thread_state[i].running)
      {
         req->core_id = i;
         break;
      }
   }

   LOG_ASSERT_ERROR(req->core_id != -1, "*ERROR* No cores available for spawnThread request.");

   // spawn process on child
   SInt32 dest_proc = Config::getSingleton()->getProcessNumForCore(req->core_id);
   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();

   req->msg_type = LCP_MESSAGE_THREAD_SPAWN_REQUEST_FROM_MASTER;

   globalNode->globalSend(dest_proc, req, sizeof(*req));
   m_thread_state[req->core_id].running = true;
}

void ThreadManager::slaveSpawnThread(ThreadSpawnRequest *req)
{
   LOG_PRINT("slaveSpawnThread with req: { %p, %p, %d, %d }", req->func, req->arg, req->requester, req->core_id);
   // step 3

   ThreadSpawnRequest *req_cpy = new ThreadSpawnRequest(*req);

   Thread *t = Thread::create(spawnedThreadFunc, req_cpy);
   t->run();
}

void ThreadManager::masterSpawnThreadReply(ThreadSpawnRequest *req)
{
   LOG_PRINT("masterSpawnThreadReply with req: { %p, %p, %d, %d }", req->func, req->arg, req->requester, req->core_id);
   // step 4

   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();

   NetPacket pkt(0 /*time*/, LCP_SPAWN_THREAD_REPLY_FROM_MASTER_TYPE,
                 0 /*sender*/, req->requester, sizeof(SInt32), &req->core_id);
   Byte *buffer = pkt.makeBuffer();
   globalNode->send(req->requester, buffer, pkt.bufferSize());
   delete [] buffer;
}

void ThreadManager::spawnedThreadFunc(void *vpreq)
{
   ThreadSpawnRequest *req = (ThreadSpawnRequest*) vpreq;
   LOG_PRINT("spawnedThreadFunc with req: { %p, %p, %d, %d }", req->func, req->arg, req->requester, req->core_id);

   Sim()->getThreadManager()->onThreadStart(req->core_id);

   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();
   req->msg_type = LCP_MESSAGE_THREAD_SPAWN_REPLY_FROM_SLAVE;
   globalNode->globalSend(0, req, sizeof(*req));

   req->func(req->arg);

   Sim()->getThreadManager()->onThreadExit();

   delete req;
}

void ThreadManager::joinThread(SInt32 core_id)
{
   // Obtain the object that allows us to communicate to other processes
   Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();

   // create a condition variable to wait for the reply
   ThreadJoinRequest msg;
   msg.core_id = core_id;
   msg.sender = m_core_manager->getCurrentCoreID();

   // Send the message to the master process
   globalNode->globalSend(0, &msg, sizeof(msg));

   // Wait for reply
   Core *core = m_core_manager->getCurrentCore();
   NetPacket pkt = core->getNetwork()->netRecvType(LCP_JOIN_THREAD_REPLY);
}

void ThreadManager::masterJoinThread(ThreadJoinRequest *req)
{
   LOG_PRINT("masterJoinThread called.");
   //FIXME: fill in the proper time

   LOG_ASSERT_ERROR(m_thread_state[req->core_id].waiter == -1,
                    "*ERROR* Multiple threads joining on thread: %d", req->core_id);
   m_thread_state[req->core_id].waiter = req->sender;

   // Core not running, so the thread must have joined
   if(m_thread_state[req->core_id].running == false)
   {
      LOG_PRINT("Not running, sending reply.");
      wakeUpWaiter(req->core_id);
   }
}

void ThreadManager::wakeUpWaiter(SInt32 core_id)
{
   if (m_thread_state[core_id].waiter != -1)
   {
      Transport::Node *globalNode = Transport::getSingleton()->getGlobalNode();
      NetPacket pkt(0 /*time*/, LCP_JOIN_THREAD_REPLY,
                    0 /*sender*/, m_thread_state[core_id].waiter, 0, NULL);
      Byte *buffer = pkt.makeBuffer();
      globalNode->send(m_thread_state[core_id].waiter, buffer, pkt.bufferSize());
      delete [] buffer;

      m_thread_state[core_id].waiter = -1;
   }
}
<|endoftext|>


<commit_before>/******************************************************************************
 *
 * Wendy asset manager
 * Copyright (c) 2011 Remi Papillie
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *    1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 *
 *    2. Altered source versions must be plainly marked as such, and must not
 *    be misrepresented as being the original software.
 *
 *    3. This notice may not be removed or altered from any source
 *    distribution.
 *
 *****************************************************************************/

#ifdef _WIN32

#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <dokan.h>
#include <iostream>

#include <wendy/Project.hpp>

#include "ProjectProxy.hpp"

static ProjectProxy *proxy = NULL;

static std::string wideToUtf8(std::wstring wide)
{
	// passing no output buffer return required buffer size
	int size = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, NULL, 0, NULL, NULL);

	// convert into a temporary buffer
	char *outputBuffer = new char[size];
	WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, outputBuffer, size, NULL, NULL);

	// create the equivalent string object
	std::string utf = outputBuffer;

	// destroy temporary buffer
	delete outputBuffer;

	return utf;
}

static std::wstring utf8ToWide(std::string utf)
{
	// passing no output buffer return required buffer size
	int size = MultiByteToWideChar(CP_UTF8, 0, utf.c_str(), -1, NULL, 0);

	// convert into a temporary buffer
	wchar_t *outputBuffer = new wchar_t[size];
	MultiByteToWideChar(CP_UTF8, 0, utf.c_str(), -1, outputBuffer, size);

	// create the equivalent wstring object
	std::wstring wide = outputBuffer;

	// destroy temporary buffer
	delete outputBuffer;

	return wide;
}

// convert to utf-8, change '\\' to '/' and remove leading slash
static std::string makePathStandard(LPCWSTR path)
{
	std::string utfPath = wideToUtf8(std::wstring(path));

	// change backslashes to forward slashes
	size_t slashPos;
	while ((slashPos = utfPath.find('\\')) != std::string::npos)
		utfPath.replace(slashPos, 1, "/");

	// remove leading slash
	return utfPath.substr(1);
}

static int DOKAN_CALLBACK WendyCreateFile(LPCWSTR filename, DWORD accessMode, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes, PDOKAN_FILE_INFO info)
{
	wprintf(L"CreateFile: %s\n", filename);
	return 0;
}

static int DOKAN_CALLBACK WendyOpenDirectory(LPCWSTR filename, PDOKAN_FILE_INFO info)
{
	wprintf(L"OpenDir %s\n", filename);
	std::cout << "OpenDir: " << makePathStandard(filename) << std::endl;

	std::string path = makePathStandard(filename);

	ProjectProxy::FileAttributes attributes;
	if (!proxy->getFileAttributes(path, &attributes))
		return -ERROR_PATH_NOT_FOUND;

	if (!attributes.folder)
		return -ERROR_PATH_NOT_FOUND; // TODO: find the right error code for this

	return 0;

	/*if (wcscmp(filename, L"\\") == 0)
		return 0;
	else if (wcscmp(filename, L"\\plop") == 0)
		return 0;

	return -ERROR_PATH_NOT_FOUND;*/
}

static int DOKAN_CALLBACK WendyCleanup(LPCWSTR filename, PDOKAN_FILE_INFO info)
{
	wprintf(L"Cleanup %s\n", filename);

	return 0;
}

static int DOKAN_CALLBACK WendyFindFiles(LPCWSTR filename, PFillFindData fillFindData, PDOKAN_FILE_INFO info)
{
	wprintf(L"FindFiles %s\n", filename);

	WIN32_FIND_DATAW entry;
	ZeroMemory(&entry, sizeof(WIN32_FIND_DATAW));

	std::string path = makePathStandard(filename);

	std::vector<std::string> files = proxy->listFolder(path);
	for (unsigned int i = 0; i < files.size(); ++i)
	{
		// filename
		const std::string &filename = files[i];
		std::wstring wfilename = utf8ToWide(filename);
		wcsncpy(entry.cFileName, wfilename.c_str(), MAX_PATH - 1);

		// other attributes
		ProjectProxy::FileAttributes attributes;
		proxy->getFileAttributes(files[i], &attributes);
		entry.dwFileAttributes = attributes.folder ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;

		// send item back to caller
		fillFindData(&entry, info);
	}

	return 0;
}

int __cdecl wmain(ULONG argc, PWCHAR argv[])
{
	if (argc < 3)
	{
		wprintf(L"Usage: %s <drive letter> <project name>\n", argv[0]);
		return 0;
	}

	DOKAN_OPTIONS options;
	DOKAN_OPERATIONS operations;

	ZeroMemory(&options, sizeof(DOKAN_OPTIONS));
	options.Version = DOKAN_VERSION;
	options.ThreadCount = 0; // use default
	options.MountPoint = argv[1];
	options.Options = DOKAN_OPTION_KEEP_ALIVE;

	ZeroMemory(&operations, sizeof(DOKAN_OPERATIONS));
	operations.CreateFile = WendyCreateFile;
	operations.OpenDirectory = WendyOpenDirectory;
	operations.Cleanup = WendyCleanup;
	operations.FindFiles = WendyFindFiles;

	//char projectName[500];
	//WideCharToMultiByte(CP_UTF8, 0, argv[2], -1, projectName, 500, NULL, NULL);
	proxy = new ProjectProxy();

	int result = DokanMain(&options, &operations);

	delete proxy;

	return result;
}

#endif // _WIN32

<commit_msg>fixed subdirectories under windows<commit_after>/******************************************************************************
 *
 * Wendy asset manager
 * Copyright (c) 2011 Remi Papillie
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *    1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software. If you use this software
 *    in a product, an acknowledgment in the product documentation would be
 *    appreciated but is not required.
 *
 *    2. Altered source versions must be plainly marked as such, and must not
 *    be misrepresented as being the original software.
 *
 *    3. This notice may not be removed or altered from any source
 *    distribution.
 *
 *****************************************************************************/

#ifdef _WIN32

#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <stdlib.h>
#include <dokan.h>
#include <iostream>

#include <wendy/Project.hpp>

#include "ProjectProxy.hpp"

static ProjectProxy *proxy = NULL;

static std::string wideToUtf8(std::wstring wide)
{
	// passing no output buffer return required buffer size
	int size = WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, NULL, 0, NULL, NULL);

	// convert into a temporary buffer
	char *outputBuffer = new char[size];
	WideCharToMultiByte(CP_UTF8, 0, wide.c_str(), -1, outputBuffer, size, NULL, NULL);

	// create the equivalent string object
	std::string utf = outputBuffer;

	// destroy temporary buffer
	delete outputBuffer;

	return utf;
}

static std::wstring utf8ToWide(std::string utf)
{
	// passing no output buffer return required buffer size
	int size = MultiByteToWideChar(CP_UTF8, 0, utf.c_str(), -1, NULL, 0);

	// convert into a temporary buffer
	wchar_t *outputBuffer = new wchar_t[size];
	MultiByteToWideChar(CP_UTF8, 0, utf.c_str(), -1, outputBuffer, size);

	// create the equivalent wstring object
	std::wstring wide = outputBuffer;

	// destroy temporary buffer
	delete outputBuffer;

	return wide;
}

// convert to utf-8, change '\\' to '/' and remove leading slash
static std::string makePathStandard(LPCWSTR path)
{
	std::string utfPath = wideToUtf8(std::wstring(path));

	// change backslashes to forward slashes
	size_t slashPos;
	while ((slashPos = utfPath.find('\\')) != std::string::npos)
		utfPath.replace(slashPos, 1, "/");

	// remove leading slash
	return utfPath.substr(1);
}

static int DOKAN_CALLBACK WendyCreateFile(LPCWSTR filename, DWORD accessMode, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes, PDOKAN_FILE_INFO info)
{
	//wprintf(L"CreateFile: %s\n", filename);
	return 0;
}

static int DOKAN_CALLBACK WendyOpenDirectory(LPCWSTR filename, PDOKAN_FILE_INFO info)
{
	//wprintf(L"OpenDir %s\n", filename);
	//std::cout << "OpenDir: " << makePathStandard(filename) << std::endl;

	std::string path = makePathStandard(filename);

	ProjectProxy::FileAttributes attributes;
	if (!proxy->getFileAttributes(path, &attributes))
		return -ERROR_PATH_NOT_FOUND;

	if (!attributes.folder)
		return -ERROR_PATH_NOT_FOUND; // TODO: find the right error code for this

	return 0;

	/*if (wcscmp(filename, L"\\") == 0)
		return 0;
	else if (wcscmp(filename, L"\\plop") == 0)
		return 0;

	return -ERROR_PATH_NOT_FOUND;*/
}

static int DOKAN_CALLBACK WendyCleanup(LPCWSTR filename, PDOKAN_FILE_INFO info)
{
	//wprintf(L"Cleanup %s\n", filename);

	return 0;
}

static int DOKAN_CALLBACK WendyFindFiles(LPCWSTR filename, PFillFindData fillFindData, PDOKAN_FILE_INFO info)
{
	//wprintf(L"FindFiles %s\n", filename);

	WIN32_FIND_DATAW entry;
	ZeroMemory(&entry, sizeof(WIN32_FIND_DATAW));

	std::string path = makePathStandard(filename);

	std::vector<std::string> files = proxy->listFolder(path);
	for (unsigned int i = 0; i < files.size(); ++i)
	{
		// filename
		const std::string &filename = files[i];
		std::wstring wfilename = utf8ToWide(filename);
		wcsncpy(entry.cFileName, wfilename.c_str(), MAX_PATH - 1);

		// other attributes
		ProjectProxy::FileAttributes attributes;
		std::string fullChildPath = files[i];
		if (path.size() > 0)
			fullChildPath = path + "/" + files[i];
		proxy->getFileAttributes(fullChildPath, &attributes);
		entry.dwFileAttributes = attributes.folder ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;

		// send item back to caller
		fillFindData(&entry, info);
	}

	return 0;
}

int __cdecl wmain(ULONG argc, PWCHAR argv[])
{
	if (argc < 3)
	{
		wprintf(L"Usage: %s <drive letter> <project name>\n", argv[0]);
		return 0;
	}

	DOKAN_OPTIONS options;
	DOKAN_OPERATIONS operations;

	ZeroMemory(&options, sizeof(DOKAN_OPTIONS));
	options.Version = DOKAN_VERSION;
	options.ThreadCount = 0; // use default
	options.MountPoint = argv[1];
	options.Options = DOKAN_OPTION_KEEP_ALIVE;

	ZeroMemory(&operations, sizeof(DOKAN_OPERATIONS));
	operations.CreateFile = WendyCreateFile;
	operations.OpenDirectory = WendyOpenDirectory;
	operations.Cleanup = WendyCleanup;
	operations.FindFiles = WendyFindFiles;

	//char projectName[500];
	//WideCharToMultiByte(CP_UTF8, 0, argv[2], -1, projectName, 500, NULL, NULL);
	proxy = new ProjectProxy();

	int result = DokanMain(&options, &operations);

	delete proxy;

	return result;
}

#endif // _WIN32

<|endoftext|>


<commit_before>#include <stingray/toolkit/StringUtils.h>

namespace stingray
{

	std::string Utf8ToLower(const std::string& str)
	{
		std::string result;
		for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
		{
			if (*it >= 'A' && *it <= 'Z')
				result.push_back(*it + 'a' - 'A');
			else if ((u8)*it == 0xD0)
			{
				u16 c0 = (u8)*it & 0x1F;
				TOOLKIT_CHECK(++it != str.end(), "Malformed utf-8!");
				u16 c = (c0 << 6) | ((u8)*it & 0x3F);
				if (c >= 0x410 && c <= 0x42F)
					c += 0x20;
				result.push_back(0xD0 | (c >> 6));
				result.push_back((c & 0x3F) | 0x80);
			}
			else
				result.push_back(*it);
		}
		return result;
	}

}
<commit_msg>reserve space for result in utf8tolower<commit_after>#include <stingray/toolkit/StringUtils.h>

namespace stingray
{

	std::string Utf8ToLower(const std::string& str)
	{
		std::string result;
		result.reserve(str.size());
		for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
		{
			if (*it >= 'A' && *it <= 'Z')
				result.push_back(*it + 'a' - 'A');
			else if ((u8)*it == 0xD0)
			{
				u16 c0 = (u8)*it & 0x1F;
				TOOLKIT_CHECK(++it != str.end(), "Malformed utf-8!");
				u16 c = (c0 << 6) | ((u8)*it & 0x3F);
				if (c >= 0x410 && c <= 0x42F)
					c += 0x20;
				result.push_back(0xD0 | (c >> 6));
				result.push_back((c & 0x3F) | 0x80);
			}
			else
				result.push_back(*it);
		}
		return result;
	}

}
<|endoftext|>


<commit_before>/* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
 *
 *  Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 *
 * @file        client-echo.cpp
 * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
 * @version     1.0
 * @brief       Key implementation.
 */
#include <openssl/bio.h>
#include <openssl/pem.h>

#include <client-key-impl.h>

namespace {

const char PEM_FIRST_CHAR = '-';

} // namespace anonymous

namespace CKM {

KeyImpl::KeyImpl()
  : m_type(KeyType::KEY_NONE)
{}

KeyImpl::KeyImpl(const KeyImpl &second)
  : m_type(second.m_type)
  , m_key(second.m_key)
{}

KeyImpl::KeyImpl(KeyImpl &&second)
  : m_type(second.m_type)
  , m_key(std::move(second.m_key))
{}

KeyImpl& KeyImpl::operator=(const KeyImpl &second) {
    m_type = second.m_type;
    m_key = second.m_key;
    return *this;
}

KeyImpl& KeyImpl::operator=(KeyImpl &&second) {
    m_type = std::move(second.m_type);
    m_key = std::move(second.m_key);
    return *this;
}

KeyImpl::KeyImpl(const RawBuffer &data, KeyType type, const std::string &password)
  : m_type(KeyType::KEY_NONE)
{
    int size = 0;
    RSA *rsa = NULL;
    char *pass = NULL;
    std::string passtmp(password);

    if (!passtmp.empty()) {
        pass = const_cast<char *>(passtmp.c_str());
    }

    if (data[0] == PEM_FIRST_CHAR && type == KeyType::KEY_RSA_PUBLIC) {
        BIO *bio = BIO_new(BIO_s_mem());
        BIO_write(bio, data.data(), data.size());
        rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, pass);
        BIO_free_all(bio);
    } else if (data[0] == PEM_FIRST_CHAR && type == KeyType::KEY_RSA_PRIVATE) {
        BIO *bio = BIO_new(BIO_s_mem());
        BIO_write(bio, data.data(), data.size());
        rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, pass);
        BIO_free_all(bio);
    } else if (type == KeyType::KEY_RSA_PUBLIC) {
        const unsigned char *p = (const unsigned char*)data.data();
        rsa = d2i_RSA_PUBKEY(NULL, &p, data.size());
    } else if (type == KeyType::KEY_RSA_PRIVATE) {
        BIO *bio = BIO_new(BIO_s_mem());
        BIO_write(bio, data.data(), data.size());
        rsa = d2i_RSAPrivateKey_bio(bio, NULL);
        BIO_free_all(bio);
    } else {
        return;
    }

    if (!rsa)
        return;

    BIO *bio = BIO_new(BIO_s_mem());

    if (type == KeyType::KEY_RSA_PUBLIC) {
        size = i2d_RSAPublicKey_bio(bio, rsa);
    } else {
        size = i2d_RSAPrivateKey_bio(bio, rsa);
    }

    if (size > 0) {
        m_key.resize(size);
        BIO_read(bio, m_key.data(), m_key.size());
        m_type = type;
    }
    BIO_free_all(bio);
}

//void KeyImpl::Serialize(IStream &stream) const {
//    Serialization::Serialize(stream, static_cast<int>(m_type));
//    Serialization::Serialize(stream, m_key);
//}

KeyImpl::~KeyImpl(){}

} // namespace CKM

<commit_msg>Bug fix<commit_after>/* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
 *
 *  Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License
 *
 *
 * @file        client-echo.cpp
 * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
 * @version     1.0
 * @brief       Key implementation.
 */
#include <openssl/bio.h>
#include <openssl/pem.h>

#include <client-key-impl.h>

namespace {

const char PEM_FIRST_CHAR = '-';

} // namespace anonymous

namespace CKM {

KeyImpl::KeyImpl()
  : m_type(KeyType::KEY_NONE)
{}

KeyImpl::KeyImpl(const KeyImpl &second)
  : m_type(second.m_type)
  , m_key(second.m_key)
{}

KeyImpl::KeyImpl(KeyImpl &&second)
  : m_type(second.m_type)
  , m_key(std::move(second.m_key))
{}

KeyImpl& KeyImpl::operator=(const KeyImpl &second) {
    m_type = second.m_type;
    m_key = second.m_key;
    return *this;
}

KeyImpl& KeyImpl::operator=(KeyImpl &&second) {
    m_type = std::move(second.m_type);
    m_key = std::move(second.m_key);
    return *this;
}

KeyImpl::KeyImpl(const RawBuffer &data, KeyType type, const std::string &password)
  : m_type(KeyType::KEY_NONE)
{
    int ret = 0;
    RSA *rsa = NULL;
    char *pass = NULL;
    std::string passtmp(password);

    if (!passtmp.empty()) {
        pass = const_cast<char *>(passtmp.c_str());
    }

    if (data[0] == PEM_FIRST_CHAR && type == KeyType::KEY_RSA_PUBLIC) {
        BIO *bio = BIO_new(BIO_s_mem());
        BIO_write(bio, data.data(), data.size());
        rsa = PEM_read_bio_RSA_PUBKEY(bio, NULL, NULL, pass);
        BIO_free_all(bio);
    } else if (data[0] == PEM_FIRST_CHAR && type == KeyType::KEY_RSA_PRIVATE) {
        BIO *bio = BIO_new(BIO_s_mem());
        BIO_write(bio, data.data(), data.size());
        rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, NULL, pass);
        BIO_free_all(bio);
    } else if (type == KeyType::KEY_RSA_PUBLIC) {
        const unsigned char *p = (const unsigned char*)data.data();
        rsa = d2i_RSA_PUBKEY(NULL, &p, data.size());
    } else if (type == KeyType::KEY_RSA_PRIVATE) {
        BIO *bio = BIO_new(BIO_s_mem());
        BIO_write(bio, data.data(), data.size());
        rsa = d2i_RSAPrivateKey_bio(bio, NULL);
        BIO_free_all(bio);
    } else {
        return;
    }

    if (!rsa)
        return;

    BIO *bio = BIO_new(BIO_s_mem());

    if (type == KeyType::KEY_RSA_PUBLIC) {
        ret = i2d_RSAPublicKey_bio(bio, rsa);
    } else {
        ret = i2d_RSAPrivateKey_bio(bio, rsa);
    }

    if (ret > 0) {
        m_key.resize(data.size());
        BIO_read(bio, m_key.data(), data.size());
        m_type = type;
    }
    BIO_free_all(bio);
}

//void KeyImpl::Serialize(IStream &stream) const {
//    Serialization::Serialize(stream, static_cast<int>(m_type));
//    Serialization::Serialize(stream, m_key);
//}

KeyImpl::~KeyImpl(){}

} // namespace CKM

<|endoftext|>


<commit_before>// Copyright (c) 2011-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sync.h"

#include "util.h"
#include "state.h"

#include <boost/foreach.hpp>

#ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
    LogPrintf("LOCKCONTENTION: %s\n", pszName);
    LogPrintf("Locker: %s:%d\n", pszFile, nLine);
}
#endif /* DEBUG_LOCKCONTENTION */

#ifdef DEBUG_LOCKORDER
//
// Early deadlock detection.
// Problem being solved:
//    Thread 1 locks  A, then B, then C
//    Thread 2 locks  D, then C, then A
//     --> may result in deadlock between the two threads, depending on when they run.
// Solution implemented here:
// Keep track of pairs of locks: (A before B), (A before C), etc.
// Complain if any thread tries to lock in a different order.
//

struct CLockLocation
{
    CLockLocation(const char* pszName, const char* pszFile, int nLine)
    {
        mutexName = pszName;
        sourceFile = pszFile;
        sourceLine = nLine;
    }

    std::string ToString() const
    {
        return mutexName+"  "+sourceFile+":"+itostr(sourceLine);
    }

    std::string MutexName() const { return mutexName; }

private:
    std::string mutexName;
    std::string sourceFile;
    int sourceLine;
};

typedef std::vector< std::pair<void*, CLockLocation> > LockStack;

static boost::mutex dd_mutex;
static std::map<std::pair<void*, void*>, LockStack> lockorders;
static boost::thread_specific_ptr<LockStack> lockstack;

static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
    LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
    LogPrintf("Previous lock order was:\n");
    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2)
    {
        if (i.first == mismatch.first) LogPrintf(" (1)");
        if (i.first == mismatch.second) LogPrintf(" (2)");
        LogPrintf(" %s\n", i.second.ToString().c_str());
    }
    LogPrintf("Current lock order is:\n");
    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1)
    {
        if (i.first == mismatch.first) LogPrintf(" (1)");
        if (i.first == mismatch.second) LogPrintf(" (2)");
        LogPrintf(" %s\n", i.second.ToString().c_str());
    }
}

static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
{
    if (lockstack.get() == NULL)
        lockstack.reset(new LockStack);

    if (fDebug) LogPrintf("Locking: %s\n", locklocation.ToString().c_str());
    dd_mutex.lock();

    (*lockstack).push_back(std::make_pair(c, locklocation));

    if (!fTry) {
        BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack)) {
            if (i.first == c) break;

            std::pair<void*, void*> p1 = std::make_pair(i.first, c);
            if (lockorders.count(p1))
                continue;
            lockorders[p1] = (*lockstack);

            std::pair<void*, void*> p2 = std::make_pair(c, i.first);
            if (lockorders.count(p2))
            {
                potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
                break;
            }
        }
    }
    dd_mutex.unlock();
}

static void pop_lock()
{
    if (fDebug)
    {
        const CLockLocation& locklocation = (*lockstack).rbegin()->second;
        LogPrintf("Unlocked: %s\n", locklocation.ToString().c_str());
    }
    dd_mutex.lock();
    (*lockstack).pop_back();
    dd_mutex.unlock();
}

void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
    push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry);
}

void LeaveCritical()
{
    pop_lock();
}

std::string LocksHeld()
{
    std::string result;
    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack)
        result += i.second.ToString() + std::string("\n");
    return result;
}

void AssertLockHeldInternal(const char *pszName, const char* pszFile, int nLine, void *cs)
{
    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack)
        if (i.first == cs) return;
    fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s",
            pszName, pszFile, nLine, LocksHeld().c_str());
    abort();
}

#endif /* DEBUG_LOCKORDER */
<commit_msg>Log not open at this point<commit_after>// Copyright (c) 2011-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sync.h"

#include "util.h"
#include "state.h"

#include <boost/foreach.hpp>

#ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
    LogPrintf("LOCKCONTENTION: %s\n", pszName);
    LogPrintf("Locker: %s:%d\n", pszFile, nLine);
}
#endif /* DEBUG_LOCKCONTENTION */

#ifdef DEBUG_LOCKORDER
//
// Early deadlock detection.
// Problem being solved:
//    Thread 1 locks  A, then B, then C
//    Thread 2 locks  D, then C, then A
//     --> may result in deadlock between the two threads, depending on when they run.
// Solution implemented here:
// Keep track of pairs of locks: (A before B), (A before C), etc.
// Complain if any thread tries to lock in a different order.
//

struct CLockLocation
{
    CLockLocation(const char* pszName, const char* pszFile, int nLine)
    {
        mutexName = pszName;
        sourceFile = pszFile;
        sourceLine = nLine;
    }

    std::string ToString() const
    {
        return mutexName+"  "+sourceFile+":"+itostr(sourceLine);
    }

    std::string MutexName() const { return mutexName; }

private:
    std::string mutexName;
    std::string sourceFile;
    int sourceLine;
};

typedef std::vector< std::pair<void*, CLockLocation> > LockStack;

static boost::mutex dd_mutex;
static std::map<std::pair<void*, void*>, LockStack> lockorders;
static boost::thread_specific_ptr<LockStack> lockstack;

static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
    LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
    LogPrintf("Previous lock order was:\n");
    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s2)
    {
        if (i.first == mismatch.first) LogPrintf(" (1)");
        if (i.first == mismatch.second) LogPrintf(" (2)");
        LogPrintf(" %s\n", i.second.ToString().c_str());
    }
    LogPrintf("Current lock order is:\n");
    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, s1)
    {
        if (i.first == mismatch.first) LogPrintf(" (1)");
        if (i.first == mismatch.second) LogPrintf(" (2)");
        LogPrintf(" %s\n", i.second.ToString().c_str());
    }
}

static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
{
    if (lockstack.get() == NULL)
        lockstack.reset(new LockStack);

//    if (fDebug) LogPrintf("Locking: %s\n", locklocation.ToString().c_str()); Logfile not yet open - causes freeze
    dd_mutex.lock();

    (*lockstack).push_back(std::make_pair(c, locklocation));

    if (!fTry) {
        BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)& i, (*lockstack)) {
            if (i.first == c) break;

            std::pair<void*, void*> p1 = std::make_pair(i.first, c);
            if (lockorders.count(p1))
                continue;
            lockorders[p1] = (*lockstack);

            std::pair<void*, void*> p2 = std::make_pair(c, i.first);
            if (lockorders.count(p2))
            {
                potential_deadlock_detected(p1, lockorders[p2], lockorders[p1]);
                break;
            }
        }
    }
    dd_mutex.unlock();
}

static void pop_lock()
{
/*
    if (fDebug)
    {
        const CLockLocation& locklocation = (*lockstack).rbegin()->second;
        LogPrintf("Unlocked: %s\n", locklocation.ToString().c_str());
    }
*/
    dd_mutex.lock();
    (*lockstack).pop_back();
    dd_mutex.unlock();
}

void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
    push_lock(cs, CLockLocation(pszName, pszFile, nLine), fTry);
}

void LeaveCritical()
{
    pop_lock();
}

std::string LocksHeld()
{
    std::string result;
    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack)
        result += i.second.ToString() + std::string("\n");
    return result;
}

void AssertLockHeldInternal(const char *pszName, const char* pszFile, int nLine, void *cs)
{
    BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack)
        if (i.first == cs) return;
    fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s",
            pszName, pszFile, nLine, LocksHeld().c_str());
    abort();
}

#endif /* DEBUG_LOCKORDER */
<|endoftext|>


<commit_before>#include <vector>
#include <string>
#include <sstream>
#include <pcl/io/pcd_io.h>
#include <pcl/common/time.h>
#include <pcl/console/parse.h>
#include <pcl/search/kdtree.h>
#include <pcl/search/brute_force.h>

using namespace std;

int
main (int argc, char ** argv)
{
  if (argc < 2)
  {
    pcl::console::print_info ("Syntax is: %s -pcd <pcd-file> (-radius <radius> | -knn <k> )\n", argv[0]);
    return (1);
  }

  string pcd_path;
  bool use_pcd_file = pcl::console::find_switch (argc, argv, "-pcd");
  if (use_pcd_file)
    pcl::console::parse (argc, argv, "-pcd", pcd_path);

  float radius = -1;
  if (pcl::console::find_switch (argc, argv, "-radius"))
    pcl::console::parse (argc, argv, "-radius", radius);

  int k = -1;
  if (pcl::console::find_switch (argc, argv, "-knn"))
    pcl::console::parse (argc, argv, "-knn", k);

  if ((radius * k) > 0)
  {
    cout << "please specify only one of the options -radius and -knn" << endl;
    return (1);
  }

  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);

  if (use_pcd_file)
    pcl::io::loadPCDFile (pcd_path, *cloud);
  else
  {
    cloud->resize (1000000);
    for (unsigned idx = 0; idx < cloud->size (); ++idx)
    {
      (*cloud)[idx].x = (double)rand () / (double)RAND_MAX;
      (*cloud)[idx].y = (double)rand () / (double)RAND_MAX;
      (*cloud)[idx].z = (double)rand () / (double)RAND_MAX;
    }
  }

  pcl::search::KdTree<pcl::PointXYZRGB> tree;
  pcl::PointXYZRGB query;
  query.x = 0.5;
  query.y = 0.5;
  query.z = 0.5;

  vector<int> kd_indices;
  vector<float> kd_distances;

  double start, stop;
  double kd_setup;
  double kd_search;
  double bf_setup;
  double bf_search;

  start = pcl::getTime ();
  tree.setInputCloud (cloud);
  stop = pcl::getTime ();
  cout << "setting up kd tree: " << (kd_setup = stop - start) << endl;
  start = pcl::getTime ();
  tree.nearestKSearchT (query, k, kd_indices, kd_distances);
  stop = pcl::getTime ();
  cout << "single search with kd tree; " << (kd_search = stop - start) << " :: " << kd_indices[0] << " , " << kd_distances [0] << endl;

  vector<int> bf_indices;
  vector<float> bf_distances;
  pcl::search::BruteForce<pcl::PointXYZRGB> brute_force;
  start = pcl::getTime ();
  brute_force.setInputCloud (cloud);
  stop = pcl::getTime ();
  cout << "setting up brute force search: " << (bf_setup = stop - start) << endl;

  start = pcl::getTime ();
  brute_force.nearestKSearchT (query, k, bf_indices, bf_distances);
  stop = pcl::getTime ();
  cout << "single search with brute force; " << (bf_search = stop - start) << " :: " << bf_indices[0] << " , " << bf_distances [0] << endl;
  cout << "amortization after searches: " << (kd_setup - bf_setup) / (bf_search - kd_search) << endl;

  if (kd_indices.size () != bf_indices.size ())
  {
    cerr << "number does not match" << endl;
  }
  else
  {
    for (unsigned idx = 0; idx < kd_indices.size (); ++idx)
    {
      if (kd_indices[idx] != bf_indices[idx] && kd_distances[idx] != bf_distances[idx])
      {
        cerr << "results do not match: " << idx << " nearest neighbor: "
                << kd_indices[idx] << " with distance: " << kd_distances[idx] << " vs. "
                << bf_indices[idx] << " with distance: " << bf_distances[idx] << endl;
      }
    }
  }
  return (0);
}
<commit_msg>added radius search to test<commit_after>#include <vector>
#include <string>
#include <sstream>
#include <pcl/io/pcd_io.h>
#include <pcl/common/time.h>
#include <pcl/console/parse.h>
#include <pcl/search/kdtree.h>
#include <pcl/search/brute_force.h>

using namespace std;

int
main (int argc, char ** argv)
{
  if (argc < 2)
  {
    pcl::console::print_info ("Syntax is: %s [-pcd <pcd-file>] (-radius <radius> [-knn <k>] | -knn <k> )\n", argv[0]);
    return (1);
  }

  string pcd_path;
  bool use_pcd_file = pcl::console::find_switch (argc, argv, "-pcd");
  if (use_pcd_file)
    pcl::console::parse (argc, argv, "-pcd", pcd_path);

  float radius = -1;
  if (pcl::console::find_switch (argc, argv, "-radius"))
    pcl::console::parse (argc, argv, "-radius", radius);

  int k = -1;
  if (pcl::console::find_switch (argc, argv, "-knn"))
    pcl::console::parse (argc, argv, "-knn", k);

  if (radius < 0 && k < 0)
  {
    cout << "please specify at least one of the options -radius and -knn" << endl;
    return (1);
  }

  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);

  if (use_pcd_file)
    pcl::io::loadPCDFile (pcd_path, *cloud);
  else
  {
    cloud->resize (1000000);
    for (unsigned idx = 0; idx < cloud->size (); ++idx)
    {
      (*cloud)[idx].x = (double)rand () / (double)RAND_MAX;
      (*cloud)[idx].y = (double)rand () / (double)RAND_MAX;
      (*cloud)[idx].z = (double)rand () / (double)RAND_MAX;
    }
  }

  pcl::search::KdTree<pcl::PointXYZRGB> tree;
  pcl::PointXYZRGB query;
  query.x = 0.5;
  query.y = 0.5;
  query.z = 0.5;

  vector<int> kd_indices;
  vector<float> kd_distances;
  vector<int> bf_indices;
  vector<float> bf_distances;

  double start, stop;
  double kd_setup;
  double kd_search;
  double bf_setup;
  double bf_search;

  if (k > 0)
  {
    start = pcl::getTime ();
    tree.setInputCloud (cloud);
    stop = pcl::getTime ();
    cout << "setting up kd tree: " << (kd_setup = stop - start) << endl;

    start = pcl::getTime ();
    tree.nearestKSearchT (query, k, kd_indices, kd_distances);
    stop = pcl::getTime ();
    cout << "single search with kd tree; " << (kd_search = stop - start) << " :: " << kd_indices[0] << " , " << kd_distances [0] << endl;

    pcl::search::BruteForce<pcl::PointXYZRGB> brute_force;
    start = pcl::getTime ();
    brute_force.setInputCloud (cloud);
    stop = pcl::getTime ();
    cout << "setting up brute force search: " << (bf_setup = stop - start) << endl;

    start = pcl::getTime ();
    brute_force.nearestKSearchT (query, k, bf_indices, bf_distances);
    stop = pcl::getTime ();
    cout << "single search with brute force; " << (bf_search = stop - start) << " :: " << bf_indices[0] << " , " << bf_distances [0] << endl;
    cout << "amortization after searches: " << (kd_setup - bf_setup) / (bf_search - kd_search) << endl;
  }
  else
  {
    start = pcl::getTime ();
    tree.setInputCloud (cloud);
    stop = pcl::getTime ();
    cout << "setting up kd tree: " << (kd_setup = stop - start) << endl;

    start = pcl::getTime ();
    tree.radiusSearch (query, radius, kd_indices, kd_distances, k);
    stop = pcl::getTime ();
    cout << "single search with kd tree; " << (kd_search = stop - start) << " :: " << kd_indices[0] << " , " << kd_distances [0] << endl;

    pcl::search::BruteForce<pcl::PointXYZRGB> brute_force;
    start = pcl::getTime ();
    brute_force.setInputCloud (cloud);
    stop = pcl::getTime ();
    cout << "setting up brute force search: " << (bf_setup = stop - start) << endl;

    start = pcl::getTime ();
    brute_force.radiusSearch (query, radius, bf_indices, bf_distances, k);
    stop = pcl::getTime ();
    cout << "single search with brute force; " << (bf_search = stop - start) << " :: " << bf_indices[0] << " , " << bf_distances [0] << endl;
    cout << "amortization after searches: " << (kd_setup - bf_setup) / (bf_search - kd_search) << endl;
  }

  if (kd_indices.size () != bf_indices.size ())
  {
    cerr << "size of results do not match " <<kd_indices.size () << " vs. " << bf_indices.size () << endl;
  }
  else
  {
    cerr << "size of result: " <<kd_indices.size () << endl;
    for (unsigned idx = 0; idx < kd_indices.size (); ++idx)
    {
      if (kd_indices[idx] != bf_indices[idx] && kd_distances[idx] != bf_distances[idx])
      {
        cerr << "results do not match: " << idx << " nearest neighbor: "
                << kd_indices[idx] << " with distance: " << kd_distances[idx] << " vs. "
                << bf_indices[idx] << " with distance: " << bf_distances[idx] << endl;
      }
    }
  }
  return (0);
}
<|endoftext|>