<commit_before>#include "certs.hpp"
#include "root_path.hpp"

#include <pxp-agent/configuration.hpp>

#include "horsewhisperer/horsewhisperer.h"

#include <leatherman/util/scope_exit.hpp>

#define LEATHERMAN_LOGGING_NAMESPACE "puppetlabs.pxp_agent.configuration_test"
#include <leatherman/logging/logging.hpp>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

#include <catch.hpp>

#include <string>
#include <vector>

namespace PXPAgent {

namespace fs = boost::filesystem;
namespace HW = HorseWhisperer;
namespace lth_log = leatherman::logging;
namespace lth_util = leatherman::util;

static const std::string CONFIG { std::string { PXP_AGENT_ROOT_PATH }
                                  + "/lib/tests/resources/config/empty-pxp-agent.cfg" };
static const std::string TEST_BROKER_WS_URI { "wss:///test_c_t_h_u_n_broker" };
static const std::string CA { getCaPath() };
static const std::string CERT { getCertPath() };
static const std::string KEY { getKeyPath() };
static const std::string MODULES_DIR { std::string { PXP_AGENT_ROOT_PATH }
                                       + "/lib/tests/resources/test_modules/" };
static const std::string SPOOL_DIR { std::string { PXP_AGENT_ROOT_PATH }
                                     + "/lib/tests/resources/test_spool" };

static const char* ARGV[] = {
    "test-command",
    "--config-file", CONFIG.data(),
    "--broker-ws-uri", TEST_BROKER_WS_URI.data(),
    "--ssl-ca-cert", CA.data(),
    "--ssl-cert", CERT.data(),
    "--ssl-key", KEY.data(),
    "--modules-dir", MODULES_DIR.data(),
    "--spool-dir", SPOOL_DIR.data(),
    "--foreground=true",
    nullptr };
static const int ARGC = 16;

static void configureTest() {
    if (!fs::exists(SPOOL_DIR) && !fs::create_directories(SPOOL_DIR)) {
        FAIL("Failed to create the results directory");
    }
    Configuration::Instance().initialize(
        [](std::vector<std::string>) {
            return EXIT_SUCCESS;
        });
    // Configuration::Instance().initialize(ARGC, const_cast<char**>(ARGV), false);
}

static void resetTest() {
    if (fs::exists(SPOOL_DIR)) {
        fs::remove_all(SPOOL_DIR);
    }
}

TEST_CASE("Configuration - metatest", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };

    SECTION("Metatest - can initialize Configuration") {
        resetTest();
        REQUIRE_NOTHROW(configureTest());
    }

    SECTION("Metatest - we can inject CL options into HorseWhisperer") {
        configureTest();
        Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
        REQUIRE(HW::GetFlag<std::string>("ssl-ca-cert") == CA);
        REQUIRE(HW::GetFlag<std::string>("modules-dir") == MODULES_DIR);
        REQUIRE(HW::GetFlag<std::string>("spool-dir") == SPOOL_DIR);
    }
}

TEST_CASE("Configuration::initialize()", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };

    SECTION("No error when starting without setting a function") {
        REQUIRE_NOTHROW(HW::Start());
    }

    SECTION("It does set HorseWhisperer's action correctly") {
        Configuration::Instance().initialize(
            [] (std::vector<std::string> arg) -> int {
                return 42;
            });
        const char* args[] = { "pxp-agent", "start", nullptr };
        HW::Parse(2, const_cast<char**>(args));

        REQUIRE(HW::Start() == 42);
    }
}

TEST_CASE("Configuration::set", "[configuration]") {
    configureTest();
    Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
    Configuration::Instance().validate();
    lth_util::scope_exit config_cleaner { resetTest };

    SECTION("can set a known flag to a valid value") {
        REQUIRE_NOTHROW(Configuration::Instance().set<std::string>("ssl-ca-cert",
                                                                   "value"));
    }

    SECTION("set a flag correctly") {
        Configuration::Instance().set<std::string>("ssl-ca-cert", "value");
        REQUIRE(HW::GetFlag<std::string>("ssl-ca-cert") == "value");
    }

    SECTION("throw when setting an unknown flag") {
        REQUIRE_THROWS_AS(Configuration::Instance()
                                .set<int>("tentacle_spawning_interval_s", 45),
                          Configuration::Error);
    }

    SECTION("throw when setting a known flag to an invalid value") {
        HW::DefineGlobalFlag<int>("num_tentacles",
                                  "number of spawn tentacles",
                                  8,
                                  [](int v) {
                                      if (v != 8) {
                                          throw HW::flag_validation_error { "bad!" };
                                      }
                                  });

        // The only valid number of tentacles is 8
        REQUIRE_THROWS_AS(Configuration::Instance().set<int>("num_tentacles", 42),
                          Configuration::Error);
        REQUIRE_NOTHROW(Configuration::Instance().set<int>("num_tentacles", 8));
    }
}

TEST_CASE("Configuration::get", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };
    configureTest();

    SECTION("When options were not parsed and validated yet") {
        SECTION("can get a defined flag") {
            REQUIRE_NOTHROW(Configuration::Instance().get<std::string>("ssl-ca-cert"));
        }

        SECTION("return the default value correctly") {
            REQUIRE(Configuration::Instance().get<std::string>("spool-dir")
                    == DEFAULT_SPOOL_DIR);
        }

        SECTION("throw a Configuration::Error if the flag is unknown") {
            REQUIRE_THROWS_AS(
                Configuration::Instance().get<std::string>("dont_exist"),
                Configuration::Error);
        }
    }

    SECTION("After parsing and validating options") {
        configureTest();
        Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
        Configuration::Instance().validate();

        SECTION("can get a defined flag") {
            REQUIRE_NOTHROW(Configuration::Instance().get<std::string>("ssl-ca-cert"));
        }

        SECTION("return the default value if the flag was not set") {
            // NB: ignoring --foreground in ARGV since argc is set to 15
            configureTest();
            Configuration::Instance().parseOptions(15, const_cast<char**>(ARGV));
            Configuration::Instance().validate();

            REQUIRE(Configuration::Instance().get<bool>("foreground") == false);
        }

        SECTION("return the correct value after the flag has been set") {
            Configuration::Instance().set<std::string>("spool-dir", "/fake/dir");
            REQUIRE(Configuration::Instance().get<std::string>("spool-dir")
                    == "/fake/dir");
        }

        SECTION("throw a Configuration::Error if the flag is unknown") {
            REQUIRE_THROWS_AS(
                Configuration::Instance().get<std::string>("still_dont_exist"),
                Configuration::Error);
        }
    }
}

TEST_CASE("Configuration::validate", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };
    configureTest();
    Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));

    SECTION("it throws an UnconfiguredError when the broker WebSocket URI is undefined") {
        HW::SetFlag<std::string>("broker-ws-uri", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when the broker WebSocket URi is invlaid") {
        HW::SetFlag<std::string>("broker-ws-uri", "ws://");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError ssl-ca-cert is undefined") {
        HW::SetFlag<std::string>("ssl-ca-cert", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-ca-cert file cannot be found") {
        HW::SetFlag<std::string>("ssl-ca-cert", "/fake/file");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-cert is undefined") {
        HW::SetFlag<std::string>("ssl-cert", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-cert file cannot be found") {
        HW::SetFlag<std::string>("ssl-cert", "/fake/file");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-key is undefined") {
        HW::SetFlag<std::string>("ssl-key", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-key file cannot be found") {
        HW::SetFlag<std::string>("ssl-key", "/fake/file");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it fails when spool-dir is empty") {
        HW::SetFlag<std::string>("spool-dir", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::Error);
    }
}

TEST_CASE("Configuration::setupLogging", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };
    configureTest();
    Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
    Configuration::Instance().validate();

    SECTION("it sets log level to info by default") {
        Configuration::Instance().setupLogging();
        REQUIRE(lth_log::get_level() == lth_log::log_level::info);
    }

#ifndef _WIN32
    SECTION("it sets log level to none if foreground is unflagged and logfile "
            "is set to stdout") {
        Configuration::Instance().set<bool>("foreground", false);
        Configuration::Instance().set<std::string>("logfile", "-");
        Configuration::Instance().setupLogging();

        REQUIRE(lth_log::get_level() == lth_log::log_level::none);
    }
#endif
}

}  // namespace PXPAgent
<commit_msg>(maint) Don't assume the directories existent in unit tests<commit_after>#include "certs.hpp"
#include "root_path.hpp"

#include <pxp-agent/configuration.hpp>

#include "horsewhisperer/horsewhisperer.h"

#include <leatherman/util/scope_exit.hpp>

#define LEATHERMAN_LOGGING_NAMESPACE "puppetlabs.pxp_agent.configuration_test"
#include <leatherman/logging/logging.hpp>

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>

#include <catch.hpp>

#include <string>
#include <vector>

namespace PXPAgent {

namespace fs = boost::filesystem;
namespace HW = HorseWhisperer;
namespace lth_log = leatherman::logging;
namespace lth_util = leatherman::util;

static const std::string CONFIG { std::string { PXP_AGENT_ROOT_PATH }
                                  + "/lib/tests/resources/config/empty-pxp-agent.cfg" };
static const std::string TEST_BROKER_WS_URI { "wss:///test_c_t_h_u_n_broker" };
static const std::string CA { getCaPath() };
static const std::string CERT { getCertPath() };
static const std::string KEY { getKeyPath() };
static const std::string MODULES_DIR { std::string { PXP_AGENT_ROOT_PATH }
                                       + "/lib/tests/resources/test_modules/" };
static const std::string SPOOL_DIR { std::string { PXP_AGENT_ROOT_PATH }
                                     + "/lib/tests/resources/test_spool" };

static const char* ARGV[] = {
    "test-command",
    "--config-file", CONFIG.data(),
    "--broker-ws-uri", TEST_BROKER_WS_URI.data(),
    "--ssl-ca-cert", CA.data(),
    "--ssl-cert", CERT.data(),
    "--ssl-key", KEY.data(),
    "--modules-dir", MODULES_DIR.data(),
    "--spool-dir", SPOOL_DIR.data(),
    "--foreground=true",
    nullptr };
static const int ARGC = 16;

static void configureTest() {
    if (!fs::exists(SPOOL_DIR) && !fs::create_directories(SPOOL_DIR)) {
        FAIL("Failed to create the results directory");
    }
    Configuration::Instance().initialize(
        [](std::vector<std::string>) {
            return EXIT_SUCCESS;
        });
    // Configuration::Instance().initialize(ARGC, const_cast<char**>(ARGV), false);
}

static void resetTest() {
    if (fs::exists(SPOOL_DIR)) {
        fs::remove_all(SPOOL_DIR);
    }
}

TEST_CASE("Configuration - metatest", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };

    SECTION("Metatest - can initialize Configuration") {
        resetTest();
        REQUIRE_NOTHROW(configureTest());
    }

    SECTION("Metatest - we can inject CL options into HorseWhisperer") {
        configureTest();
        Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
        REQUIRE(HW::GetFlag<std::string>("ssl-ca-cert") == CA);
        REQUIRE(HW::GetFlag<std::string>("modules-dir") == MODULES_DIR);
        REQUIRE(HW::GetFlag<std::string>("spool-dir") == SPOOL_DIR);
    }
}

TEST_CASE("Configuration::initialize()", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };

    SECTION("No error when starting without setting a function") {
        REQUIRE_NOTHROW(HW::Start());
    }

    SECTION("It does set HorseWhisperer's action correctly") {
        Configuration::Instance().initialize(
            [] (std::vector<std::string> arg) -> int {
                return 42;
            });
        const char* args[] = { "pxp-agent", "start", nullptr };
        HW::Parse(2, const_cast<char**>(args));

        REQUIRE(HW::Start() == 42);
    }
}

TEST_CASE("Configuration::set", "[configuration]") {
    configureTest();
    Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
    Configuration::Instance().validate();
    lth_util::scope_exit config_cleaner { resetTest };

    SECTION("can set a known flag to a valid value") {
        REQUIRE_NOTHROW(Configuration::Instance().set<std::string>("ssl-ca-cert",
                                                                   "value"));
    }

    SECTION("set a flag correctly") {
        Configuration::Instance().set<std::string>("ssl-ca-cert", "value");
        REQUIRE(HW::GetFlag<std::string>("ssl-ca-cert") == "value");
    }

    SECTION("throw when setting an unknown flag") {
        REQUIRE_THROWS_AS(Configuration::Instance()
                                .set<int>("tentacle_spawning_interval_s", 45),
                          Configuration::Error);
    }

    SECTION("throw when setting a known flag to an invalid value") {
        HW::DefineGlobalFlag<int>("num_tentacles",
                                  "number of spawn tentacles",
                                  8,
                                  [](int v) {
                                      if (v != 8) {
                                          throw HW::flag_validation_error { "bad!" };
                                      }
                                  });

        // The only valid number of tentacles is 8
        REQUIRE_THROWS_AS(Configuration::Instance().set<int>("num_tentacles", 42),
                          Configuration::Error);
        REQUIRE_NOTHROW(Configuration::Instance().set<int>("num_tentacles", 8));
    }
}

TEST_CASE("Configuration::get", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };
    configureTest();

    SECTION("When options were not parsed and validated yet") {
        SECTION("can get a defined flag") {
            REQUIRE_NOTHROW(Configuration::Instance().get<std::string>("ssl-ca-cert"));
        }

        SECTION("return the default value correctly") {
            REQUIRE(Configuration::Instance().get<std::string>("spool-dir")
                    == DEFAULT_SPOOL_DIR);
        }

        SECTION("throw a Configuration::Error if the flag is unknown") {
            REQUIRE_THROWS_AS(
                Configuration::Instance().get<std::string>("dont_exist"),
                Configuration::Error);
        }
    }

    SECTION("After parsing and validating options") {
        configureTest();

        SECTION("can get a defined flag") {
            Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
            Configuration::Instance().validate();
            REQUIRE_NOTHROW(Configuration::Instance().get<std::string>("ssl-ca-cert"));
        }

        SECTION("return the default value if the flag was not set") {
            // NB: ignoring --foreground in ARGV since argc is set to 15
            Configuration::Instance().parseOptions(15, const_cast<char**>(ARGV));
#ifndef _WIN32
            HW::SetFlag<std::string>("pidfile", SPOOL_DIR + "/test.pid");
#endif
            Configuration::Instance().validate();

            REQUIRE(Configuration::Instance().get<bool>("foreground") == false);
        }

        SECTION("return the correct value after the flag has been set") {
            Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
            Configuration::Instance().validate();
            Configuration::Instance().set<std::string>("spool-dir", "/fake/dir");
            REQUIRE(Configuration::Instance().get<std::string>("spool-dir")
                    == "/fake/dir");
        }

        SECTION("throw a Configuration::Error if the flag is unknown") {
            Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
            Configuration::Instance().validate();
            REQUIRE_THROWS_AS(
                Configuration::Instance().get<std::string>("still_dont_exist"),
                Configuration::Error);
        }
    }
}

TEST_CASE("Configuration::validate", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };
    configureTest();
    Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));

    SECTION("it throws an UnconfiguredError when the broker WebSocket URI is undefined") {
        HW::SetFlag<std::string>("broker-ws-uri", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when the broker WebSocket URi is invlaid") {
        HW::SetFlag<std::string>("broker-ws-uri", "ws://");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError ssl-ca-cert is undefined") {
        HW::SetFlag<std::string>("ssl-ca-cert", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-ca-cert file cannot be found") {
        HW::SetFlag<std::string>("ssl-ca-cert", "/fake/file");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-cert is undefined") {
        HW::SetFlag<std::string>("ssl-cert", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-cert file cannot be found") {
        HW::SetFlag<std::string>("ssl-cert", "/fake/file");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-key is undefined") {
        HW::SetFlag<std::string>("ssl-key", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it throws an UnconfiguredError when ssl-key file cannot be found") {
        HW::SetFlag<std::string>("ssl-key", "/fake/file");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::UnconfiguredError);
    }

    SECTION("it fails when spool-dir is empty") {
        HW::SetFlag<std::string>("spool-dir", "");
        REQUIRE_THROWS_AS(Configuration::Instance().validate(),
                          Configuration::Error);
    }
}

TEST_CASE("Configuration::setupLogging", "[configuration]") {
    lth_util::scope_exit config_cleaner { resetTest };
    configureTest();
    Configuration::Instance().parseOptions(ARGC, const_cast<char**>(ARGV));
    Configuration::Instance().validate();

#ifndef _WIN32
    SECTION("it sets log level to info by default") {
        // NOTE(ale): we cannot test this on Windows because it won't
        // allow us to delete the SPOOL_DIR while test.log is open
        Configuration::Instance().set<std::string>("logfile", SPOOL_DIR + "/test.log");
        Configuration::Instance().setupLogging();
        REQUIRE(lth_log::get_level() == lth_log::log_level::info);
    }

    SECTION("it sets log level to none if foreground is unflagged and logfile "
            "is set to stdout") {
        Configuration::Instance().set<bool>("foreground", false);
        Configuration::Instance().set<std::string>("logfile", "-");
        Configuration::Instance().setupLogging();

        REQUIRE(lth_log::get_level() == lth_log::log_level::none);
    }
#endif
}

}  // namespace PXPAgent
<|endoftext|>


<commit_before>/*
  This file is part of c-ethash.

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

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

  You should have received a copy of the GNU General Public License
  along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ethash_cuda_miner.cpp
* @author Genoil <jw@meneer.net>
* @date 2015
*/

#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <assert.h>
#include <queue>
#include <random>
#include <atomic>
#include <sstream>
#include <vector>
#include <chrono>
#include <thread>
#include <libethash/util.h>
#include <libethash/ethash.h>
#include <libethash/internal.h>
#include <cuda_runtime.h>
#include "ethash_cuda_miner.h"
#include "ethash_cuda_miner_kernel_globals.h"

#define ETHASH_BYTES 32

// workaround lame platforms

#undef min
#undef max

using namespace std;

unsigned const ethash_cuda_miner::c_defaultBlockSize = 128;
unsigned const ethash_cuda_miner::c_defaultGridSize = 2048; // * CL_DEFAULT_LOCAL_WORK_SIZE
unsigned const ethash_cuda_miner::c_defaultNumStreams = 2;

#if defined(_WIN32)
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString);
static std::atomic_flag s_logSpin = ATOMIC_FLAG_INIT;
#define ETHCUDA_LOG(_contents) \
	do \
			{ \
		std::stringstream ss; \
		ss << _contents; \
						while (s_logSpin.test_and_set(std::memory_order_acquire)) {} \
		OutputDebugStringA(ss.str().c_str()); \
		cerr << ss.str() << endl << flush; \
		s_logSpin.clear(std::memory_order_release); \
			} while (false)
#else
#define ETHCUDA_LOG(_contents) cout << "[CUDA]:" << _contents << endl
#endif

ethash_cuda_miner::search_hook::~search_hook() {}

ethash_cuda_miner::ethash_cuda_miner()
{
}

std::string ethash_cuda_miner::platform_info(unsigned _deviceId)
{
	int runtime_version;
	int device_count;

	device_count = getNumDevices();

	if (device_count == 0)
		return std::string();

	CUDA_SAFE_CALL(cudaRuntimeGetVersion(&runtime_version));

	// use selected default device
	int device_num = std::min<int>((int)_deviceId, device_count - 1);
	cudaDeviceProp device_props;

	CUDA_SAFE_CALL(cudaGetDeviceProperties(&device_props, device_num));

	char platform[5];
	int version_major = runtime_version / 1000;
	int version_minor = (runtime_version - (version_major * 1000)) / 10;
	sprintf(platform, "%d.%d", version_major, version_minor);

	char compute[5];
	sprintf(compute, "%d.%d", device_props.major, device_props.minor);

	return "{ \"platform\": \"CUDA " + std::string(platform) + "\", \"device\": \"" + std::string(device_props.name) + "\", \"version\": \"Compute " + std::string(compute) + "\" }";
}

unsigned ethash_cuda_miner::getNumDevices()
{
	int device_count;
	CUDA_SAFE_CALL(cudaGetDeviceCount(&device_count));
	return device_count;
}

bool ethash_cuda_miner::configureGPU(
	int *	 _devices,
	unsigned _blockSize,
	unsigned _gridSize,
	unsigned _numStreams,
	unsigned _extraGPUMemory,
	unsigned _scheduleFlag,
	uint64_t _currentBlock
	)
{
	try
	{
		s_blockSize = _blockSize;
		s_gridSize = _gridSize;
		s_extraRequiredGPUMem = _extraGPUMemory;
		s_numStreams = _numStreams;
		s_scheduleFlag = _scheduleFlag;

		// by default let's only consider the DAG of the first epoch
		uint64_t dagSize = ethash_get_datasize(_currentBlock);
		uint64_t requiredSize = dagSize + _extraGPUMemory;
		unsigned devicesCount = getNumDevices();
		for (unsigned int i = 0; i < devicesCount; i++)
		{
			if (_devices[i] != -1)
			{
				cudaDeviceProp props;
				CUDA_SAFE_CALL(cudaGetDeviceProperties(&props, _devices[i]));
				if (props.totalGlobalMem >= requiredSize)
				{
					ETHCUDA_LOG(
						"Found suitable CUDA device [" << string(props.name)
						<< "] with " << props.totalGlobalMem << " bytes of GPU memory"
						);
				}
				else
				{
					ETHCUDA_LOG(
						"CUDA device " << string(props.name)
						<< " has insufficient GPU memory." << to_string(props.totalGlobalMem) <<
						" bytes of memory found < " << to_string(requiredSize) << " bytes of memory required"
						);
					return false;
				}
			}
		}
		return true;
	}
	catch (runtime_error)
	{
		return false;
	}
}

unsigned ethash_cuda_miner::s_extraRequiredGPUMem;
unsigned ethash_cuda_miner::s_blockSize = ethash_cuda_miner::c_defaultBlockSize;
unsigned ethash_cuda_miner::s_gridSize = ethash_cuda_miner::c_defaultGridSize;
unsigned ethash_cuda_miner::s_numStreams = ethash_cuda_miner::c_defaultNumStreams;
unsigned ethash_cuda_miner::s_scheduleFlag = 0;

void ethash_cuda_miner::listDevices()
{
	string outString = "\nListing CUDA devices.\nFORMAT: [deviceID] deviceName\n";
	for (unsigned int i = 0; i < getNumDevices(); i++)
	{
		cudaDeviceProp props;
		CUDA_SAFE_CALL(cudaGetDeviceProperties(&props, i));

		outString += "[" + to_string(i) + "] " + string(props.name) + "\n";
		outString += "\tCompute version: " + to_string(props.major) + "." + to_string(props.minor) + "\n";
		outString += "\tcudaDeviceProp::totalGlobalMem: " + to_string(props.totalGlobalMem) + "\n";
	}
	ETHCUDA_LOG(outString);
}

void ethash_cuda_miner::finish()
{
	CUDA_SAFE_CALL(cudaDeviceReset());
}

bool ethash_cuda_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned _deviceId)
{
	try
	{
		int device_count = getNumDevices();

		if (device_count == 0)
			return false;

		// use selected device
		int device_num = std::min<int>((int)_deviceId, device_count - 1);

		cudaDeviceProp device_props;
		CUDA_SAFE_CALL(cudaGetDeviceProperties(&device_props, device_num));

		cout << "Using device: " << device_props.name << " (Compute " << device_props.major << "." << device_props.minor << ")" << endl;

		CUDA_SAFE_CALL(cudaSetDevice(device_num));
		CUDA_SAFE_CALL(cudaDeviceReset());
		CUDA_SAFE_CALL(cudaSetDeviceFlags(s_scheduleFlag));
		CUDA_SAFE_CALL(cudaDeviceSetCacheConfig(cudaFuncCachePreferL1));

		m_search_buf = new volatile uint32_t *[s_numStreams];
		m_streams = new cudaStream_t[s_numStreams];

		uint32_t dagSize128 = (unsigned)(_dagSize / ETHASH_MIX_BYTES);

		// create buffer for dag
		hash128_t * dag;
		CUDA_SAFE_CALL(cudaMalloc(reinterpret_cast<void**>(&dag), _dagSize));
		// copy dag to CPU.
		CUDA_SAFE_CALL(cudaMemcpy(reinterpret_cast<void*>(dag), _dag, _dagSize, cudaMemcpyHostToDevice));

		// create mining buffers
		for (unsigned i = 0; i != s_numStreams; ++i)
		{
			CUDA_SAFE_CALL(cudaMallocHost(&m_search_buf[i], SEARCH_RESULT_BUFFER_SIZE * sizeof(uint32_t)));
			CUDA_SAFE_CALL(cudaStreamCreate(&m_streams[i]));
		}
		set_constants(dag, dagSize128);
		memset(&m_current_header, 0, sizeof(hash32_t));
		m_current_target = 0;
		m_current_nonce = 0;
		m_current_index = 0;
		return true;
	}
	catch (runtime_error)
	{
		return false;
	}
}

void ethash_cuda_miner::search(uint8_t const* header, uint64_t target, search_hook& hook)
{
	bool initialize = false;
	bool exit = false;
	if (memcmp(&m_current_header, header, sizeof(hash32_t)))
	{
		m_current_header = *reinterpret_cast<hash32_t const *>(header);
		set_header(m_current_header);
		initialize = true;
	}
	if (m_current_target != target)
	{
		m_current_target = target;
		set_target(m_current_target);
		initialize = true;
	}
	if (initialize)
	{
		random_device engine;
		m_current_nonce = uniform_int_distribution<uint64_t>()(engine);
		m_current_index = 0;
		CUDA_SAFE_CALL(cudaDeviceSynchronize());
		for (unsigned int i = 0; i < s_numStreams; i++)
			m_search_buf[i][0] = 0;
	}
	uint64_t batch_size = s_gridSize * s_blockSize;
	for (; !exit; m_current_index++, m_current_nonce += batch_size)
	{
		unsigned int stream_index = m_current_index % s_numStreams;
		cudaStream_t stream = m_streams[stream_index];
		volatile uint32_t* buffer = m_search_buf[stream_index];
		uint32_t found_count = 0;
		uint64_t nonces[SEARCH_RESULT_BUFFER_SIZE - 1];
		uint64_t nonce_base = m_current_nonce - s_numStreams * batch_size;
		if (m_current_index >= s_numStreams)
		{
			CUDA_SAFE_CALL(cudaStreamSynchronize(stream));
			found_count = buffer[0];
			if (found_count)
				buffer[0] = 0;
			for (unsigned int j = 0; j < found_count; j++)
				nonces[j] = nonce_base + buffer[j + 1];
		}
		run_ethash_search(s_gridSize, s_blockSize, stream, buffer, m_current_nonce);
		if (m_current_index >= s_numStreams)
		{
			exit = found_count && hook.found(nonces, found_count);
			exit |= hook.searched(nonce_base, batch_size);
		}
	}
}

<commit_msg>routed CUDA_LOG to stdout instead of stderr<commit_after>/*
  This file is part of c-ethash.

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

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

  You should have received a copy of the GNU General Public License
  along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ethash_cuda_miner.cpp
* @author Genoil <jw@meneer.net>
* @date 2015
*/

#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <assert.h>
#include <queue>
#include <random>
#include <atomic>
#include <sstream>
#include <vector>
#include <chrono>
#include <thread>
#include <libethash/util.h>
#include <libethash/ethash.h>
#include <libethash/internal.h>
#include <cuda_runtime.h>
#include "ethash_cuda_miner.h"
#include "ethash_cuda_miner_kernel_globals.h"

#define ETHASH_BYTES 32

// workaround lame platforms

#undef min
#undef max

using namespace std;

unsigned const ethash_cuda_miner::c_defaultBlockSize = 128;
unsigned const ethash_cuda_miner::c_defaultGridSize = 2048; // * CL_DEFAULT_LOCAL_WORK_SIZE
unsigned const ethash_cuda_miner::c_defaultNumStreams = 2;

#if defined(_WIN32)
extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString);
static std::atomic_flag s_logSpin = ATOMIC_FLAG_INIT;
#define ETHCUDA_LOG(_contents) \
	do \
			{ \
		std::stringstream ss; \
		ss << _contents; \
						while (s_logSpin.test_and_set(std::memory_order_acquire)) {} \
		OutputDebugStringA(ss.str().c_str()); \
		cout << ss.str() << endl << flush; \
		s_logSpin.clear(std::memory_order_release); \
			} while (false)
#else
#define ETHCUDA_LOG(_contents) cout << "[CUDA]:" << _contents << endl
#endif

ethash_cuda_miner::search_hook::~search_hook() {}

ethash_cuda_miner::ethash_cuda_miner()
{
}

std::string ethash_cuda_miner::platform_info(unsigned _deviceId)
{
	int runtime_version;
	int device_count;

	device_count = getNumDevices();

	if (device_count == 0)
		return std::string();

	CUDA_SAFE_CALL(cudaRuntimeGetVersion(&runtime_version));

	// use selected default device
	int device_num = std::min<int>((int)_deviceId, device_count - 1);
	cudaDeviceProp device_props;

	CUDA_SAFE_CALL(cudaGetDeviceProperties(&device_props, device_num));

	char platform[5];
	int version_major = runtime_version / 1000;
	int version_minor = (runtime_version - (version_major * 1000)) / 10;
	sprintf(platform, "%d.%d", version_major, version_minor);

	char compute[5];
	sprintf(compute, "%d.%d", device_props.major, device_props.minor);

	return "{ \"platform\": \"CUDA " + std::string(platform) + "\", \"device\": \"" + std::string(device_props.name) + "\", \"version\": \"Compute " + std::string(compute) + "\" }";
}

unsigned ethash_cuda_miner::getNumDevices()
{
	int device_count;
	CUDA_SAFE_CALL(cudaGetDeviceCount(&device_count));
	return device_count;
}

bool ethash_cuda_miner::configureGPU(
	int *	 _devices,
	unsigned _blockSize,
	unsigned _gridSize,
	unsigned _numStreams,
	unsigned _extraGPUMemory,
	unsigned _scheduleFlag,
	uint64_t _currentBlock
	)
{
	try
	{
		s_blockSize = _blockSize;
		s_gridSize = _gridSize;
		s_extraRequiredGPUMem = _extraGPUMemory;
		s_numStreams = _numStreams;
		s_scheduleFlag = _scheduleFlag;

		// by default let's only consider the DAG of the first epoch
		uint64_t dagSize = ethash_get_datasize(_currentBlock);
		uint64_t requiredSize = dagSize + _extraGPUMemory;
		unsigned devicesCount = getNumDevices();
		for (unsigned int i = 0; i < devicesCount; i++)
		{
			if (_devices[i] != -1)
			{
				cudaDeviceProp props;
				CUDA_SAFE_CALL(cudaGetDeviceProperties(&props, _devices[i]));
				if (props.totalGlobalMem >= requiredSize)
				{
					ETHCUDA_LOG(
						"Found suitable CUDA device [" << string(props.name)
						<< "] with " << props.totalGlobalMem << " bytes of GPU memory"
						);
				}
				else
				{
					ETHCUDA_LOG(
						"CUDA device " << string(props.name)
						<< " has insufficient GPU memory." << to_string(props.totalGlobalMem) <<
						" bytes of memory found < " << to_string(requiredSize) << " bytes of memory required"
						);
					return false;
				}
			}
		}
		return true;
	}
	catch (runtime_error)
	{
		return false;
	}
}

unsigned ethash_cuda_miner::s_extraRequiredGPUMem;
unsigned ethash_cuda_miner::s_blockSize = ethash_cuda_miner::c_defaultBlockSize;
unsigned ethash_cuda_miner::s_gridSize = ethash_cuda_miner::c_defaultGridSize;
unsigned ethash_cuda_miner::s_numStreams = ethash_cuda_miner::c_defaultNumStreams;
unsigned ethash_cuda_miner::s_scheduleFlag = 0;

void ethash_cuda_miner::listDevices()
{
	string outString = "\nListing CUDA devices.\nFORMAT: [deviceID] deviceName\n";
	for (unsigned int i = 0; i < getNumDevices(); i++)
	{
		cudaDeviceProp props;
		CUDA_SAFE_CALL(cudaGetDeviceProperties(&props, i));

		outString += "[" + to_string(i) + "] " + string(props.name) + "\n";
		outString += "\tCompute version: " + to_string(props.major) + "." + to_string(props.minor) + "\n";
		outString += "\tcudaDeviceProp::totalGlobalMem: " + to_string(props.totalGlobalMem) + "\n";
	}
	ETHCUDA_LOG(outString);
}

void ethash_cuda_miner::finish()
{
	CUDA_SAFE_CALL(cudaDeviceReset());
}

bool ethash_cuda_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned _deviceId)
{
	try
	{
		int device_count = getNumDevices();

		if (device_count == 0)
			return false;

		// use selected device
		int device_num = std::min<int>((int)_deviceId, device_count - 1);

		cudaDeviceProp device_props;
		CUDA_SAFE_CALL(cudaGetDeviceProperties(&device_props, device_num));

		cout << "Using device: " << device_props.name << " (Compute " << device_props.major << "." << device_props.minor << ")" << endl;

		CUDA_SAFE_CALL(cudaSetDevice(device_num));
		CUDA_SAFE_CALL(cudaDeviceReset());
		CUDA_SAFE_CALL(cudaSetDeviceFlags(s_scheduleFlag));
		CUDA_SAFE_CALL(cudaDeviceSetCacheConfig(cudaFuncCachePreferL1));

		m_search_buf = new volatile uint32_t *[s_numStreams];
		m_streams = new cudaStream_t[s_numStreams];

		uint32_t dagSize128 = (unsigned)(_dagSize / ETHASH_MIX_BYTES);

		// create buffer for dag
		hash128_t * dag;
		CUDA_SAFE_CALL(cudaMalloc(reinterpret_cast<void**>(&dag), _dagSize));
		// copy dag to CPU.
		CUDA_SAFE_CALL(cudaMemcpy(reinterpret_cast<void*>(dag), _dag, _dagSize, cudaMemcpyHostToDevice));

		// create mining buffers
		for (unsigned i = 0; i != s_numStreams; ++i)
		{
			CUDA_SAFE_CALL(cudaMallocHost(&m_search_buf[i], SEARCH_RESULT_BUFFER_SIZE * sizeof(uint32_t)));
			CUDA_SAFE_CALL(cudaStreamCreate(&m_streams[i]));
		}
		set_constants(dag, dagSize128);
		memset(&m_current_header, 0, sizeof(hash32_t));
		m_current_target = 0;
		m_current_nonce = 0;
		m_current_index = 0;
		return true;
	}
	catch (runtime_error)
	{
		return false;
	}
}

void ethash_cuda_miner::search(uint8_t const* header, uint64_t target, search_hook& hook)
{
	bool initialize = false;
	bool exit = false;
	if (memcmp(&m_current_header, header, sizeof(hash32_t)))
	{
		m_current_header = *reinterpret_cast<hash32_t const *>(header);
		set_header(m_current_header);
		initialize = true;
	}
	if (m_current_target != target)
	{
		m_current_target = target;
		set_target(m_current_target);
		initialize = true;
	}
	if (initialize)
	{
		random_device engine;
		m_current_nonce = uniform_int_distribution<uint64_t>()(engine);
		m_current_index = 0;
		CUDA_SAFE_CALL(cudaDeviceSynchronize());
		for (unsigned int i = 0; i < s_numStreams; i++)
			m_search_buf[i][0] = 0;
	}
	uint64_t batch_size = s_gridSize * s_blockSize;
	for (; !exit; m_current_index++, m_current_nonce += batch_size)
	{
		unsigned int stream_index = m_current_index % s_numStreams;
		cudaStream_t stream = m_streams[stream_index];
		volatile uint32_t* buffer = m_search_buf[stream_index];
		uint32_t found_count = 0;
		uint64_t nonces[SEARCH_RESULT_BUFFER_SIZE - 1];
		uint64_t nonce_base = m_current_nonce - s_numStreams * batch_size;
		if (m_current_index >= s_numStreams)
		{
			CUDA_SAFE_CALL(cudaStreamSynchronize(stream));
			found_count = buffer[0];
			if (found_count)
				buffer[0] = 0;
			for (unsigned int j = 0; j < found_count; j++)
				nonces[j] = nonce_base + buffer[j + 1];
		}
		run_ethash_search(s_gridSize, s_blockSize, stream, buffer, m_current_nonce);
		if (m_current_index >= s_numStreams)
		{
			exit = found_count && hook.found(nonces, found_count);
			exit |= hook.searched(nonce_base, batch_size);
		}
	}
}

<|endoftext|>


<commit_before><commit_msg>GUIでsetting.iniに変換モードを保存するようにした<commit_after><|endoftext|>


<commit_before>#include <eosio/chain/webassembly/wavm.hpp>
#include <eosio/chain/wasm_eosio_constraints.hpp>
#include <eosio/chain/wasm_eosio_injection.hpp>
#include <eosio/chain/apply_context.hpp>
#include <eosio/chain/exceptions.hpp>

#include "IR/Module.h"
#include "Platform/Platform.h"
#include "WAST/WAST.h"
#include "IR/Operators.h"
#include "IR/Validate.h"
#include "Runtime/Linker.h"
#include "Runtime/Intrinsics.h"

#include <vector>
#include <iterator>

using namespace IR;
using namespace Runtime;

namespace eosio { namespace chain { namespace webassembly { namespace wavm {

running_instance_context the_running_instance_context;

namespace detail {
struct wavm_runtime_initializer {
   wavm_runtime_initializer() {
      Runtime::init();
   }
};

using live_module_ref = std::list<ObjectInstance*>::iterator;

struct wavm_live_modules {
   live_module_ref add_live_module(ModuleInstance* module_instance) {
      return live_modules.insert(live_modules.begin(), asObject(module_instance));
   }

   void remove_live_module(live_module_ref it) {
      live_modules.erase(it);
      run_wavm_garbage_collection();
   }

   void run_wavm_garbage_collection() {
      //need to pass in a mutable list of root objects we want the garbage collector to retain
      std::vector<ObjectInstance*> root;
      std::copy(live_modules.begin(), live_modules.end(), std::back_inserter(root));
      Runtime::freeUnreferencedObjects(std::move(root));
   }

   std::list<ObjectInstance*> live_modules;
};

static wavm_live_modules the_wavm_live_modules;

}

class wavm_instantiated_module : public wasm_instantiated_module_interface {
   public:
      wavm_instantiated_module(ModuleInstance* instance, std::unique_ptr<Module> module, std::vector<uint8_t> initial_mem) :
         _initial_memory(initial_mem),
         _instance(instance),
         _module_ref(detail::the_wavm_live_modules.add_live_module(instance))
      {
         //The memory instance is reused across all wavm_instantiated_modules, but for wasm instances
         // that didn't declare "memory", getDefaultMemory() won't see it. It would also be possible
         // to say something like if(module->memories.size()) here I believe
         if(getDefaultMemory(_instance))
            _initial_memory_config = module->memories.defs.at(0).type;
      }

      ~wavm_instantiated_module() {
         detail::the_wavm_live_modules.remove_live_module(_module_ref);
      }

      void apply(apply_context& context) override {
         vector<Value> args = {Value(context.get_receiver().to_uint64_t()),
	                            Value(context.get_action().account.to_uint64_t()),
                               Value(context.get_action().name.to_uint64_t())};

         call("apply", args, context);
      }

   private:
      void call(const string &entry_point, const vector <Value> &args, apply_context &context) {
         try {
            FunctionInstance* call = asFunctionNullable(getInstanceExport(_instance,entry_point));
            if( !call )
               return;

            EOS_ASSERT( getFunctionType(call)->parameters.size() == args.size(), wasm_exception, "" );

            //The memory instance is reused across all wavm_instantiated_modules, but for wasm instances
            // that didn't declare "memory", getDefaultMemory() won't see it
            MemoryInstance* default_mem = getDefaultMemory(_instance);
            if(default_mem) {
               //reset memory resizes the sandbox'ed memory to the module's init memory size and then
               // (effectively) memzeros it all
               resetMemory(default_mem, _initial_memory_config);

               char* memstart = &memoryRef<char>(getDefaultMemory(_instance), 0);
               memcpy(memstart, _initial_memory.data(), _initial_memory.size());
            }

            the_running_instance_context.memory = default_mem;
            the_running_instance_context.apply_ctx = &context;

            resetGlobalInstances(_instance);
            runInstanceStartFunc(_instance);
            Runtime::invokeFunction(call,args);
         } catch( const wasm_exit& e ) {
         } catch( const Runtime::Exception& e ) {
             FC_THROW_EXCEPTION(wasm_execution_error,
                         "cause: ${cause}\n${callstack}",
                         ("cause", string(describeExceptionCause(e.cause)))
                         ("callstack", e.callStack));
         } FC_CAPTURE_AND_RETHROW()
      }

      std::vector<uint8_t>     _initial_memory;
      //naked pointer because ModuleInstance is opaque
      //_instance is deleted via WAVM's object garbage collection when wavm_rutime is deleted
      ModuleInstance*          _instance;
      detail::live_module_ref  _module_ref;
      MemoryType               _initial_memory_config;
};

wavm_runtime::wavm_runtime() {
   static detail::wavm_runtime_initializer the_wavm_runtime_initializer;
}

wavm_runtime::~wavm_runtime() {
}

bool wavm_runtime::inject_module(IR::Module& module) {
   wasm_injections::wasm_binary_injection<true> injector(module);
   injector.inject();
   return true;
}

std::unique_ptr<wasm_instantiated_module_interface> wavm_runtime::instantiate_module(const char* code_bytes, size_t code_size, std::vector<uint8_t> initial_memory,
                                                                                const digest_type& code_hash, const uint8_t& vm_type, const uint8_t& vm_version) {
   std::unique_ptr<Module> module = std::make_unique<Module>();
   try {
      Serialization::MemoryInputStream stream((const U8*)code_bytes, code_size);
      WASM::serialize(stream, *module);
   } catch(const Serialization::FatalSerializationException& e) {
      EOS_ASSERT(false, wasm_serialization_error, e.message.c_str());
   } catch(const IR::ValidationException& e) {
      EOS_ASSERT(false, wasm_serialization_error, e.message.c_str());
   }

   try {
      eosio::chain::webassembly::common::root_resolver resolver;
      LinkResult link_result = linkModule(*module, resolver);
      ModuleInstance *instance = instantiateModule(*module, std::move(link_result.resolvedImports));
      EOS_ASSERT(instance != nullptr, wasm_exception, "Fail to Instantiate WAVM Module");

      return std::make_unique<wavm_instantiated_module>(instance, std::move(module), initial_memory);
   }
   catch(const Runtime::Exception& e) {
      EOS_THROW(wasm_execution_error, "Failed to stand up WAVM instance: ${m}", ("m", describeExceptionCause(e.cause)));
   }
}

void wavm_runtime::immediately_exit_currently_running_module() {
#ifdef _WIN32
   throw wasm_exit();
#else
   Platform::immediately_exit(nullptr);
#endif
}

}}}}
<commit_msg>remove lingering wavm runtime file that escaped the first purge<commit_after><|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2013 lailongwei<lailongwei@126.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "llbc/common/Export.h"

#include "llbc.h" //! Include llbc header to use Startup/Cleanup function.
#include "llbc/application/Application.h"

__LLBC_INTERNAL_NS_BEGIN

static const LLBC_NS LLBC_String __cfgSuffix_Ini = ".ini";
static const LLBC_NS LLBC_String __cfgSuffix_Xml = ".xml";
static const LLBC_NS LLBC_String __cfgSuffix_Property = ".cfg";
static const LLBC_NS LLBC_String __cfgSuffix_Unknown = "";

__LLBC_INTERNAL_NS_END

__LLBC_NS_BEGIN

const LLBC_String &LLBC_ApplicationConfigType::GetConfigSuffix(int cfgType)
{
    if (cfgType == Ini)
        return LLBC_INL_NS __cfgSuffix_Ini;
    else if (cfgType == Xml)
        return LLBC_INL_NS __cfgSuffix_Xml;
    else if (cfgType == Property)
        return LLBC_INL_NS __cfgSuffix_Property;
    else
        return LLBC_INL_NS __cfgSuffix_Unknown;
}

auto LLBC_ApplicationConfigType::GetConfigType(const LLBC_String &cfgSuffix) -> ENUM
{
    auto nmlCfgSuffix = cfgSuffix.strip().tolower();
    if (nmlCfgSuffix == LLBC_INL_NS __cfgSuffix_Ini)
        return Ini;
    else if (nmlCfgSuffix == LLBC_INL_NS __cfgSuffix_Xml)
        return Xml;
    else if (nmlCfgSuffix == LLBC_INL_NS __cfgSuffix_Property)
        return Property;
    else
        return End;
}

LLBC_Application *LLBC_Application::_thisApp = nullptr;

LLBC_Application::LLBC_Application()
: _name()

, _llbcLibStartupInApp(false)

, _loadingCfg(false)
, _cfgType(LLBC_ApplicationConfigType::End)

, _services(*LLBC_ServiceMgrSingleton)

, _started(false)

{
    LLBC_DoIf(_thisApp == nullptr, _thisApp = this);
}

LLBC_Application::~LLBC_Application()
{
    Stop();
}

int LLBC_Application::SetConfigPath(const LLBC_String &cfgPath)
{
    // Check config file exists or not.
    LLBC_SetErrAndReturnIf(!LLBC_File::Exists(cfgPath), LLBC_ERROR_ARG, LLBC_FAILED);

    // Get config type.
    const auto ext = LLBC_Directory::SplitExt(cfgPath)[1];
    const auto cfgType = LLBC_ApplicationConfigType::GetConfigType(ext);
    LLBC_SetErrAndReturnIf(cfgType < LLBC_ApplicationConfigType::Begin ||
                                cfgType >= LLBC_ApplicationConfigType::End,
                           LLBC_ERROR_NOT_SUPPORT,
                           LLBC_FAILED);

    // Check _started flag.
    LLBC_SetErrAndReturnIf(_started, LLBC_ERROR_NOT_ALLOW, LLBC_FAILED);

    // Lock and check _started flag again.
    LLBC_LockGuard guard(_cfgLock);
    LLBC_SetErrAndReturnIf(_started, LLBC_ERROR_NOT_ALLOW, LLBC_FAILED);

    // Save config info.
    _cfgType = cfgType;
    _cfgPath = cfgPath;

    return LLBC_OK;
}

int LLBC_Application::ReloadConfig(bool callEvMeth)
{
    // Not allow reload config if application not start.
    LLBC_SetErrAndReturnIf(!_started, LLBC_ERROR_NOT_ALLOW, LLBC_FAILED);

    // Lock and check again.
    LLBC_LockGuard guard(_cfgLock);
    LLBC_SetErrAndReturnIf(!_started, LLBC_ERROR_NOT_ALLOW, LLBC_FAILED);

    // Config not found when application start.
    LLBC_SetErrAndReturnIf(_cfgType == LLBC_ApplicationConfigType::End, LLBC_ERROR_NOT_FOUND, LLBC_FAILED);

    // Reload.
    LLBC_ReturnIf(LoadConfig(false) != LLBC_OK, LLBC_FAILED);

    // Call config reload event method.
    if (callEvMeth)
    {
        OnConfigReload();
        for (auto &svcPair : this->_services.GetAllIndexedByIdServices())
            svcPair.second->ProcessAppConfigReload();
    }

    return LLBC_OK;
}

int LLBC_Application::Start(const LLBC_String &name, int argc, char *argv[])
{
    // Multi application check.
    LLBC_SetErrAndReturnIf(_thisApp != this, LLBC_ERROR_REPEAT, LLBC_FAILED);
    // Application name check.
    LLBC_SetErrAndReturnIf(name.empty(), LLBC_ERROR_INVALID, LLBC_FAILED);

    // Reentry check.
    LLBC_SetErrAndReturnIf(_started, LLBC_ERROR_REENTRY, LLBC_FAILED);

    // Parse startup arguments.
    LLBC_ReturnIf(_startArgs.Parse(argc, argv) != LLBC_OK, LLBC_FAILED);

    // Startup llbc library.
    int ret = LLBC_FAILED;
    _llbcLibStartupInApp = true;
    if (LLBC_Startup() != LLBC_OK)
    {
        LLBC_ReturnIf(LLBC_Errno != LLBC_ERROR_REENTRY, LLBC_FAILED);

        _llbcLibStartupInApp = false;
        LLBC_SetLastError(LLBC_OK);
    }

    // Set name.
    _name = name;

    // Define app start failed defer.
    LLBC_Defer(if (ret != LLBC_OK) {
        _cfgPath.clear();
        _cfgType = LLBC_ApplicationConfigType::End;
        _propCfg.RemoveAllProperties();
        _nonPropCfg.BecomeNil();

        _name.clear();

        LLBC_DoIf(_llbcLibStartupInApp, LLBC_Cleanup(); _llbcLibStartupInApp = false);
    });

    // Locate config path.
    if (_cfgPath.empty())
    {
        int intCfgType;
        if (!(_cfgPath = LocateConfigPath(name, intCfgType)).empty())
            _cfgType = static_cast<LLBC_ApplicationConfigType::ENUM>(intCfgType);
    }

    // Load config.
    LLBC_ReturnIf(!_cfgPath.empty() && LoadConfig(true) != LLBC_OK, LLBC_FAILED);

    // Call OnStart event method.
    while (true)
    {
        bool startFinished = true;

        LLBC_SetLastError(LLBC_ERROR_SUCCESS);
        if (OnStart(argc, argv, startFinished) != LLBC_OK)
        {
            if (LLBC_GetLastError() == LLBC_ERROR_SUCCESS)
                LLBC_SetLastError(LLBC_ERROR_UNKNOWN);
            return LLBC_FAILED;
        }

        LLBC_BreakIf(startFinished);
        LLBC_Sleep(LLBC_CFG_APP_TRY_START_INTERVAL);
    }

    // Mark started.
    _started = true;

    // Return ok.
    ret = LLBC_OK;
    return ret;
}

void LLBC_Application::Stop()
{
    if (!_started)
        return;

    while (true)
    {
        bool stopFinished = true;
        OnStop(stopFinished);
        LLBC_BreakIf(stopFinished);

        LLBC_Sleep(LLBC_CFG_APP_TRY_STOP_INTERVAL);
    }

    _services.StopAll(true);

    _cfgPath.clear();
    _cfgType = LLBC_ApplicationConfigType::End;
    _propCfg.RemoveAllProperties();
    _nonPropCfg.BecomeNil();

    LLBC_DoIf(_llbcLibStartupInApp, LLBC_Cleanup(); _llbcLibStartupInApp = false);

    _started = false;
}

LLBC_String LLBC_Application::LocateConfigPath(const LLBC_String &appName, int &cfgType)
{
    // Application config directory locate order:
    // -> <cwd>
    // -> <module file directory>
    //    -> <cwd>/Config -> config -> Conf -> conf -> Cfg -> cfg
    //    -> <module file directory>/Config -> config -> Conf -> conf -> Cfg -> cfg
    //       -> <cwd>/../Config -> config -> Conf -> conf -> Cfg -> cfg
    //       -> <module file directory>/../Config -> config -> Conf -> conf -> Cfg -> cfg
    //          -> <cwd>/..
    //          -> <module file directory>/..
    //
    // Application config filename locate order:
    // -> app_name
    //    -> stripped _d/_debug suffix app_name
    //       -> executable_name
    //          -> stripped _d/_debug suffix executable_name
    //
    // Application config type locate order:
    // -> .ini
    //    -> .xml
    //       -> .cfg

    // Build config directories.
    // -> <cwd>
    //    -> <module file directory>
    LLBC_Strings cfgFileDirs{LLBC_Directory::CurDir(),
                             LLBC_Directory::ModuleFileDir()};

    // -> <cwd>/xxxxx
    //    -> <module file directory/xxxxx
    const char *interDirs[] = {"Config", "config", "Conf", "conf", "Cfg", "cfg"};
    for (auto &cfgDir : interDirs)
        cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::CurDir(), cfgDir));
    for (auto &cfgDir : interDirs)
        cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::ModuleFileDir(), cfgDir));
    // -> <cwd>/../xxxxx
    //    -> <module file directory>/../xxxxx
    for (auto &cfgDir : interDirs)
        cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::CurDir(), "..", cfgDir));
    for (auto &cfgDir : interDirs)
        cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::ModuleFileDir(), "..", cfgDir));
    // -> <cwd>/..
    //    -> <module file directory>/..
    cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::CurDir(), ".."));
    cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::ModuleFileDir(), ".."));

    // Building config filenames.
    LLBC_Strings cfgFileNames{appName};
    if (appName.endswith("_d") || appName.endswith("_debug"))
              cfgFileNames.push_back(appName.substr(0, appName.rfind('_')));
    const auto execName = LLBC_Directory::SplitExt(LLBC_Directory::BaseName(LLBC_Directory::ModuleFileName()))[0];
    cfgFileNames.push_back(execName);
    if (execName.endswith("_d") || execName.endswith("_debug"))
        cfgFileNames.push_back(execName.substr(0, execName.rfind('_')));

    // Execute config file locate.
    for (auto &cfgFileDir : cfgFileDirs)
    {
        for (auto &cfgFileName : cfgFileNames)
        {
            for (cfgType = LLBC_ApplicationConfigType::Begin;
                 cfgType != LLBC_ApplicationConfigType::End;
                 ++cfgType)
            {
                const auto cfgPath = LLBC_Directory::Join(
                    cfgFileDir, cfgFileName + LLBC_ApplicationConfigType::GetConfigSuffix(cfgType));
                LLBC_ReturnIf(LLBC_File::Exists(cfgPath), cfgPath);
            }
        }
    }

    LLBC_SetLastError(LLBC_ERROR_NOT_FOUND);
    return "";
}

int LLBC_Application::LoadConfig(bool lock)
{
    // Reentry check.
    LLBC_SetErrAndReturnIf(_loadingCfg, LLBC_ERROR_REENTRY, LLBC_FAILED);

    // Lock and check again.
    if (lock)
        _cfgLock.Lock();
    LLBC_Defer(if (lock) _cfgLock.Unlock());
    LLBC_SetErrAndReturnIf(_loadingCfg, LLBC_ERROR_REENTRY, LLBC_FAILED);

    // Check config file exist or not.
    LLBC_SetErrAndReturnIf(!LLBC_File::Exists(_cfgPath), LLBC_ERROR_NOT_FOUND, LLBC_FAILED);

    _loadingCfg = true;
    LLBC_Defer(_loadingCfg = false);

    LLBC_DoIf(_cfgType == LLBC_ApplicationConfigType::Ini, return LoadIniConfig());
    LLBC_DoIf(_cfgType == LLBC_ApplicationConfigType::Xml, return LoadXmlConfig());
    LLBC_DoIf(true, return LoadPropertyConfig());
}

int LLBC_Application::LoadIniConfig()
{
    LLBC_Ini ini;
    LLBC_ReturnIf(ini.LoadFromFile(_cfgPath) != LLBC_OK, LLBC_FAILED);

    LLBC_VariantUtil::Ini2Variant(ini, _nonPropCfg);
    return LLBC_OK;
}

int LLBC_Application::LoadXmlConfig()
{
    ::llbc::tinyxml2::XMLDocument doc;
    LLBC_SetErrAndReturnIf(doc.LoadFile(_cfgPath.c_str()) != ::llbc::tinyxml2::XML_SUCCESS,
                           LLBC_ERROR_FORMAT,
                           LLBC_FAILED);

    LLBC_VariantUtil::Xml2Variant(doc, _nonPropCfg);
    return LLBC_OK;
}

int LLBC_Application::LoadPropertyConfig()
{
    return _propCfg.LoadFromFile(_cfgPath);
}

__LLBC_NS_END

<commit_msg>App stop流程调整:优先stop all services, 以确保栈序<commit_after>// The MIT License (MIT)

// Copyright (c) 2013 lailongwei<lailongwei@126.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "llbc/common/Export.h"

#include "llbc.h" //! Include llbc header to use Startup/Cleanup function.
#include "llbc/application/Application.h"

__LLBC_INTERNAL_NS_BEGIN

static const LLBC_NS LLBC_String __cfgSuffix_Ini = ".ini";
static const LLBC_NS LLBC_String __cfgSuffix_Xml = ".xml";
static const LLBC_NS LLBC_String __cfgSuffix_Property = ".cfg";
static const LLBC_NS LLBC_String __cfgSuffix_Unknown = "";

__LLBC_INTERNAL_NS_END

__LLBC_NS_BEGIN

const LLBC_String &LLBC_ApplicationConfigType::GetConfigSuffix(int cfgType)
{
    if (cfgType == Ini)
        return LLBC_INL_NS __cfgSuffix_Ini;
    else if (cfgType == Xml)
        return LLBC_INL_NS __cfgSuffix_Xml;
    else if (cfgType == Property)
        return LLBC_INL_NS __cfgSuffix_Property;
    else
        return LLBC_INL_NS __cfgSuffix_Unknown;
}

auto LLBC_ApplicationConfigType::GetConfigType(const LLBC_String &cfgSuffix) -> ENUM
{
    auto nmlCfgSuffix = cfgSuffix.strip().tolower();
    if (nmlCfgSuffix == LLBC_INL_NS __cfgSuffix_Ini)
        return Ini;
    else if (nmlCfgSuffix == LLBC_INL_NS __cfgSuffix_Xml)
        return Xml;
    else if (nmlCfgSuffix == LLBC_INL_NS __cfgSuffix_Property)
        return Property;
    else
        return End;
}

LLBC_Application *LLBC_Application::_thisApp = nullptr;

LLBC_Application::LLBC_Application()
: _name()

, _llbcLibStartupInApp(false)

, _loadingCfg(false)
, _cfgType(LLBC_ApplicationConfigType::End)

, _services(*LLBC_ServiceMgrSingleton)

, _started(false)

{
    LLBC_DoIf(_thisApp == nullptr, _thisApp = this);
}

LLBC_Application::~LLBC_Application()
{
    Stop();
}

int LLBC_Application::SetConfigPath(const LLBC_String &cfgPath)
{
    // Check config file exists or not.
    LLBC_SetErrAndReturnIf(!LLBC_File::Exists(cfgPath), LLBC_ERROR_ARG, LLBC_FAILED);

    // Get config type.
    const auto ext = LLBC_Directory::SplitExt(cfgPath)[1];
    const auto cfgType = LLBC_ApplicationConfigType::GetConfigType(ext);
    LLBC_SetErrAndReturnIf(cfgType < LLBC_ApplicationConfigType::Begin ||
                                cfgType >= LLBC_ApplicationConfigType::End,
                           LLBC_ERROR_NOT_SUPPORT,
                           LLBC_FAILED);

    // Check _started flag.
    LLBC_SetErrAndReturnIf(_started, LLBC_ERROR_NOT_ALLOW, LLBC_FAILED);

    // Lock and check _started flag again.
    LLBC_LockGuard guard(_cfgLock);
    LLBC_SetErrAndReturnIf(_started, LLBC_ERROR_NOT_ALLOW, LLBC_FAILED);

    // Save config info.
    _cfgType = cfgType;
    _cfgPath = cfgPath;

    return LLBC_OK;
}

int LLBC_Application::ReloadConfig(bool callEvMeth)
{
    // Not allow reload config if application not start.
    LLBC_SetErrAndReturnIf(!_started, LLBC_ERROR_NOT_ALLOW, LLBC_FAILED);

    // Lock and check again.
    LLBC_LockGuard guard(_cfgLock);
    LLBC_SetErrAndReturnIf(!_started, LLBC_ERROR_NOT_ALLOW, LLBC_FAILED);

    // Config not found when application start.
    LLBC_SetErrAndReturnIf(_cfgType == LLBC_ApplicationConfigType::End, LLBC_ERROR_NOT_FOUND, LLBC_FAILED);

    // Reload.
    LLBC_ReturnIf(LoadConfig(false) != LLBC_OK, LLBC_FAILED);

    // Call config reload event method.
    if (callEvMeth)
    {
        OnConfigReload();
        for (auto &svcPair : this->_services.GetAllIndexedByIdServices())
            svcPair.second->ProcessAppConfigReload();
    }

    return LLBC_OK;
}

int LLBC_Application::Start(const LLBC_String &name, int argc, char *argv[])
{
    // Multi application check.
    LLBC_SetErrAndReturnIf(_thisApp != this, LLBC_ERROR_REPEAT, LLBC_FAILED);
    // Application name check.
    LLBC_SetErrAndReturnIf(name.empty(), LLBC_ERROR_INVALID, LLBC_FAILED);

    // Reentry check.
    LLBC_SetErrAndReturnIf(_started, LLBC_ERROR_REENTRY, LLBC_FAILED);

    // Parse startup arguments.
    LLBC_ReturnIf(_startArgs.Parse(argc, argv) != LLBC_OK, LLBC_FAILED);

    // Startup llbc library.
    int ret = LLBC_FAILED;
    _llbcLibStartupInApp = true;
    if (LLBC_Startup() != LLBC_OK)
    {
        LLBC_ReturnIf(LLBC_Errno != LLBC_ERROR_REENTRY, LLBC_FAILED);

        _llbcLibStartupInApp = false;
        LLBC_SetLastError(LLBC_OK);
    }

    // Set name.
    _name = name;

    // Define app start failed defer.
    LLBC_Defer(if (ret != LLBC_OK) {
        _cfgPath.clear();
        _cfgType = LLBC_ApplicationConfigType::End;
        _propCfg.RemoveAllProperties();
        _nonPropCfg.BecomeNil();

        _name.clear();

        LLBC_DoIf(_llbcLibStartupInApp, LLBC_Cleanup(); _llbcLibStartupInApp = false);
    });

    // Locate config path.
    if (_cfgPath.empty())
    {
        int intCfgType;
        if (!(_cfgPath = LocateConfigPath(name, intCfgType)).empty())
            _cfgType = static_cast<LLBC_ApplicationConfigType::ENUM>(intCfgType);
    }

    // Load config.
    LLBC_ReturnIf(!_cfgPath.empty() && LoadConfig(true) != LLBC_OK, LLBC_FAILED);

    // Call OnStart event method.
    while (true)
    {
        bool startFinished = true;

        LLBC_SetLastError(LLBC_ERROR_SUCCESS);
        if (OnStart(argc, argv, startFinished) != LLBC_OK)
        {
            if (LLBC_GetLastError() == LLBC_ERROR_SUCCESS)
                LLBC_SetLastError(LLBC_ERROR_UNKNOWN);
            return LLBC_FAILED;
        }

        LLBC_BreakIf(startFinished);
        LLBC_Sleep(LLBC_CFG_APP_TRY_START_INTERVAL);
    }

    // Mark started.
    _started = true;

    // Return ok.
    ret = LLBC_OK;
    return ret;
}

void LLBC_Application::Stop()
{
    if (!_started)
        return;

    _services.StopAll(true);

    while (true)
    {
        bool stopFinished = true;
        OnStop(stopFinished);
        LLBC_BreakIf(stopFinished);

        LLBC_Sleep(LLBC_CFG_APP_TRY_STOP_INTERVAL);
    }

    _cfgPath.clear();
    _cfgType = LLBC_ApplicationConfigType::End;
    _propCfg.RemoveAllProperties();
    _nonPropCfg.BecomeNil();

    LLBC_DoIf(_llbcLibStartupInApp, LLBC_Cleanup(); _llbcLibStartupInApp = false);

    _started = false;
}

LLBC_String LLBC_Application::LocateConfigPath(const LLBC_String &appName, int &cfgType)
{
    // Application config directory locate order:
    // -> <cwd>
    // -> <module file directory>
    //    -> <cwd>/Config -> config -> Conf -> conf -> Cfg -> cfg
    //    -> <module file directory>/Config -> config -> Conf -> conf -> Cfg -> cfg
    //       -> <cwd>/../Config -> config -> Conf -> conf -> Cfg -> cfg
    //       -> <module file directory>/../Config -> config -> Conf -> conf -> Cfg -> cfg
    //          -> <cwd>/..
    //          -> <module file directory>/..
    //
    // Application config filename locate order:
    // -> app_name
    //    -> stripped _d/_debug suffix app_name
    //       -> executable_name
    //          -> stripped _d/_debug suffix executable_name
    //
    // Application config type locate order:
    // -> .ini
    //    -> .xml
    //       -> .cfg

    // Build config directories.
    // -> <cwd>
    //    -> <module file directory>
    LLBC_Strings cfgFileDirs{LLBC_Directory::CurDir(),
                             LLBC_Directory::ModuleFileDir()};

    // -> <cwd>/xxxxx
    //    -> <module file directory/xxxxx
    const char *interDirs[] = {"Config", "config", "Conf", "conf", "Cfg", "cfg"};
    for (auto &cfgDir : interDirs)
        cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::CurDir(), cfgDir));
    for (auto &cfgDir : interDirs)
        cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::ModuleFileDir(), cfgDir));
    // -> <cwd>/../xxxxx
    //    -> <module file directory>/../xxxxx
    for (auto &cfgDir : interDirs)
        cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::CurDir(), "..", cfgDir));
    for (auto &cfgDir : interDirs)
        cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::ModuleFileDir(), "..", cfgDir));
    // -> <cwd>/..
    //    -> <module file directory>/..
    cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::CurDir(), ".."));
    cfgFileDirs.push_back(LLBC_Directory::Join(LLBC_Directory::ModuleFileDir(), ".."));

    // Building config filenames.
    LLBC_Strings cfgFileNames{appName};
    if (appName.endswith("_d") || appName.endswith("_debug"))
              cfgFileNames.push_back(appName.substr(0, appName.rfind('_')));
    const auto execName = LLBC_Directory::SplitExt(LLBC_Directory::BaseName(LLBC_Directory::ModuleFileName()))[0];
    cfgFileNames.push_back(execName);
    if (execName.endswith("_d") || execName.endswith("_debug"))
        cfgFileNames.push_back(execName.substr(0, execName.rfind('_')));

    // Execute config file locate.
    for (auto &cfgFileDir : cfgFileDirs)
    {
        for (auto &cfgFileName : cfgFileNames)
        {
            for (cfgType = LLBC_ApplicationConfigType::Begin;
                 cfgType != LLBC_ApplicationConfigType::End;
                 ++cfgType)
            {
                const auto cfgPath = LLBC_Directory::Join(
                    cfgFileDir, cfgFileName + LLBC_ApplicationConfigType::GetConfigSuffix(cfgType));
                LLBC_ReturnIf(LLBC_File::Exists(cfgPath), cfgPath);
            }
        }
    }

    LLBC_SetLastError(LLBC_ERROR_NOT_FOUND);
    return "";
}

int LLBC_Application::LoadConfig(bool lock)
{
    // Reentry check.
    LLBC_SetErrAndReturnIf(_loadingCfg, LLBC_ERROR_REENTRY, LLBC_FAILED);

    // Lock and check again.
    if (lock)
        _cfgLock.Lock();
    LLBC_Defer(if (lock) _cfgLock.Unlock());
    LLBC_SetErrAndReturnIf(_loadingCfg, LLBC_ERROR_REENTRY, LLBC_FAILED);

    // Check config file exist or not.
    LLBC_SetErrAndReturnIf(!LLBC_File::Exists(_cfgPath), LLBC_ERROR_NOT_FOUND, LLBC_FAILED);

    _loadingCfg = true;
    LLBC_Defer(_loadingCfg = false);

    LLBC_DoIf(_cfgType == LLBC_ApplicationConfigType::Ini, return LoadIniConfig());
    LLBC_DoIf(_cfgType == LLBC_ApplicationConfigType::Xml, return LoadXmlConfig());
    LLBC_DoIf(true, return LoadPropertyConfig());
}

int LLBC_Application::LoadIniConfig()
{
    LLBC_Ini ini;
    LLBC_ReturnIf(ini.LoadFromFile(_cfgPath) != LLBC_OK, LLBC_FAILED);

    LLBC_VariantUtil::Ini2Variant(ini, _nonPropCfg);
    return LLBC_OK;
}

int LLBC_Application::LoadXmlConfig()
{
    ::llbc::tinyxml2::XMLDocument doc;
    LLBC_SetErrAndReturnIf(doc.LoadFile(_cfgPath.c_str()) != ::llbc::tinyxml2::XML_SUCCESS,
                           LLBC_ERROR_FORMAT,
                           LLBC_FAILED);

    LLBC_VariantUtil::Xml2Variant(doc, _nonPropCfg);
    return LLBC_OK;
}

int LLBC_Application::LoadPropertyConfig()
{
    return _propCfg.LoadFromFile(_cfgPath);
}

__LLBC_NS_END

<|endoftext|>


<commit_before>/*
 * File:   list.hpp
 * Author: manu343726
 *
 * Created on 1 de septiembre de 2013, 13:17
 */

#ifndef LIST_HPP
#define	LIST_HPP

#undef max
#undef min

#include "basic_types.hpp"
#include "iterator.hpp"
#include "to_string.hpp"

#include <sstream>

namespace mpl
{

    /* mpl::list */

    template<typename... Ts>
    struct list
    {
        static const std::size_t lenght = sizeof...(Ts);
        static const std::size_t size = lenght;
        static const bool is_empty = lenght == 0;
    };

    using empty_list = mpl::list<>;

    namespace
    {
        template<typename LIST>
        struct _to_string;

        //length > 2 (Recursive case)
        template<typename HEAD , typename... TAIL>
        struct _to_string<mpl::list<HEAD,TAIL...>>
        {
            friend std::ostream& operator<<(std::ostream& os , _to_string<mpl::list<HEAD,TAIL...>>)
            {
                return os << mpl::to_string<HEAD>() << ',' << _to_string<mpl::list<TAIL...>>();
            }
        };

        //length == 1 (Base case)
        template<typename HEAD>
        struct _to_string<mpl::list<HEAD>>
        {
            friend std::ostream& operator<<(std::ostream& os , _to_string<mpl::list<HEAD>>)
            {
                return os << mpl::to_string<HEAD>();
            }
        };

        //length == 0 (Base case)
        template<>
        struct _to_string<mpl::empty_list>
        {
            friend std::ostream& operator<<(std::ostream& os , _to_string<mpl::empty_list>)
            {
                return os;
            }
        };
    }

    template<typename... Ts>
    struct to_string_t<mpl::list<Ts...>>
    {
        operator std::string() const
        {
            std::stringstream os;

            os << '[' << _to_string<mpl::list<Ts...>>() << ']';

            return os.str();
        }
    };

    namespace
    {
        /* mpl::index_of */

        //Forward-declaration:
        template<typename LIST , typename T>
        struct _index_of;

        //Recursive case:
        template<typename HEAD , typename... TAIL , typename T>
        struct _index_of<mpl::list<HEAD,TAIL...>,T>
        {
            static const int tmp = _index_of<mpl::list<TAIL...>,T>::value;
            static const int value = tmp < 0 ? -1 : tmp + 1;
        };

        //Base case:
        template<typename... TAIL , typename T>
        struct _index_of<mpl::list<T,TAIL...>,T> : public mpl::integer<0> {};

        //Base case:
        template<typename T>
        struct _index_of<mpl::list<>,T> : public mpl::integer<-1> {};

        /* mpl::contains */

        template<typename LIST , typename T>
        struct _contains : public mpl::boolean<_index_of<LIST,T>::value >= 0> {};

        /* mpl::type_at */

        //Forward declaration:
        template<typename LIST , std::size_t INDEX>
        struct _type_at;

        //Recursive case:
        template<typename HEAD , typename... TAIL , std::size_t INDEX>
        struct _type_at<mpl::list<HEAD,TAIL...> , INDEX> : public mpl::type_t< typename _type_at<mpl::list<TAIL...>,INDEX - 1>::type> {};

        //Base case:
        template<typename HEAD , typename... TAIL>
        struct _type_at<mpl::list<HEAD,TAIL...>,0> : public mpl::type_t<HEAD> {};

        //Base case:
        template<std::size_t INDEX>
        struct _type_at<mpl::empty_list,INDEX>
        {
            static_assert( mpl::empty_list::lenght == 0 , "Index out of bounds");
        };

        /* mpl::split */

        template<typename LEFT_TYPES , typename RIGHT_TYPES , std::size_t INDEX>
        struct _splitter;

        //Recursive case:
        template<typename... LEFT_TYPES , typename HEAD , typename... TAIL , std::size_t INDEX>
        struct _splitter<mpl::list<LEFT_TYPES...>,mpl::list<HEAD,TAIL...>,INDEX>
        {
            using next = _splitter<mpl::list<LEFT_TYPES...,HEAD> , mpl::list<TAIL...> , INDEX - 1>;
            using right = typename next::right;
            using left  = typename next::left;
        };

        //Base case:
        template<typename... LEFT_TYPES , typename HEAD , typename... TAIL>
        struct _splitter<mpl::list<LEFT_TYPES...> , mpl::list<HEAD,TAIL...> , 0>
        {
            using right = mpl::list<HEAD,TAIL...>;
            using left  = mpl::list<LEFT_TYPES...>;
        };

        /* mpl::concat */

        template<typename LIST1 , typename LIST2>
        struct _concat;

        template<typename... Ts , typename... Us>
        struct _concat<mpl::list<Ts...>,mpl::list<Us...>> : public mpl::type_t<mpl::list<Ts...,Us...>>{};
    }

    template<typename LIST , typename T>
    using index_of = mpl::integer<_index_of<LIST,T>::value>;

    template<typename LIST , typename T>
    using contains = _contains<LIST,T>;

    template<typename LIST , typename INDEX>
    using type_at = typename _type_at<LIST,INDEX::value>::type;

    template<typename LIST , typename INDEX>
    using split = _splitter<LIST,mpl::empty_list,INDEX::value>;

    template<typename LIST , typename INDEX>
    using split_left = typename _splitter<mpl::empty_list,LIST,INDEX::value>::left;

    template<typename LIST , typename INDEX>
    using split_right = typename _splitter<mpl::empty_list,LIST,INDEX::value>::right;

    template<typename LHS , typename RHS>
    using concat = typename _concat<LHS,RHS>::type;

    using empty_list = list<>;

    using invalid_list = mpl::no_type;
    using invalid_list_item = mpl::no_type;

    template<typename HEAD , typename... TAIL>
    struct begin_t<mpl::list<HEAD,TAIL...>> : public mpl::make_forward_iterator<HEAD,list<TAIL...>> {};

    template<typename... Ts>
    struct end_t<mpl::list<Ts...>> : public mpl::make_forward_iterator<mpl::invalid_list_item , mpl::invalid_list> {};

    template<typename... R_TAIL , typename R_HEAD>
    struct rbegin_t<mpl::list<R_TAIL...,R_HEAD>> : public mpl::make_backward_iterator<mpl::list<R_TAIL...> , R_HEAD> {};

    template<typename... Ts>
    struct rend_t<mpl::list<Ts...>> : public mpl::make_backward_iterator<mpl::invalid_list , mpl::invalid_list_item> {};

    template<typename ITEM , typename HEAD , typename... TAIL>
    struct next_t<mpl::forward_iterator<ITEM,mpl::list<HEAD,TAIL...>>> : public mpl::make_forward_iterator<HEAD,mpl::list<TAIL...>> {};

    template<typename ITEM>
    struct next_t<mpl::forward_iterator<ITEM,mpl::empty_list>> : public mpl::make_forward_iterator<mpl::invalid_list_item , mpl::invalid_list> {};

    template<typename R_HEAD , typename... R_TAIL , typename ITEM>
    struct previous_t<mpl::backward_iterator<mpl::list<R_TAIL...,R_HEAD>,ITEM>> : public mpl::make_backward_iterator<mpl::list<R_TAIL...>,R_HEAD> {};

    template<typename ITEM>
    struct previous_t<mpl::backward_iterator<mpl::empty_list,ITEM>> : public mpl::make_backward_iterator<mpl::invalid_list , mpl::invalid_list_item> {};
}

#endif	/* LIST_HPP */

<commit_msg>mpl::to_list , mpl::from_list<commit_after>/*
 * File:   list.hpp
 * Author: manu343726
 *
 * Created on 1 de septiembre de 2013, 13:17
 */

#ifndef LIST_HPP
#define	LIST_HPP

#undef max
#undef min

#include "basic_types.hpp"
#include "iterator.hpp"
#include "to_string.hpp"

#include <sstream>

namespace mpl
{

    /* mpl::list */

    template<typename... Ts>
    struct list
    {
        static const std::size_t lenght = sizeof...(Ts);
        static const std::size_t size = lenght;
        static const bool is_empty = lenght == 0;
    };

    using empty_list = mpl::list<>;

    namespace
    {
        template<typename LIST>
        struct _to_string;

        //length > 2 (Recursive case)
        template<typename HEAD , typename... TAIL>
        struct _to_string<mpl::list<HEAD,TAIL...>>
        {
            friend std::ostream& operator<<(std::ostream& os , _to_string<mpl::list<HEAD,TAIL...>>)
            {
                return os << mpl::to_string<HEAD>() << ',' << _to_string<mpl::list<TAIL...>>();
            }
        };

        //length == 1 (Base case)
        template<typename HEAD>
        struct _to_string<mpl::list<HEAD>>
        {
            friend std::ostream& operator<<(std::ostream& os , _to_string<mpl::list<HEAD>>)
            {
                return os << mpl::to_string<HEAD>();
            }
        };

        //length == 0 (Base case)
        template<>
        struct _to_string<mpl::empty_list>
        {
            friend std::ostream& operator<<(std::ostream& os , _to_string<mpl::empty_list>)
            {
                return os;
            }
        };
    }

    template<typename... Ts>
    struct to_string_t<mpl::list<Ts...>>
    {
        operator std::string() const
        {
            std::stringstream os;

            os << '[' << _to_string<mpl::list<Ts...>>() << ']';

            return os.str();
        }
    };

    namespace
    {
        /* mpl::index_of */

        //Forward-declaration:
        template<typename LIST , typename T>
        struct _index_of;

        //Recursive case:
        template<typename HEAD , typename... TAIL , typename T>
        struct _index_of<mpl::list<HEAD,TAIL...>,T>
        {
            static const int tmp = _index_of<mpl::list<TAIL...>,T>::value;
            static const int value = tmp < 0 ? -1 : tmp + 1;
        };

        //Base case:
        template<typename... TAIL , typename T>
        struct _index_of<mpl::list<T,TAIL...>,T> : public mpl::integer<0> {};

        //Base case:
        template<typename T>
        struct _index_of<mpl::list<>,T> : public mpl::integer<-1> {};

        /* mpl::contains */

        template<typename LIST , typename T>
        struct _contains : public mpl::boolean<_index_of<LIST,T>::value >= 0> {};

        /* mpl::type_at */

        //Forward declaration:
        template<typename LIST , std::size_t INDEX>
        struct _type_at;

        //Recursive case:
        template<typename HEAD , typename... TAIL , std::size_t INDEX>
        struct _type_at<mpl::list<HEAD,TAIL...> , INDEX> : public mpl::type_t< typename _type_at<mpl::list<TAIL...>,INDEX - 1>::type> {};

        //Base case:
        template<typename HEAD , typename... TAIL>
        struct _type_at<mpl::list<HEAD,TAIL...>,0> : public mpl::type_t<HEAD> {};

        //Base case:
        template<std::size_t INDEX>
        struct _type_at<mpl::empty_list,INDEX>
        {
            static_assert( mpl::empty_list::lenght == 0 , "Index out of bounds");
        };

        /* mpl::split */

        template<typename LEFT_TYPES , typename RIGHT_TYPES , std::size_t INDEX>
        struct _splitter;

        //Recursive case:
        template<typename... LEFT_TYPES , typename HEAD , typename... TAIL , std::size_t INDEX>
        struct _splitter<mpl::list<LEFT_TYPES...>,mpl::list<HEAD,TAIL...>,INDEX>
        {
            using next = _splitter<mpl::list<LEFT_TYPES...,HEAD> , mpl::list<TAIL...> , INDEX - 1>;
            using right = typename next::right;
            using left  = typename next::left;
        };

        //Base case:
        template<typename... LEFT_TYPES , typename HEAD , typename... TAIL>
        struct _splitter<mpl::list<LEFT_TYPES...> , mpl::list<HEAD,TAIL...> , 0>
        {
            using right = mpl::list<HEAD,TAIL...>;
            using left  = mpl::list<LEFT_TYPES...>;
        };

        /* mpl::concat */

        template<typename LIST1 , typename LIST2>
        struct _concat;

        template<typename... Ts , typename... Us>
        struct _concat<mpl::list<Ts...>,mpl::list<Us...>> : public mpl::type_t<mpl::list<Ts...,Us...>>{};
    }

    template<typename LIST , typename T>
    using index_of = mpl::integer<_index_of<LIST,T>::value>;

    template<typename LIST , typename T>
    using contains = _contains<LIST,T>;

    template<typename LIST , typename INDEX>
    using type_at = typename _type_at<LIST,INDEX::value>::type;

    template<typename LIST , typename INDEX>
    using split = _splitter<LIST,mpl::empty_list,INDEX::value>;

    template<typename LIST , typename INDEX>
    using split_left = typename _splitter<mpl::empty_list,LIST,INDEX::value>::left;

    template<typename LIST , typename INDEX>
    using split_right = typename _splitter<mpl::empty_list,LIST,INDEX::value>::right;

    template<typename LHS , typename RHS>
    using concat = typename _concat<LHS,RHS>::type;

    using empty_list = list<>;

    using invalid_list = mpl::no_type;
    using invalid_list_item = mpl::no_type;

    template<typename HEAD , typename... TAIL>
    struct begin_t<mpl::list<HEAD,TAIL...>> : public mpl::make_forward_iterator<HEAD,list<TAIL...>> {};

    template<typename... Ts>
    struct end_t<mpl::list<Ts...>> : public mpl::make_forward_iterator<mpl::invalid_list_item , mpl::invalid_list> {};

    template<typename... R_TAIL , typename R_HEAD>
    struct rbegin_t<mpl::list<R_TAIL...,R_HEAD>> : public mpl::make_backward_iterator<mpl::list<R_TAIL...> , R_HEAD> {};

    template<typename... Ts>
    struct rend_t<mpl::list<Ts...>> : public mpl::make_backward_iterator<mpl::invalid_list , mpl::invalid_list_item> {};

    template<typename ITEM , typename HEAD , typename... TAIL>
    struct next_t<mpl::forward_iterator<ITEM,mpl::list<HEAD,TAIL...>>> : public mpl::make_forward_iterator<HEAD,mpl::list<TAIL...>> {};

    template<typename ITEM>
    struct next_t<mpl::forward_iterator<ITEM,mpl::empty_list>> : public mpl::make_forward_iterator<mpl::invalid_list_item , mpl::invalid_list> {};

    template<typename R_HEAD , typename... R_TAIL , typename ITEM>
    struct previous_t<mpl::backward_iterator<mpl::list<R_TAIL...,R_HEAD>,ITEM>> : public mpl::make_backward_iterator<mpl::list<R_TAIL...>,R_HEAD> {};

    template<typename ITEM>
    struct previous_t<mpl::backward_iterator<mpl::empty_list,ITEM>> : public mpl::make_backward_iterator<mpl::invalid_list , mpl::invalid_list_item> {};

    template<typename LIST>
    struct from_list_t;

    template<typename LIST>
    using from_list = mpl::result_of<from_list_t<LIST>>;

    template<typename T>
    struct to_list_t;

    template<typename T>
    using to_list = mpl::result_of<to_list_t<T>>;
}

#endif	/* LIST_HPP */

<|endoftext|>


<commit_before>a5af8223-2747-11e6-a450-e0f84713e7b8<commit_msg>Adding stuff<commit_after>a647e405-2747-11e6-9c59-e0f84713e7b8<|endoftext|>