<commit_before>#include <sqlite_orm/sqlite_orm.h>
#include <catch2/catch.hpp>
#include <cstdio>  //  remove

using namespace sqlite_orm;

namespace BackupTests {
    struct User {
        int id = 0;
        std::string name;
    };

    bool operator==(const User &lhs, const User &rhs) {
        return lhs.id == rhs.id && lhs.name == rhs.name;
    }

    struct MarvelHero {
        int id;
        std::string name;
        std::string abilities;
    };

    inline auto initStorageMarvel(const std::string &path) {
        using namespace sqlite_orm;
        auto storage = make_storage(path,
                                    make_table("marvel",
                                               make_column("id", &MarvelHero::id, primary_key()),
                                               make_column("name", &MarvelHero::name),
                                               make_column("abilities", &MarvelHero::abilities)));
        return storage;
    }
}

TEST_CASE("backup") {
    using namespace BackupTests;
    using Catch::Matchers::UnorderedEquals;
    const std::string usersTableName = "users";
    auto makeStorage = [&usersTableName](const std::string &filename) {
        return make_storage(
            filename,
            make_table(usersTableName, make_column("id", &User::id, primary_key()), make_column("name", &User::name)));
    };
    const std::string backupFilename = "backup.sqlite";
    SECTION("to") {
        ::remove(backupFilename.c_str());
        auto storage2 = makeStorage(backupFilename);
        auto storage = makeStorage("");
        storage.sync_schema();
        storage.replace(User{1, "Sharon"});
        storage.replace(User{2, "Maitre"});
        storage.replace(User{3, "Rita"});
        REQUIRE(!storage2.table_exists(usersTableName));
        SECTION("filename") {
            storage.backup_to(backupFilename);
        }
        SECTION("storage") {
            storage.backup_to(storage2);
        }
        SECTION("filename step -1") {
            auto backup = storage.make_backup_to(backupFilename);
            backup.step(-1);
        }
        SECTION("filename step 1") {
            auto backup = storage.make_backup_to(backupFilename);
            do {
                backup.step(1);
            } while(backup.remaining() > 0);
        }
        SECTION("storage step -1") {
            auto backup = storage.make_backup_to(storage2);
            backup.step(-1);
        }
        SECTION("storage step 1") {
            auto backup = storage.make_backup_to(storage2);
            do {
                backup.step(1);
            } while(backup.remaining() > 0);
        }
        REQUIRE(storage2.table_exists(usersTableName));
        auto rowsFromBackup = storage2.get_all<User>();
        auto expectedRows = storage.get_all<User>();
        REQUIRE_THAT(rowsFromBackup, UnorderedEquals(expectedRows));
    }
    SECTION("from") {
        ::remove(backupFilename.c_str());
        auto storage = makeStorage(backupFilename);
        storage.sync_schema();
        storage.replace(User{1, "Sharon"});
        storage.replace(User{2, "Maitre"});
        storage.replace(User{3, "Rita"});
        auto storage2 = makeStorage("");
        SECTION("filename") {
            storage2.backup_from(backupFilename);
        }
        SECTION("filename step -1") {
            auto backup = storage2.make_backup_from(backupFilename);
            backup.step(-1);
        }
        SECTION("filename step 1") {
            auto backup = storage2.make_backup_from(backupFilename);
            do {
                backup.step(1);
            } while(backup.remaining() > 0);
        }
        SECTION("storage") {
            storage2.backup_from(storage);
        }
        SECTION("storage step -1") {
            auto backup = storage2.make_backup_from(storage);
            backup.step(-1);
        }
        SECTION("storage step -1") {
            auto backup = storage2.make_backup_from(storage);
            do {
                backup.step(1);
            } while(backup.remaining() > 0);
        }
        REQUIRE(storage2.table_exists(usersTableName));
        auto rowsFromBackup = storage2.get_all<User>();
        REQUIRE_THAT(rowsFromBackup, UnorderedEquals(storage.get_all<User>()));
    }
}

TEST_CASE("Backup crash") {
    using namespace BackupTests;
    using MarvelStorage = decltype(initStorageMarvel(""));

    // --- Create a shared pointer to the MarvelStorage
    std::string fp("iteration.sqlite");
    std::shared_ptr<MarvelStorage> db = std::make_shared<MarvelStorage>(initStorageMarvel(fp));
    auto storage{*db};

    storage.sync_schema();
    storage.remove_all<MarvelHero>();

    // --- Insert values
    storage.insert(MarvelHero{-1, "Tony Stark", "Iron man, playboy, billionaire, philanthropist"});
    storage.insert(MarvelHero{-1, "Thor", "Storm god"});
    storage.insert(MarvelHero{-1, "Vision", "Min Stone"});
    storage.insert(MarvelHero{-1, "Captain America", "Vibranium shield"});
    storage.insert(MarvelHero{-1, "Hulk", "Strength"});
    storage.insert(MarvelHero{-1, "Star Lord", "Humor"});
    storage.insert(MarvelHero{-1, "Peter Parker", "Spiderman"});
    storage.insert(MarvelHero{-1, "Clint Barton", "Hawkeye"});
    storage.insert(MarvelHero{-1, "Natasha Romanoff", "Black widow"});
    storage.insert(MarvelHero{-1, "Groot", "I am Groot!"});
    REQUIRE(storage.count<MarvelHero>() == 10);

    // --- Create backup file name and verify that the file does not exist
    std::string backupFilename{"backup.sqlite"};

    // --- Backup the current storage to the file
    auto backup = storage.make_backup_to(backupFilename);
    backup.step(-1);
}
<commit_msg>added unique filename<commit_after>#include <sqlite_orm/sqlite_orm.h>
#include <catch2/catch.hpp>
#include <cstdio>  //  remove

using namespace sqlite_orm;

namespace BackupTests {
    struct User {
        int id = 0;
        std::string name;
    };

    bool operator==(const User &lhs, const User &rhs) {
        return lhs.id == rhs.id && lhs.name == rhs.name;
    }

    struct MarvelHero {
        int id;
        std::string name;
        std::string abilities;
    };

    inline auto initStorageMarvel(const std::string &path) {
        using namespace sqlite_orm;
        auto storage = make_storage(path,
                                    make_table("marvel",
                                               make_column("id", &MarvelHero::id, primary_key()),
                                               make_column("name", &MarvelHero::name),
                                               make_column("abilities", &MarvelHero::abilities)));
        return storage;
    }
}

TEST_CASE("backup") {
    using namespace BackupTests;
    using Catch::Matchers::UnorderedEquals;
    const std::string usersTableName = "users";
    auto makeStorage = [&usersTableName](const std::string &filename) {
        return make_storage(
            filename,
            make_table(usersTableName, make_column("id", &User::id, primary_key()), make_column("name", &User::name)));
    };
    static int filenameSuffix = 0;  //  to make an unique filename for every test
    const std::string backupFilename = "backup" + std::to_string(filenameSuffix++) + ".sqlite";
    SECTION("to") {
        ::remove(backupFilename.c_str());
        auto storage2 = makeStorage(backupFilename);
        auto storage = makeStorage("");
        storage.sync_schema();
        storage.replace(User{1, "Sharon"});
        storage.replace(User{2, "Maitre"});
        storage.replace(User{3, "Rita"});
        REQUIRE(!storage2.table_exists(usersTableName));
        SECTION("filename") {
            storage.backup_to(backupFilename);
        }
        SECTION("storage") {
            storage.backup_to(storage2);
        }
        SECTION("filename step -1") {
            auto backup = storage.make_backup_to(backupFilename);
            backup.step(-1);
        }
        SECTION("filename step 1") {
            auto backup = storage.make_backup_to(backupFilename);
            do {
                backup.step(1);
            } while(backup.remaining() > 0);
        }
        SECTION("storage step -1") {
            auto backup = storage.make_backup_to(storage2);
            backup.step(-1);
        }
        SECTION("storage step 1") {
            auto backup = storage.make_backup_to(storage2);
            do {
                backup.step(1);
            } while(backup.remaining() > 0);
        }
        REQUIRE(storage2.table_exists(usersTableName));
        auto rowsFromBackup = storage2.get_all<User>();
        auto expectedRows = storage.get_all<User>();
        REQUIRE_THAT(rowsFromBackup, UnorderedEquals(expectedRows));
    }
    SECTION("from") {
        ::remove(backupFilename.c_str());
        auto storage = makeStorage(backupFilename);
        storage.sync_schema();
        storage.replace(User{1, "Sharon"});
        storage.replace(User{2, "Maitre"});
        storage.replace(User{3, "Rita"});
        auto storage2 = makeStorage("");
        SECTION("filename") {
            storage2.backup_from(backupFilename);
        }
        SECTION("filename step -1") {
            auto backup = storage2.make_backup_from(backupFilename);
            backup.step(-1);
        }
        SECTION("filename step 1") {
            auto backup = storage2.make_backup_from(backupFilename);
            do {
                backup.step(1);
            } while(backup.remaining() > 0);
        }
        SECTION("storage") {
            storage2.backup_from(storage);
        }
        SECTION("storage step -1") {
            auto backup = storage2.make_backup_from(storage);
            backup.step(-1);
        }
        SECTION("storage step -1") {
            auto backup = storage2.make_backup_from(storage);
            do {
                backup.step(1);
            } while(backup.remaining() > 0);
        }
        REQUIRE(storage2.table_exists(usersTableName));
        auto rowsFromBackup = storage2.get_all<User>();
        REQUIRE_THAT(rowsFromBackup, UnorderedEquals(storage.get_all<User>()));
    }
}

TEST_CASE("Backup crash") {
    using namespace BackupTests;
    using MarvelStorage = decltype(initStorageMarvel(""));

    // --- Create a shared pointer to the MarvelStorage
    std::string fp("iteration.sqlite");
    std::shared_ptr<MarvelStorage> db = std::make_shared<MarvelStorage>(initStorageMarvel(fp));
    auto storage{*db};

    storage.sync_schema();
    storage.remove_all<MarvelHero>();

    // --- Insert values
    storage.insert(MarvelHero{-1, "Tony Stark", "Iron man, playboy, billionaire, philanthropist"});
    storage.insert(MarvelHero{-1, "Thor", "Storm god"});
    storage.insert(MarvelHero{-1, "Vision", "Min Stone"});
    storage.insert(MarvelHero{-1, "Captain America", "Vibranium shield"});
    storage.insert(MarvelHero{-1, "Hulk", "Strength"});
    storage.insert(MarvelHero{-1, "Star Lord", "Humor"});
    storage.insert(MarvelHero{-1, "Peter Parker", "Spiderman"});
    storage.insert(MarvelHero{-1, "Clint Barton", "Hawkeye"});
    storage.insert(MarvelHero{-1, "Natasha Romanoff", "Black widow"});
    storage.insert(MarvelHero{-1, "Groot", "I am Groot!"});
    REQUIRE(storage.count<MarvelHero>() == 10);

    // --- Create backup file name and verify that the file does not exist
    std::string backupFilename{"backup.sqlite"};

    // --- Backup the current storage to the file
    auto backup = storage.make_backup_to(backupFilename);
    backup.step(-1);
}
<|endoftext|>


<commit_before>#define CATCH_CONFIG_RUNNER

#include "DepLibSRTP.hpp"
#include "DepLibUV.hpp"
#include "DepLibWebRTC.hpp"
#include "DepOpenSSL.hpp"
#include "DepUsrSCTP.hpp"
#include "LogLevel.hpp"
#include "Settings.hpp"
#include "Utils.hpp"
#include <catch.hpp>
#include <cstdlib> // std::getenv()

int main(int argc, char* argv[])
{
	LogLevel logLevel{ LogLevel::LOG_NONE };

	// Get logLevel from ENV variable.
	if (std::getenv("MS_TEST_LOG_LEVEL"))
	{
		if (std::string(std::getenv("MS_TEST_LOG_LEVEL")) == "debug")
			logLevel = LogLevel::LOG_DEBUG;
		else if (std::string(std::getenv("MS_TEST_LOG_LEVEL")) == "warn")
			logLevel = LogLevel::LOG_WARN;
		else if (std::string(std::getenv("MS_TEST_LOG_LEVEL")) == "error")
			logLevel = LogLevel::LOG_ERROR;
	}

	Settings::configuration.logLevel = logLevel;

	// Initialize static stuff.
	DepLibUV::ClassInit();
	DepOpenSSL::ClassInit();
	DepLibSRTP::ClassInit();
	DepUsrSCTP::ClassInit();
	DepLibWebRTC::ClassInit();
	Utils::Crypto::ClassInit();

	int status = Catch::Session().run(argc, argv);

	// Free static stuff.
	DepLibUV::ClassDestroy();
	DepLibSRTP::ClassDestroy();
	Utils::Crypto::ClassDestroy();
	DepLibWebRTC::ClassDestroy();
	DepUsrSCTP::ClassDestroy();

	return status;
}
<commit_msg>tests.cpp: fix order of ClassDestroy() calls<commit_after>#define CATCH_CONFIG_RUNNER

#include "DepLibSRTP.hpp"
#include "DepLibUV.hpp"
#include "DepLibWebRTC.hpp"
#include "DepOpenSSL.hpp"
#include "DepUsrSCTP.hpp"
#include "LogLevel.hpp"
#include "Settings.hpp"
#include "Utils.hpp"
#include <catch.hpp>
#include <cstdlib> // std::getenv()

int main(int argc, char* argv[])
{
	LogLevel logLevel{ LogLevel::LOG_NONE };

	// Get logLevel from ENV variable.
	if (std::getenv("MS_TEST_LOG_LEVEL"))
	{
		if (std::string(std::getenv("MS_TEST_LOG_LEVEL")) == "debug")
			logLevel = LogLevel::LOG_DEBUG;
		else if (std::string(std::getenv("MS_TEST_LOG_LEVEL")) == "warn")
			logLevel = LogLevel::LOG_WARN;
		else if (std::string(std::getenv("MS_TEST_LOG_LEVEL")) == "error")
			logLevel = LogLevel::LOG_ERROR;
	}

	Settings::configuration.logLevel = logLevel;

	// Initialize static stuff.
	DepLibUV::ClassInit();
	DepOpenSSL::ClassInit();
	DepLibSRTP::ClassInit();
	DepUsrSCTP::ClassInit();
	DepLibWebRTC::ClassInit();
	Utils::Crypto::ClassInit();

	int status = Catch::Session().run(argc, argv);

	// Free static stuff.
	DepLibSRTP::ClassDestroy();
	Utils::Crypto::ClassDestroy();
	DepLibWebRTC::ClassDestroy();
	DepUsrSCTP::ClassDestroy();
	DepLibUV::ClassDestroy();

	return status;
}
<|endoftext|>


<commit_before>#include "aof_manager.h"
#include "../flags.h"
#include "../utils/exception.h"
#include "../utils/fs.h"
#include "../utils/logger.h"
#include "../utils/metrics.h"
#include "../utils/thread_manager.h"
#include "callbacks.h"
#include "manifest.h"
#include "options.h"

#include <cassert>
#include <iterator>
#include <tuple>

using namespace dariadb;
using namespace dariadb::storage;
using namespace dariadb::utils::async;

AOFManager *AOFManager::_instance = nullptr;

AOFManager::~AOFManager() {
  this->flush();
}

AOFManager::AOFManager() {
  _down = nullptr;

  if (dariadb::utils::fs::path_exists(Options::instance()->path)) {
    auto aofs = Manifest::instance()->aof_list();
    for (auto f : aofs) {
      auto full_filename = utils::fs::append_path(Options::instance()->path, f);
      if (AOFile::writed(full_filename) != Options::instance()->aof_max_size) {
        logger_info("engine: AofManager open exist file ", f);
        AOFile_Ptr p{new AOFile(full_filename)};
        _aof = p;
        break;
      }
    }
  }

  _buffer.resize(Options::instance()->aof_buffer_size);
  _buffer_pos = 0;
}

void AOFManager::start() {
  if (AOFManager::_instance == nullptr) {
    AOFManager::_instance = new AOFManager();
  } else {
    throw MAKE_EXCEPTION("AOFManager::start started twice.");
  }
}

void AOFManager::stop() {
  _instance->flush();
  delete AOFManager::_instance;
  AOFManager::_instance = nullptr;
}

AOFManager *AOFManager::instance() {
  return AOFManager::_instance;
}

void AOFManager::create_new() {
  TIMECODE_METRICS(ctm, "create", "AOFManager::create_new");
  _aof = nullptr;
  if (Options::instance()->strategy != STRATEGY::FAST_WRITE) {
    drop_old_if_needed();
  }
  _aof = AOFile_Ptr{new AOFile()};
}

void AOFManager::drop_closed_files(size_t count) {
  if (_down != nullptr) {
    auto closed = this->closed_aofs();

    TIMECODE_METRICS(ctmd, "drop", "AOFManager::drop_closed_files");
    size_t to_drop = std::min(closed.size(), count);
    for (size_t i = 0; i < to_drop; ++i) {
      auto f = closed.front();
      closed.pop_front();
      auto without_path = utils::fs::extract_filename(f);
      if (_files_send_to_drop.find(without_path) == _files_send_to_drop.end()) {
        this->drop_aof(f, _down);
      }
    }
    // clean set of sended to drop files.
    auto aofs_exists = Manifest::instance()->aof_list();
    std::set<std::string> aof_exists_set{aofs_exists.begin(), aofs_exists.end()};
    std::set<std::string> new_sended_files;
    for (auto &v : _files_send_to_drop) {
      if (aof_exists_set.find(v) != aof_exists_set.end()) {
        new_sended_files.insert(v);
      }
    }
    _files_send_to_drop = new_sended_files;
  }
}

void AOFManager::drop_old_if_needed() {
  auto closed = this->closed_aofs();
  drop_closed_files(closed.size());
}

std::list<std::string> AOFManager::aof_files() const {
  std::list<std::string> res;
  auto files = Manifest::instance()->aof_list();
  for (auto f : files) {
    auto full_path = utils::fs::append_path(Options::instance()->path, f);
    res.push_back(full_path);
  }
  return res;
}

std::list<std::string> AOFManager::closed_aofs() {
  auto all_files = aof_files();
  std::list<std::string> result;
  for (auto fn : all_files) {
    if (_aof == nullptr) {
      result.push_back(fn);
    } else {
      if (fn != this->_aof->filename()) {
        result.push_back(fn);
      }
    }
  }
  return result;
}

void AOFManager::drop_aof(const std::string &fname, IAofDropper *storage) {
  AOFile_Ptr ptr = AOFile_Ptr{new AOFile{fname, false}};
  auto without_path = utils::fs::extract_filename(fname);
  _files_send_to_drop.insert(without_path);
  storage->drop_aof(without_path);
}

void AOFManager::set_downlevel(IAofDropper *down) {
  _down = down;
  this->drop_old_if_needed();
}

dariadb::Time AOFManager::minTime() {
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  dariadb::Time result = dariadb::MAX_TIME;
  for (auto filename : files) {
    AOFile aof(filename, true);
    auto local = aof.minTime();
    result = std::min(local, result);
  }
  size_t pos = 0;
  for (auto v : _buffer) {
    result = std::min(v.time, result);
    ++pos;
    if (pos > _buffer_pos) {
      break;
    }
  }
  return result;
}

dariadb::Time AOFManager::maxTime() {
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  dariadb::Time result = dariadb::MIN_TIME;
  for (auto filename : files) {
    AOFile aof(filename, true);
    auto local = aof.maxTime();
    result = std::max(local, result);
  }
  for (auto v : _buffer) {
    result = std::max(v.time, result);
  }
  return result;
}

bool AOFManager::minMaxTime(dariadb::Id id, dariadb::Time *minResult,
                            dariadb::Time *maxResult) {
  TIMECODE_METRICS(ctmd, "minMaxTime", "AOFManager::minMaxTime");
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  using MMRes = std::tuple<bool, dariadb::Time, dariadb::Time>;
  std::vector<MMRes> results{files.size()};
  std::vector<TaskResult_Ptr> task_res{files.size()};
  size_t num = 0;

  for (auto filename : files) {
    AsyncTask at = [filename, &results, num, id](const ThreadInfo &ti) {
      TKIND_CHECK(THREAD_COMMON_KINDS::DISK_IO, ti.kind);
      AOFile aof(filename, true);
      dariadb::Time lmin = dariadb::MAX_TIME, lmax = dariadb::MIN_TIME;
      if (aof.minMaxTime(id, &lmin, &lmax)) {
        results[num] = MMRes(true, lmin, lmax);
      } else {
        results[num] = MMRes(false, lmin, lmax);
      }
    };
    task_res[num] =
        ThreadManager::instance()->post(THREAD_COMMON_KINDS::DISK_IO, AT(at));
    num++;
  }

  for (auto &tw : task_res) {
    tw->wait();
  }

  bool res = false;

  *minResult = dariadb::MAX_TIME;
  *maxResult = dariadb::MIN_TIME;
  for (auto &subRes : results) {
    if (std::get<0>(subRes)) {
      res = true;
      *minResult = std::min(std::get<1>(subRes), *minResult);
      *maxResult = std::max(std::get<2>(subRes), *maxResult);
    }
  }

  size_t pos = 0;
  for (auto v : _buffer) {
    if (v.id == id) {
      res = true;
      *minResult = std::min(v.time, *minResult);
      *maxResult = std::max(v.time, *maxResult);
    }
    ++pos;
    if (pos > _buffer_pos) {
      break;
    }
  }
  return res;
}

void AOFManager::foreach (const QueryInterval &q, IReaderClb * clbk) {
  TIMECODE_METRICS(ctmd, "foreach", "AOFManager::foreach");
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  if (files.empty()) {
    return;
  }

  std::vector<TaskResult_Ptr> task_res{files.size()};
  size_t num = 0;

  for (auto filename : files) {
    AsyncTask at = [filename, &q, &clbk](const ThreadInfo &ti) {
      TKIND_CHECK(THREAD_COMMON_KINDS::DISK_IO, ti.kind);
      AOFile aof(filename, true);
      aof.foreach (q, clbk);
    };
    task_res[num] =
        ThreadManager::instance()->post(THREAD_COMMON_KINDS::DISK_IO, AT(at));
    num++;
  }
  for (auto &t : task_res) {
    t->wait();
  }

  size_t pos = 0;
  for (auto v : _buffer) {
    if (pos >= _buffer_pos) {
      break;
    }
    if (v.inQuery(q.ids, q.flag, q.from, q.to)) {
      clbk->call(v);
    }
    ++pos;
  }
}

Id2Meas AOFManager::readTimePoint(const QueryTimePoint &query) {
  TIMECODE_METRICS(ctmd, "readTimePoint", "AOFManager::readTimePoint");
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  dariadb::Id2Meas sub_result;

  for (auto id : query.ids) {
    sub_result[id].flag = Flags::_NO_DATA;
    sub_result[id].time = query.time_point;
  }

  std::vector<Id2Meas> results{files.size()};
  std::vector<TaskResult_Ptr> task_res{files.size()};

  size_t num = 0;
  for (auto filename : files) {
    AsyncTask at = [filename, &query, num, &results](const ThreadInfo &ti) {
      TKIND_CHECK(THREAD_COMMON_KINDS::DISK_IO, ti.kind);
      AOFile aof(filename, true);
      results[num] = aof.readTimePoint(query);
    };
    task_res[num] =
        ThreadManager::instance()->post(THREAD_COMMON_KINDS::DISK_IO, AT(at));
    num++;
  }

  for (auto &tw : task_res) {
    tw->wait();
  }

  for (auto &out : results) {
    for (auto &kv : out) {
      auto it = sub_result.find(kv.first);
      if (it == sub_result.end()) {
        sub_result.insert(std::make_pair(kv.first, kv.second));
      } else {
        if (it->second.flag == Flags::_NO_DATA) {
          sub_result[kv.first] = kv.second;
        }
      }
    }
  }
  size_t pos = 0;
  for (auto v : _buffer) {
    if (v.inQuery(query.ids, query.flag)) {
      auto it = sub_result.find(v.id);
      if (it == sub_result.end()) {
        sub_result.insert(std::make_pair(v.id, v));
      } else {
        if ((v.time > it->second.time) && (v.time <= query.time_point)) {
          sub_result[v.id] = v;
        }
      }
    }
    ++pos;
    if (pos > _buffer_pos) {
      break;
    }
  }

  return sub_result;
}

Id2Meas AOFManager::currentValue(const IdArray &ids, const Flag &flag) {
  auto files = aof_files();

  dariadb::Id2Meas meases;
  for (const auto &f : files) {
    AOFile c(f, true);
    auto sub_rdr = c.currentValue(ids, flag);

    for (auto &kv : sub_rdr) {
      auto it = meases.find(kv.first);
      if (it == meases.end()) {
        meases.insert(std::make_pair(kv.first, kv.second));
      } else {
        if (it->second.flag == Flags::_NO_DATA) {
          meases[kv.first] = kv.second;
        }
      }
    }
  }
  return meases;
}

dariadb::append_result AOFManager::append(const Meas &value) {
  TIMECODE_METRICS(ctmd, "append", "AOFManager::append");
  std::lock_guard<std::mutex> lg(_locker);
  _buffer[_buffer_pos] = value;
  _buffer_pos++;

  if (_buffer_pos >= Options::instance()->aof_buffer_size) {
    flush_buffer();
  }
  return dariadb::append_result(1, 0);
}

void AOFManager::flush_buffer() {
  if (_buffer_pos == size_t(0)) {
    return;
  }
  if (_aof == nullptr) {
    create_new();
  }
  size_t pos = 0;
  size_t total_writed = 0;
  while (1) {
    auto res = _aof->append(_buffer.begin() + pos, _buffer.begin() + _buffer_pos);
    total_writed += res.writed;
    if (total_writed != _buffer_pos) {
      create_new();
      pos += res.writed;
    } else {
      break;
    }
  }
  _buffer_pos = 0;
}

void AOFManager::flush() {
  TIMECODE_METRICS(ctmd, "flush", "AOFManager::flush");
  flush_buffer();
}

size_t AOFManager::files_count() const {
  return aof_files().size();
}

void AOFManager::erase(const std::string &fname) {
  Manifest::instance()->aof_rm(fname);
  utils::fs::rm(utils::fs::append_path(Options::instance()->path, fname));
}
<commit_msg>aof_manager: use disk_io pool for write.<commit_after>#include "aof_manager.h"
#include "../flags.h"
#include "../utils/exception.h"
#include "../utils/fs.h"
#include "../utils/logger.h"
#include "../utils/metrics.h"
#include "../utils/thread_manager.h"
#include "callbacks.h"
#include "manifest.h"
#include "options.h"

#include <cassert>
#include <iterator>
#include <tuple>

using namespace dariadb;
using namespace dariadb::storage;
using namespace dariadb::utils::async;

AOFManager *AOFManager::_instance = nullptr;

AOFManager::~AOFManager() {
  this->flush();
}

AOFManager::AOFManager() {
  _down = nullptr;

  if (dariadb::utils::fs::path_exists(Options::instance()->path)) {
    auto aofs = Manifest::instance()->aof_list();
    for (auto f : aofs) {
      auto full_filename = utils::fs::append_path(Options::instance()->path, f);
      if (AOFile::writed(full_filename) != Options::instance()->aof_max_size) {
        logger_info("engine: AofManager open exist file ", f);
        AOFile_Ptr p{new AOFile(full_filename)};
        _aof = p;
        break;
      }
    }
  }

  _buffer.resize(Options::instance()->aof_buffer_size);
  _buffer_pos = 0;
}

void AOFManager::start() {
  if (AOFManager::_instance == nullptr) {
    AOFManager::_instance = new AOFManager();
  } else {
    throw MAKE_EXCEPTION("AOFManager::start started twice.");
  }
}

void AOFManager::stop() {
  _instance->flush();
  delete AOFManager::_instance;
  AOFManager::_instance = nullptr;
}

AOFManager *AOFManager::instance() {
  return AOFManager::_instance;
}

void AOFManager::create_new() {
  TIMECODE_METRICS(ctm, "create", "AOFManager::create_new");
  _aof = nullptr;
  if (Options::instance()->strategy != STRATEGY::FAST_WRITE) {
    drop_old_if_needed();
  }
  _aof = AOFile_Ptr{new AOFile()};
}

void AOFManager::drop_closed_files(size_t count) {
  if (_down != nullptr) {
    auto closed = this->closed_aofs();

    TIMECODE_METRICS(ctmd, "drop", "AOFManager::drop_closed_files");
    size_t to_drop = std::min(closed.size(), count);
    for (size_t i = 0; i < to_drop; ++i) {
      auto f = closed.front();
      closed.pop_front();
      auto without_path = utils::fs::extract_filename(f);
      if (_files_send_to_drop.find(without_path) == _files_send_to_drop.end()) {
        this->drop_aof(f, _down);
      }
    }
    // clean set of sended to drop files.
    auto aofs_exists = Manifest::instance()->aof_list();
    std::set<std::string> aof_exists_set{aofs_exists.begin(), aofs_exists.end()};
    std::set<std::string> new_sended_files;
    for (auto &v : _files_send_to_drop) {
      if (aof_exists_set.find(v) != aof_exists_set.end()) {
        new_sended_files.insert(v);
      }
    }
    _files_send_to_drop = new_sended_files;
  }
}

void AOFManager::drop_old_if_needed() {
  auto closed = this->closed_aofs();
  drop_closed_files(closed.size());
}

std::list<std::string> AOFManager::aof_files() const {
  std::list<std::string> res;
  auto files = Manifest::instance()->aof_list();
  for (auto f : files) {
    auto full_path = utils::fs::append_path(Options::instance()->path, f);
    res.push_back(full_path);
  }
  return res;
}

std::list<std::string> AOFManager::closed_aofs() {
  auto all_files = aof_files();
  std::list<std::string> result;
  for (auto fn : all_files) {
    if (_aof == nullptr) {
      result.push_back(fn);
    } else {
      if (fn != this->_aof->filename()) {
        result.push_back(fn);
      }
    }
  }
  return result;
}

void AOFManager::drop_aof(const std::string &fname, IAofDropper *storage) {
  AOFile_Ptr ptr = AOFile_Ptr{new AOFile{fname, false}};
  auto without_path = utils::fs::extract_filename(fname);
  _files_send_to_drop.insert(without_path);
  storage->drop_aof(without_path);
}

void AOFManager::set_downlevel(IAofDropper *down) {
  _down = down;
  this->drop_old_if_needed();
}

dariadb::Time AOFManager::minTime() {
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  dariadb::Time result = dariadb::MAX_TIME;
  for (auto filename : files) {
    AOFile aof(filename, true);
    auto local = aof.minTime();
    result = std::min(local, result);
  }
  size_t pos = 0;
  for (auto v : _buffer) {
    result = std::min(v.time, result);
    ++pos;
    if (pos > _buffer_pos) {
      break;
    }
  }
  return result;
}

dariadb::Time AOFManager::maxTime() {
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  dariadb::Time result = dariadb::MIN_TIME;
  for (auto filename : files) {
    AOFile aof(filename, true);
    auto local = aof.maxTime();
    result = std::max(local, result);
  }
  for (auto v : _buffer) {
    result = std::max(v.time, result);
  }
  return result;
}

bool AOFManager::minMaxTime(dariadb::Id id, dariadb::Time *minResult,
                            dariadb::Time *maxResult) {
  TIMECODE_METRICS(ctmd, "minMaxTime", "AOFManager::minMaxTime");
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  using MMRes = std::tuple<bool, dariadb::Time, dariadb::Time>;
  std::vector<MMRes> results{files.size()};
  std::vector<TaskResult_Ptr> task_res{files.size()};
  size_t num = 0;

  for (auto filename : files) {
    AsyncTask at = [filename, &results, num, id](const ThreadInfo &ti) {
      TKIND_CHECK(THREAD_COMMON_KINDS::DISK_IO, ti.kind);
      AOFile aof(filename, true);
      dariadb::Time lmin = dariadb::MAX_TIME, lmax = dariadb::MIN_TIME;
      if (aof.minMaxTime(id, &lmin, &lmax)) {
        results[num] = MMRes(true, lmin, lmax);
      } else {
        results[num] = MMRes(false, lmin, lmax);
      }
    };
    task_res[num] =
        ThreadManager::instance()->post(THREAD_COMMON_KINDS::DISK_IO, AT(at));
    num++;
  }

  for (auto &tw : task_res) {
    tw->wait();
  }

  bool res = false;

  *minResult = dariadb::MAX_TIME;
  *maxResult = dariadb::MIN_TIME;
  for (auto &subRes : results) {
    if (std::get<0>(subRes)) {
      res = true;
      *minResult = std::min(std::get<1>(subRes), *minResult);
      *maxResult = std::max(std::get<2>(subRes), *maxResult);
    }
  }

  size_t pos = 0;
  for (auto v : _buffer) {
    if (v.id == id) {
      res = true;
      *minResult = std::min(v.time, *minResult);
      *maxResult = std::max(v.time, *maxResult);
    }
    ++pos;
    if (pos > _buffer_pos) {
      break;
    }
  }
  return res;
}

void AOFManager::foreach (const QueryInterval &q, IReaderClb * clbk) {
  TIMECODE_METRICS(ctmd, "foreach", "AOFManager::foreach");
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  if (files.empty()) {
    return;
  }

  std::vector<TaskResult_Ptr> task_res{files.size()};
  size_t num = 0;

  for (auto filename : files) {
    AsyncTask at = [filename, &q, &clbk](const ThreadInfo &ti) {
      TKIND_CHECK(THREAD_COMMON_KINDS::DISK_IO, ti.kind);
      AOFile aof(filename, true);
      aof.foreach (q, clbk);
    };
    task_res[num] =
        ThreadManager::instance()->post(THREAD_COMMON_KINDS::DISK_IO, AT(at));
    num++;
  }
  for (auto &t : task_res) {
    t->wait();
  }

  size_t pos = 0;
  for (auto v : _buffer) {
    if (pos >= _buffer_pos) {
      break;
    }
    if (v.inQuery(q.ids, q.flag, q.from, q.to)) {
      clbk->call(v);
    }
    ++pos;
  }
}

Id2Meas AOFManager::readTimePoint(const QueryTimePoint &query) {
  TIMECODE_METRICS(ctmd, "readTimePoint", "AOFManager::readTimePoint");
  std::lock_guard<std::mutex> lg(_locker);
  auto files = aof_files();
  dariadb::Id2Meas sub_result;

  for (auto id : query.ids) {
    sub_result[id].flag = Flags::_NO_DATA;
    sub_result[id].time = query.time_point;
  }

  std::vector<Id2Meas> results{files.size()};
  std::vector<TaskResult_Ptr> task_res{files.size()};

  size_t num = 0;
  for (auto filename : files) {
    AsyncTask at = [filename, &query, num, &results](const ThreadInfo &ti) {
      TKIND_CHECK(THREAD_COMMON_KINDS::DISK_IO, ti.kind);
      AOFile aof(filename, true);
      results[num] = aof.readTimePoint(query);
    };
    task_res[num] =
        ThreadManager::instance()->post(THREAD_COMMON_KINDS::DISK_IO, AT(at));
    num++;
  }

  for (auto &tw : task_res) {
    tw->wait();
  }

  for (auto &out : results) {
    for (auto &kv : out) {
      auto it = sub_result.find(kv.first);
      if (it == sub_result.end()) {
        sub_result.insert(std::make_pair(kv.first, kv.second));
      } else {
        if (it->second.flag == Flags::_NO_DATA) {
          sub_result[kv.first] = kv.second;
        }
      }
    }
  }
  size_t pos = 0;
  for (auto v : _buffer) {
    if (v.inQuery(query.ids, query.flag)) {
      auto it = sub_result.find(v.id);
      if (it == sub_result.end()) {
        sub_result.insert(std::make_pair(v.id, v));
      } else {
        if ((v.time > it->second.time) && (v.time <= query.time_point)) {
          sub_result[v.id] = v;
        }
      }
    }
    ++pos;
    if (pos > _buffer_pos) {
      break;
    }
  }

  return sub_result;
}

Id2Meas AOFManager::currentValue(const IdArray &ids, const Flag &flag) {
  auto files = aof_files();

  dariadb::Id2Meas meases;
  for (const auto &f : files) {
    AOFile c(f, true);
    auto sub_rdr = c.currentValue(ids, flag);

    for (auto &kv : sub_rdr) {
      auto it = meases.find(kv.first);
      if (it == meases.end()) {
        meases.insert(std::make_pair(kv.first, kv.second));
      } else {
        if (it->second.flag == Flags::_NO_DATA) {
          meases[kv.first] = kv.second;
        }
      }
    }
  }
  return meases;
}

dariadb::append_result AOFManager::append(const Meas &value) {
  TIMECODE_METRICS(ctmd, "append", "AOFManager::append");
  std::lock_guard<std::mutex> lg(_locker);
  _buffer[_buffer_pos] = value;
  _buffer_pos++;

  if (_buffer_pos >= Options::instance()->aof_buffer_size) {
    flush_buffer();
  }
  return dariadb::append_result(1, 0);
}

void AOFManager::flush_buffer() {
  if (_buffer_pos == size_t(0)) {
    return;
  }
  AsyncTask at = [this](const ThreadInfo &ti) {
	  TKIND_CHECK(THREAD_COMMON_KINDS::DISK_IO, ti.kind);
	  if (_aof == nullptr) {
		  create_new();
	  }
	  size_t pos = 0;
	  size_t total_writed = 0;
	  while (1) {
		  auto res = _aof->append(_buffer.begin() + pos, _buffer.begin() + _buffer_pos);
		  total_writed += res.writed;
		  if (total_writed != _buffer_pos) {
			  create_new();
			  pos += res.writed;
		  }
		  else {
			  break;
		  }
	  }
	  _buffer_pos = 0;
  };
  auto async_r = ThreadManager::instance()->post(THREAD_COMMON_KINDS::DISK_IO, AT(at));
  async_r->wait();
}

void AOFManager::flush() {
  TIMECODE_METRICS(ctmd, "flush", "AOFManager::flush");
  flush_buffer();
}

size_t AOFManager::files_count() const {
  return aof_files().size();
}

void AOFManager::erase(const std::string &fname) {
  Manifest::instance()->aof_rm(fname);
  utils::fs::rm(utils::fs::append_path(Options::instance()->path, fname));
}
<|endoftext|>


<commit_before>//===- SymbolTable.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Symbol table is a bag of all known symbols. We put all symbols of
// all input files to the symbol table. The symbol Table is basically
// a hash table with the logic to resolve symbol name conflicts using
// the symbol types.
//
//===----------------------------------------------------------------------===//

#include "SymbolTable.h"
#include "Config.h"
#include "Error.h"
#include "Symbols.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;

using namespace lld;
using namespace lld::elf2;

template <class ELFT> SymbolTable<ELFT>::SymbolTable() {}

template <class ELFT>
static void checkCompatibility(InputFile *FileP) {
  auto *F = dyn_cast<ELFFileBase<ELFT>>(FileP);
  if (!F)
    return;
  if (F->getELFKind() == Config->EKind && F->getEMachine() == Config->EMachine)
    return;
  StringRef A = F->getName();
  StringRef B = Config->Emulation;
  if (B.empty())
    B = Config->FirstElf->getName();
  error(A + " is incompatible with " + B);
}

template <class ELFT>
void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
  InputFile *FileP = File.get();
  checkCompatibility<ELFT>(FileP);

  // .a file
  if (auto *F = dyn_cast<ArchiveFile>(FileP)) {
    ArchiveFiles.emplace_back(cast<ArchiveFile>(File.release()));
    F->parse();
    for (Lazy &Sym : F->getLazySymbols())
      addLazy(&Sym);
    return;
  }

  // .so file
  if (auto *F = dyn_cast<SharedFile<ELFT>>(FileP)) {
    // DSOs are uniquified not by filename but by soname.
    F->parseSoName();
    if (!IncludedSoNames.insert(F->getSoName()).second)
      return;

    SharedFiles.emplace_back(cast<SharedFile<ELFT>>(File.release()));
    F->parse();
    for (SharedSymbol<ELFT> &B : F->getSharedSymbols())
      resolve(&B);
    return;
  }

  // .o file
  auto *F = cast<ObjectFile<ELFT>>(FileP);
  ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
  F->parse(Comdats);
  for (SymbolBody *B : F->getSymbols())
    resolve(B);
}

// Add an undefined symbol.
template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
  auto *Sym = new (Alloc) Undefined(Name, false, STV_DEFAULT, false);
  resolve(Sym);
  return Sym;
}

// Add an undefined symbol. Unlike addUndefined, that symbol
// doesn't have to be resolved, thus "opt" (optional).
template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) {
  auto *Sym = new (Alloc) Undefined(Name, false, STV_HIDDEN, true);
  resolve(Sym);
  return Sym;
}

template <class ELFT>
void SymbolTable<ELFT>::addAbsolute(StringRef Name,
                                    typename ELFFile<ELFT>::Elf_Sym &ESym) {
  resolve(new (Alloc) DefinedRegular<ELFT>(Name, ESym, nullptr));
}

template <class ELFT>
void SymbolTable<ELFT>::addSynthetic(StringRef Name,
                                     OutputSectionBase<ELFT> &Section,
                                     typename ELFFile<ELFT>::uintX_t Value) {
  auto *Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, Value, Section);
  resolve(Sym);
}

template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) {
  auto *Sym = new (Alloc)
      DefinedRegular<ELFT>(Name, ElfSym<ELFT>::IgnoreUndef, nullptr);
  resolve(Sym);
  return Sym;
}

// Returns a file from which symbol B was created.
// If B does not belong to any file, returns a nullptr.
template <class ELFT>
ELFFileBase<ELFT> *SymbolTable<ELFT>::findFile(SymbolBody *B) {
  for (const std::unique_ptr<ObjectFile<ELFT>> &F : ObjectFiles) {
    ArrayRef<SymbolBody *> Syms = F->getSymbols();
    if (std::find(Syms.begin(), Syms.end(), B) != Syms.end())
      return F.get();
  }
  return nullptr;
}

template <class ELFT>
std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Old, SymbolBody *New) {
  ELFFileBase<ELFT> *OldFile = findFile(Old);
  ELFFileBase<ELFT> *NewFile = findFile(New);

  StringRef Sym = Old->getName();
  StringRef F1 = OldFile ? OldFile->getName() : "(internal)";
  StringRef F2 = NewFile ? NewFile->getName() : "(internal)";
  return (Sym + " in " + F1 + " and " + F2).str();
}

// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;

  SymbolBody *Existing = Sym->Body;

  if (Lazy *L = dyn_cast<Lazy>(Existing)) {
    if (auto *Undef = dyn_cast<Undefined>(New)) {
      addMemberFile(Undef, L);
      return;
    }
    // Found a definition for something also in an archive.
    // Ignore the archive definition.
    Sym->Body = New;
    return;
  }

  if (New->isTls() != Existing->isTls())
    error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New));

  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
  // equivalent (conflicting), or more preferable, respectively.
  int comp = Existing->compare<ELFT>(New);
  if (comp == 0) {
    std::string S = "duplicate symbol: " + conflictMsg(Existing, New);
    if (!Config->AllowMultipleDefinition)
      error(S);
    warning(S);
    return;
  }
  if (comp < 0)
    Sym->Body = New;
}

template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) {
  // Find an existing Symbol or create and insert a new one.
  StringRef Name = New->getName();
  Symbol *&Sym = Symtab[Name];
  if (!Sym)
    Sym = new (Alloc) Symbol{New};
  New->setBackref(Sym);
  return Sym;
}

template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
  auto It = Symtab.find(Name);
  if (It == Symtab.end())
    return nullptr;
  return It->second->Body;
}

template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *L) {
  Symbol *Sym = insert(L);
  if (Sym->Body == L)
    return;
  if (auto *Undef = dyn_cast<Undefined>(Sym->Body)) {
    Sym->Body = L;
    addMemberFile(Undef, L);
  }
}

template <class ELFT>
void SymbolTable<ELFT>::addMemberFile(Undefined *Undef, Lazy *L) {
  // Weak undefined symbols should not fetch members from archives.
  // If we were to keep old symbol we would not know that an archive member was
  // available if a strong undefined symbol shows up afterwards in the link.
  // If a strong undefined symbol never shows up, this lazy symbol will
  // get to the end of the link and must be treated as the weak undefined one.
  // We set UsedInRegularObj in a similar way to what is done with shared
  // symbols and mark it as weak to reduce how many special cases are needed.
  if (Undef->isWeak()) {
    L->setUsedInRegularObj();
    L->setWeak();
    return;
  }

  // Fetch a member file that has the definition for L.
  // getMember returns nullptr if the member was already read from the library.
  if (std::unique_ptr<InputFile> File = L->getMember())
    addFile(std::move(File));
}

// This function takes care of the case in which shared libraries depend on
// the user program (not the other way, which is usual). Shared libraries
// may have undefined symbols, expecting that the user program provides
// the definitions for them. An example is BSD's __progname symbol.
// We need to put such symbols to the main program's .dynsym so that
// shared libraries can find them.
// Except this, we ignore undefined symbols in DSOs.
template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
  for (std::unique_ptr<SharedFile<ELFT>> &File : SharedFiles)
    for (StringRef U : File->getUndefinedSymbols())
      if (SymbolBody *Sym = find(U))
        if (Sym->isDefined())
          Sym->setUsedInDynamicReloc();
}

template class lld::elf2::SymbolTable<ELF32LE>;
template class lld::elf2::SymbolTable<ELF32BE>;
template class lld::elf2::SymbolTable<ELF64LE>;
template class lld::elf2::SymbolTable<ELF64BE>;
<commit_msg>Add comments.<commit_after>//===- SymbolTable.cpp ----------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Symbol table is a bag of all known symbols. We put all symbols of
// all input files to the symbol table. The symbol table is basically
// a hash table with the logic to resolve symbol name conflicts using
// the symbol types.
//
//===----------------------------------------------------------------------===//

#include "SymbolTable.h"
#include "Config.h"
#include "Error.h"
#include "Symbols.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;

using namespace lld;
using namespace lld::elf2;

template <class ELFT> SymbolTable<ELFT>::SymbolTable() {}

// All input object files must be for the same architecture
// (e.g. it does not make sense to link x86 object files with
// MIPS object files.) This function checks for that error.
template <class ELFT>
static void checkCompatibility(InputFile *FileP) {
  auto *F = dyn_cast<ELFFileBase<ELFT>>(FileP);
  if (!F)
    return;
  if (F->getELFKind() == Config->EKind && F->getEMachine() == Config->EMachine)
    return;
  StringRef A = F->getName();
  StringRef B = Config->Emulation;
  if (B.empty())
    B = Config->FirstElf->getName();
  error(A + " is incompatible with " + B);
}

// Add symbols in File to the symbol table.
template <class ELFT>
void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
  InputFile *FileP = File.get();
  checkCompatibility<ELFT>(FileP);

  // .a file
  if (auto *F = dyn_cast<ArchiveFile>(FileP)) {
    ArchiveFiles.emplace_back(cast<ArchiveFile>(File.release()));
    F->parse();
    for (Lazy &Sym : F->getLazySymbols())
      addLazy(&Sym);
    return;
  }

  // .so file
  if (auto *F = dyn_cast<SharedFile<ELFT>>(FileP)) {
    // DSOs are uniquified not by filename but by soname.
    F->parseSoName();
    if (!IncludedSoNames.insert(F->getSoName()).second)
      return;

    SharedFiles.emplace_back(cast<SharedFile<ELFT>>(File.release()));
    F->parse();
    for (SharedSymbol<ELFT> &B : F->getSharedSymbols())
      resolve(&B);
    return;
  }

  // .o file
  auto *F = cast<ObjectFile<ELFT>>(FileP);
  ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
  F->parse(Comdats);
  for (SymbolBody *B : F->getSymbols())
    resolve(B);
}

// Add an undefined symbol.
template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
  auto *Sym = new (Alloc) Undefined(Name, false, STV_DEFAULT, false);
  resolve(Sym);
  return Sym;
}

// Add an undefined symbol. Unlike addUndefined, that symbol
// doesn't have to be resolved, thus "opt" (optional).
template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) {
  auto *Sym = new (Alloc) Undefined(Name, false, STV_HIDDEN, true);
  resolve(Sym);
  return Sym;
}

template <class ELFT>
void SymbolTable<ELFT>::addAbsolute(StringRef Name,
                                    typename ELFFile<ELFT>::Elf_Sym &ESym) {
  resolve(new (Alloc) DefinedRegular<ELFT>(Name, ESym, nullptr));
}

template <class ELFT>
void SymbolTable<ELFT>::addSynthetic(StringRef Name,
                                     OutputSectionBase<ELFT> &Section,
                                     typename ELFFile<ELFT>::uintX_t Value) {
  auto *Sym = new (Alloc) DefinedSynthetic<ELFT>(Name, Value, Section);
  resolve(Sym);
}

// Add Name as an "ignored" symbol. An ignored symbol is a regular
// linker-synthesized defined symbol, but it is not recorded to the output
// file's symbol table. Such symbols are useful for some linker-defined symbols.
template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) {
  auto *Sym = new (Alloc)
      DefinedRegular<ELFT>(Name, ElfSym<ELFT>::IgnoreUndef, nullptr);
  resolve(Sym);
  return Sym;
}

// Returns a file from which symbol B was created.
// If B does not belong to any file, returns a nullptr.
template <class ELFT>
ELFFileBase<ELFT> *SymbolTable<ELFT>::findFile(SymbolBody *B) {
  for (const std::unique_ptr<ObjectFile<ELFT>> &F : ObjectFiles) {
    ArrayRef<SymbolBody *> Syms = F->getSymbols();
    if (std::find(Syms.begin(), Syms.end(), B) != Syms.end())
      return F.get();
  }
  return nullptr;
}

template <class ELFT>
std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Old, SymbolBody *New) {
  ELFFileBase<ELFT> *OldFile = findFile(Old);
  ELFFileBase<ELFT> *NewFile = findFile(New);

  StringRef Sym = Old->getName();
  StringRef F1 = OldFile ? OldFile->getName() : "(internal)";
  StringRef F2 = NewFile ? NewFile->getName() : "(internal)";
  return (Sym + " in " + F1 + " and " + F2).str();
}

// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
  Symbol *Sym = insert(New);
  if (Sym->Body == New)
    return;

  SymbolBody *Existing = Sym->Body;

  if (Lazy *L = dyn_cast<Lazy>(Existing)) {
    if (auto *Undef = dyn_cast<Undefined>(New)) {
      addMemberFile(Undef, L);
      return;
    }
    // Found a definition for something also in an archive.
    // Ignore the archive definition.
    Sym->Body = New;
    return;
  }

  if (New->isTls() != Existing->isTls())
    error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New));

  // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
  // equivalent (conflicting), or more preferable, respectively.
  int comp = Existing->compare<ELFT>(New);
  if (comp == 0) {
    std::string S = "duplicate symbol: " + conflictMsg(Existing, New);
    if (!Config->AllowMultipleDefinition)
      error(S);
    warning(S);
    return;
  }
  if (comp < 0)
    Sym->Body = New;
}

template <class ELFT> Symbol *SymbolTable<ELFT>::insert(SymbolBody *New) {
  // Find an existing Symbol or create and insert a new one.
  StringRef Name = New->getName();
  Symbol *&Sym = Symtab[Name];
  if (!Sym)
    Sym = new (Alloc) Symbol{New};
  New->setBackref(Sym);
  return Sym;
}

template <class ELFT> SymbolBody *SymbolTable<ELFT>::find(StringRef Name) {
  auto It = Symtab.find(Name);
  if (It == Symtab.end())
    return nullptr;
  return It->second->Body;
}

template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *L) {
  Symbol *Sym = insert(L);
  if (Sym->Body == L)
    return;
  if (auto *Undef = dyn_cast<Undefined>(Sym->Body)) {
    Sym->Body = L;
    addMemberFile(Undef, L);
  }
}

template <class ELFT>
void SymbolTable<ELFT>::addMemberFile(Undefined *Undef, Lazy *L) {
  // Weak undefined symbols should not fetch members from archives.
  // If we were to keep old symbol we would not know that an archive member was
  // available if a strong undefined symbol shows up afterwards in the link.
  // If a strong undefined symbol never shows up, this lazy symbol will
  // get to the end of the link and must be treated as the weak undefined one.
  // We set UsedInRegularObj in a similar way to what is done with shared
  // symbols and mark it as weak to reduce how many special cases are needed.
  if (Undef->isWeak()) {
    L->setUsedInRegularObj();
    L->setWeak();
    return;
  }

  // Fetch a member file that has the definition for L.
  // getMember returns nullptr if the member was already read from the library.
  if (std::unique_ptr<InputFile> File = L->getMember())
    addFile(std::move(File));
}

// This function takes care of the case in which shared libraries depend on
// the user program (not the other way, which is usual). Shared libraries
// may have undefined symbols, expecting that the user program provides
// the definitions for them. An example is BSD's __progname symbol.
// We need to put such symbols to the main program's .dynsym so that
// shared libraries can find them.
// Except this, we ignore undefined symbols in DSOs.
template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
  for (std::unique_ptr<SharedFile<ELFT>> &File : SharedFiles)
    for (StringRef U : File->getUndefinedSymbols())
      if (SymbolBody *Sym = find(U))
        if (Sym->isDefined())
          Sym->setUsedInDynamicReloc();
}

template class lld::elf2::SymbolTable<ELF32LE>;
template class lld::elf2::SymbolTable<ELF32BE>;
template class lld::elf2::SymbolTable<ELF64LE>;
template class lld::elf2::SymbolTable<ELF64BE>;
<|endoftext|>


<commit_before>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <blackhole/record.hpp>
#include <blackhole/sink/console.hpp>

namespace blackhole {
namespace testing {
namespace sink {

using ::testing::StrictMock;
using ::testing::internal::CaptureStdout;
using ::testing::internal::GetCapturedStdout;

using ::blackhole::sink::color_t;
using ::blackhole::sink::console_t;

namespace mock {
namespace {

class console_t : public ::blackhole::sink::console_t {
public:
    std::ostringstream stream;

    explicit console_t(::blackhole::sink::termcolor_map colmap) :
        ::blackhole::sink::console_t(stream, std::move(colmap))
    {}
};

}  // namespace
}  // namespace mock

TEST(color_t, Default) {
    std::ostringstream stream;
    stream << color_t();

    EXPECT_EQ("\033[39m", stream.str());
}

TEST(color_t, Red) {
    std::ostringstream stream;
    stream << color_t::red();

    EXPECT_EQ("\033[31m", stream.str());
}

TEST(color_t, Green) {
    std::ostringstream stream;
    stream << color_t::green();

    EXPECT_EQ("\033[32m", stream.str());
}

TEST(color_t, Yellow) {
    std::ostringstream stream;
    stream << color_t::yellow();

    EXPECT_EQ("\033[33m", stream.str());
}

TEST(color_t, Blue) {
    std::ostringstream stream;
    stream << color_t::blue();

    EXPECT_EQ("\033[34m", stream.str());
}

TEST(color_t, Reset) {
    std::ostringstream stream;
    stream << color_t::reset();

    EXPECT_EQ("\033[0m", stream.str());
}

TEST(console_t, WriteIntoStandardOutputByDefault) {
    console_t sink;

    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    CaptureStdout();
    sink.execute(record, "expected");

    const std::string actual = GetCapturedStdout();
    EXPECT_EQ("expected\n", actual);
}

class cout_redirector_t {
    std::streambuf* prev;

public:
    cout_redirector_t(std::streambuf* buffer) :
        prev(std::cout.rdbuf(buffer))
    {}

    ~cout_redirector_t() {
        std::cout.rdbuf(prev);
    }
};

TEST(console_t, ColoredOutput) {
    console_t sink([](const record_t&) -> color_t {
        return color_t::red();
    });

    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    std::ostringstream stream;
    cout_redirector_t lock(stream.rdbuf());
    sink.execute(record, "expected");

    EXPECT_EQ("\033[31mexpected\033[0m\n", stream.str());
}

TEST(console_t, NonColoredOutputToNonTTY) {
    mock::console_t sink([](const record_t&) -> color_t {
        return color_t::red();
    });

    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    sink.execute(record, "expected");

    EXPECT_EQ("expected\n", sink.stream.str());
}

TEST(console_t, FilterAcceptsAll) {
    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    console_t sink;

    EXPECT_TRUE(sink.filter(record));
}

TEST(console_t, Type) {
    EXPECT_EQ("console", std::string(factory<sink::console_t>::type()));
}

}  // namespace sink
}  // namespace testing
}  // namespace blackhole
<commit_msg>fix(tests): disable color output test for non TTY<commit_after>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <unistd.h>

#include <blackhole/record.hpp>
#include <blackhole/sink/console.hpp>

namespace blackhole {
namespace testing {
namespace sink {

using ::testing::StrictMock;
using ::testing::internal::CaptureStdout;
using ::testing::internal::GetCapturedStdout;

using ::blackhole::sink::color_t;
using ::blackhole::sink::console_t;

namespace mock {
namespace {

class console_t : public ::blackhole::sink::console_t {
public:
    std::ostringstream stream;

    explicit console_t(::blackhole::sink::termcolor_map colmap) :
        ::blackhole::sink::console_t(stream, std::move(colmap))
    {}
};

}  // namespace
}  // namespace mock

TEST(color_t, Default) {
    std::ostringstream stream;
    stream << color_t();

    EXPECT_EQ("\033[39m", stream.str());
}

TEST(color_t, Red) {
    std::ostringstream stream;
    stream << color_t::red();

    EXPECT_EQ("\033[31m", stream.str());
}

TEST(color_t, Green) {
    std::ostringstream stream;
    stream << color_t::green();

    EXPECT_EQ("\033[32m", stream.str());
}

TEST(color_t, Yellow) {
    std::ostringstream stream;
    stream << color_t::yellow();

    EXPECT_EQ("\033[33m", stream.str());
}

TEST(color_t, Blue) {
    std::ostringstream stream;
    stream << color_t::blue();

    EXPECT_EQ("\033[34m", stream.str());
}

TEST(color_t, Reset) {
    std::ostringstream stream;
    stream << color_t::reset();

    EXPECT_EQ("\033[0m", stream.str());
}

TEST(console_t, WriteIntoStandardOutputByDefault) {
    console_t sink;

    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    CaptureStdout();
    sink.execute(record, "expected");

    const std::string actual = GetCapturedStdout();
    EXPECT_EQ("expected\n", actual);
}

class cout_redirector_t {
    std::streambuf* prev;

public:
    cout_redirector_t(std::streambuf* buffer) :
        prev(std::cout.rdbuf(buffer))
    {}

    ~cout_redirector_t() {
        std::cout.rdbuf(prev);
    }
};

TEST(console_t, ColoredOutput) {
    console_t sink([](const record_t&) -> color_t {
        return color_t::red();
    });

    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    std::ostringstream stream;
    cout_redirector_t lock(stream.rdbuf());
    sink.execute(record, "expected");

    if (::isatty(1)) {
        EXPECT_EQ("\033[31mexpected\033[0m\n", stream.str());
    } else {
        EXPECT_EQ("expected\n", stream.str());
    }
}

TEST(console_t, NonColoredOutputToNonTTY) {
    mock::console_t sink([](const record_t&) -> color_t {
        return color_t::red();
    });

    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    sink.execute(record, "expected");

    EXPECT_EQ("expected\n", sink.stream.str());
}

TEST(console_t, FilterAcceptsAll) {
    const string_view message("");
    const attribute_pack pack;
    record_t record(42, message, pack);

    console_t sink;

    EXPECT_TRUE(sink.filter(record));
}

TEST(console_t, Type) {
    EXPECT_EQ("console", std::string(factory<sink::console_t>::type()));
}

}  // namespace sink
}  // namespace testing
}  // namespace blackhole
<|endoftext|>


<commit_before>// Copyright (c) 2011 Sirikata Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

#include "JSVisibleData.hpp"

namespace Sirikata {
namespace JS {

JSVisibleData::~JSVisibleData()
{
}

void JSVisibleData::clearFromParent() {
    // We're guaranteed by shared_ptrs and our reference counting that
    // this destructor is only called once there are no more
    // ProxyObjectPtrs and no v8 visibles referring to this data,
    // allowing us to clear this out of the JSVisibleManager.
    if (mParent) mParent->removeVisibleData(this);
}

void JSVisibleData::disable() {
    mParent = NULL;
}

// JSProxyVisibleData
JSProxyVisibleData::JSProxyVisibleData(JSVisibleDataListener* parent, ProxyObjectPtr from)
 : JSVisibleData(parent),
   proxy(from)
{
    proxy->PositionProvider::addListener(this);
    proxy->MeshProvider::addListener(this);
}

JSProxyVisibleData::~JSProxyVisibleData() {
    if (proxy) {
        proxy->PositionProvider::removeListener(this);
        proxy->MeshProvider::removeListener(this);
    }
    clearFromParent();
}

const SpaceObjectReference& JSProxyVisibleData::id() {
    return proxy->getObjectReference();
}

const SpaceObjectReference& JSProxyVisibleData::observer() {
    return proxy->getOwnerPresenceID();
}

void JSProxyVisibleData::disable() {
    proxy->PositionProvider::removeListener(this);
    proxy->MeshProvider::removeListener(this);
    proxy.reset();
    JSVisibleData::disable();
}

// PositionListener Interface
void JSProxyVisibleData::updateLocation(ProxyObjectPtr obj,
    const TimedMotionVector3f &newLocation, const TimedMotionQuaternion& newOrient,
    const AggregateBoundingInfo& newBounds, const SpaceObjectReference& sporef)
{
    // FIXME this interface doesn't let us tell exactly what's updated, so we
    // have to send notifications for everything
    notify(&JSVisibleDataEventListener::visiblePositionChanged, this);
    notify(&JSVisibleDataEventListener::visibleVelocityChanged, this);
    notify(&JSVisibleDataEventListener::visibleOrientationChanged, this);
    notify(&JSVisibleDataEventListener::visibleOrientationVelChanged, this);
    // scale handled by MeshListener interface
}
// MeshListener Interface
void JSProxyVisibleData::onSetMesh(ProxyObjectPtr proxy, Transfer::URI const& newMesh, const SpaceObjectReference& sporef) {
    notify(&JSVisibleDataEventListener::visibleMeshChanged, this);
}
void JSProxyVisibleData::onSetScale(ProxyObjectPtr proxy, float32 newScale,const SpaceObjectReference& sporef ) {
    notify(&JSVisibleDataEventListener::visibleScaleChanged, this);
}
void JSProxyVisibleData::onSetPhysics(ProxyObjectPtr proxy, const String& phy,const SpaceObjectReference& sporef ) {
    notify(&JSVisibleDataEventListener::visiblePhysicsChanged, this);
}
void JSProxyVisibleData::onSetIsAggregate(ProxyObjectPtr proxy, bool isAggregate, const SpaceObjectReference& sporef ) {
    // Not exposed to VisibleDataEventListeners
}

// JSRestoredVisibleData
JSRestoredVisibleData::JSRestoredVisibleData(JSVisibleDataListener* parent, const SpaceObjectReference& from, JSVisibleDataPtr fromData)
 : JSVisibleData(parent),
   sporefToListenTo(from)
{
    if (fromData) {
        assert(from == fromData->id());
        updateFrom(*fromData);
    }
}

JSRestoredVisibleData::JSRestoredVisibleData(JSVisibleDataListener* parent, const SpaceObjectReference& from, const IPresencePropertiesRead& orig)
 : JSVisibleData(parent),
   sporefToListenTo(from)
{
    updateFrom(orig);
}

JSRestoredVisibleData::~JSRestoredVisibleData() {
    clearFromParent();
}

const SpaceObjectReference& JSRestoredVisibleData::id() {
    return sporefToListenTo;
}

const SpaceObjectReference& JSRestoredVisibleData::observer() {
    // No observer...
    static SpaceObjectReference n = SpaceObjectReference::null();
    return n;
}

void JSRestoredVisibleData::updateFrom(const IPresencePropertiesRead& orig) {
    setLocation(orig.location());
    setOrientation(orig.orientation());
    setBounds(orig.bounds());
    setMesh(orig.mesh());
    setPhysics(orig.physics());

}

// JSAggregateVisibleData
JSAggregateVisibleData::JSAggregateVisibleData(JSVisibleDataListener* parent, const SpaceObjectReference& vis)
 : JSVisibleData(parent),
   refcount(0),
   selfPtr(),
   mBest(SpaceObjectReference::null())
{
    // Note NULL so we don't get notifications since they'd only happen on
    // destruction since we hold strong refs currently.
    // We use null index to indicate no associated presence
    mChildren[SpaceObjectReference::null()] =
        JSVisibleDataPtr(new JSRestoredVisibleData(NULL, vis) );
}

JSAggregateVisibleData::~JSAggregateVisibleData() {
    clearFromParent();
}

const SpaceObjectReference& JSAggregateVisibleData::id() {
    return getBestChild()->id();
}

const SpaceObjectReference& JSAggregateVisibleData::observer() {
    // Can't specify one observer...
    static SpaceObjectReference n = SpaceObjectReference::null();
    return n;
}

// IPresencePropertiesRead Interface
TimedMotionVector3f JSAggregateVisibleData::location() const{
    return getBestChild()->location();
}

TimedMotionQuaternion JSAggregateVisibleData::orientation() const{
    return getBestChild()->orientation();
}

AggregateBoundingInfo JSAggregateVisibleData::bounds() const{
    return getBestChild()->bounds();
}

Transfer::URI JSAggregateVisibleData::mesh() const{
    return getBestChild()->mesh();
}

String JSAggregateVisibleData::physics() const{
    return getBestChild()->physics();
}

bool JSAggregateVisibleData::isAggregate() const{
    return getBestChild()->isAggregate();
}

ObjectReference JSAggregateVisibleData::parent() const{
    return getBestChild()->parent();
}

void JSAggregateVisibleData::removeVisibleData(JSVisibleData* data) {
    Mutex::scoped_lock locker (childMutex);
    mChildren.erase(data->observer());
}

void JSAggregateVisibleData::updateFrom(ProxyObjectPtr proxy) {
    Mutex::scoped_lock locker (childMutex);
    if (mChildren.find(proxy->getObjectReference()) == mChildren.end()) {
        // Note that we currently pass in NULL so we don't get
        // notifications. We'd only get them upon clearing our children list in
        // the destructor anyway.
        JSVisibleDataPtr jsvisdata(new JSProxyVisibleData(NULL, proxy));
        jsvisdata->addListener(this); // JSVisibleDataEventListener
        mChildren[proxy->getObjectReference()] = jsvisdata;
    }
    mBest = proxy->getObjectReference();
}

void JSAggregateVisibleData::updateFrom(const IPresencePropertiesRead& props) {
    Mutex::scoped_lock locker (childMutex);
    if (mChildren.find(SpaceObjectReference::null()) != mChildren.end()) {
        std::tr1::dynamic_pointer_cast<JSRestoredVisibleData>(mChildren[SpaceObjectReference::null()])->updateFrom(props);
    }
    // We don't update mBest because either it's already this, or we have a
    // Proxy, which is preferable.
}

JSVisibleDataPtr JSAggregateVisibleData::getBestChild() const{
    Mutex::scoped_lock locker (const_cast<Mutex&>(childMutex));
    assert(!mChildren.empty());
    assert(mChildren.find(mBest) != mChildren.end());
    return mChildren.find(mBest)->second;
}

void JSAggregateVisibleData::incref(JSVisibleDataPtr self) {
    selfPtr = self;
    refcount++;
}

void JSAggregateVisibleData::decref() {
    assert(refcount > 0);
    refcount--;
    if (refcount == 0) selfPtr.reset();
}

bool JSAggregateVisibleData::visibleToPresence() const {
    return refcount > 0;
}

void JSAggregateVisibleData::disable() {
    Mutex::scoped_lock locker (childMutex);
    mChildren.clear();
    JSVisibleData::disable();
}

void JSAggregateVisibleData::visiblePositionChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visiblePositionChanged, this);
}

void JSAggregateVisibleData::visibleVelocityChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleVelocityChanged, this);
}

void JSAggregateVisibleData::visibleOrientationChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleOrientationChanged, this);
}

void JSAggregateVisibleData::visibleOrientationVelChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleOrientationVelChanged, this);
}

void JSAggregateVisibleData::visibleScaleChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleScaleChanged, this);
}

void JSAggregateVisibleData::visibleMeshChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleMeshChanged, this);
}

void JSAggregateVisibleData::visiblePhysicsChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visiblePhysicsChanged, this);
}

} // namespace JS
} // namespace Sirikata
<commit_msg>Fix JSProxyVisibleData removeListener calls.<commit_after>// Copyright (c) 2011 Sirikata Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

#include "JSVisibleData.hpp"

namespace Sirikata {
namespace JS {

JSVisibleData::~JSVisibleData()
{
}

void JSVisibleData::clearFromParent() {
    // We're guaranteed by shared_ptrs and our reference counting that
    // this destructor is only called once there are no more
    // ProxyObjectPtrs and no v8 visibles referring to this data,
    // allowing us to clear this out of the JSVisibleManager.
    if (mParent) mParent->removeVisibleData(this);
}

void JSVisibleData::disable() {
    mParent = NULL;
}

// JSProxyVisibleData
JSProxyVisibleData::JSProxyVisibleData(JSVisibleDataListener* parent, ProxyObjectPtr from)
 : JSVisibleData(parent),
   proxy(from)
{
    proxy->PositionProvider::addListener(this);
    proxy->MeshProvider::addListener(this);
}

JSProxyVisibleData::~JSProxyVisibleData() {
    if (proxy) {
        proxy->PositionProvider::removeListener(this);
        proxy->MeshProvider::removeListener(this);
    }
    clearFromParent();
}

const SpaceObjectReference& JSProxyVisibleData::id() {
    return proxy->getObjectReference();
}

const SpaceObjectReference& JSProxyVisibleData::observer() {
    return proxy->getOwnerPresenceID();
}

void JSProxyVisibleData::disable() {
    if (proxy) {
        proxy->PositionProvider::removeListener(this);
        proxy->MeshProvider::removeListener(this);
        proxy.reset();
    }
    JSVisibleData::disable();
}

// PositionListener Interface
void JSProxyVisibleData::updateLocation(ProxyObjectPtr obj,
    const TimedMotionVector3f &newLocation, const TimedMotionQuaternion& newOrient,
    const AggregateBoundingInfo& newBounds, const SpaceObjectReference& sporef)
{
    // FIXME this interface doesn't let us tell exactly what's updated, so we
    // have to send notifications for everything
    notify(&JSVisibleDataEventListener::visiblePositionChanged, this);
    notify(&JSVisibleDataEventListener::visibleVelocityChanged, this);
    notify(&JSVisibleDataEventListener::visibleOrientationChanged, this);
    notify(&JSVisibleDataEventListener::visibleOrientationVelChanged, this);
    // scale handled by MeshListener interface
}
// MeshListener Interface
void JSProxyVisibleData::onSetMesh(ProxyObjectPtr proxy, Transfer::URI const& newMesh, const SpaceObjectReference& sporef) {
    notify(&JSVisibleDataEventListener::visibleMeshChanged, this);
}
void JSProxyVisibleData::onSetScale(ProxyObjectPtr proxy, float32 newScale,const SpaceObjectReference& sporef ) {
    notify(&JSVisibleDataEventListener::visibleScaleChanged, this);
}
void JSProxyVisibleData::onSetPhysics(ProxyObjectPtr proxy, const String& phy,const SpaceObjectReference& sporef ) {
    notify(&JSVisibleDataEventListener::visiblePhysicsChanged, this);
}
void JSProxyVisibleData::onSetIsAggregate(ProxyObjectPtr proxy, bool isAggregate, const SpaceObjectReference& sporef ) {
    // Not exposed to VisibleDataEventListeners
}

// JSRestoredVisibleData
JSRestoredVisibleData::JSRestoredVisibleData(JSVisibleDataListener* parent, const SpaceObjectReference& from, JSVisibleDataPtr fromData)
 : JSVisibleData(parent),
   sporefToListenTo(from)
{
    if (fromData) {
        assert(from == fromData->id());
        updateFrom(*fromData);
    }
}

JSRestoredVisibleData::JSRestoredVisibleData(JSVisibleDataListener* parent, const SpaceObjectReference& from, const IPresencePropertiesRead& orig)
 : JSVisibleData(parent),
   sporefToListenTo(from)
{
    updateFrom(orig);
}

JSRestoredVisibleData::~JSRestoredVisibleData() {
    clearFromParent();
}

const SpaceObjectReference& JSRestoredVisibleData::id() {
    return sporefToListenTo;
}

const SpaceObjectReference& JSRestoredVisibleData::observer() {
    // No observer...
    static SpaceObjectReference n = SpaceObjectReference::null();
    return n;
}

void JSRestoredVisibleData::updateFrom(const IPresencePropertiesRead& orig) {
    setLocation(orig.location());
    setOrientation(orig.orientation());
    setBounds(orig.bounds());
    setMesh(orig.mesh());
    setPhysics(orig.physics());

}

// JSAggregateVisibleData
JSAggregateVisibleData::JSAggregateVisibleData(JSVisibleDataListener* parent, const SpaceObjectReference& vis)
 : JSVisibleData(parent),
   refcount(0),
   selfPtr(),
   mBest(SpaceObjectReference::null())
{
    // Note NULL so we don't get notifications since they'd only happen on
    // destruction since we hold strong refs currently.
    // We use null index to indicate no associated presence
    mChildren[SpaceObjectReference::null()] =
        JSVisibleDataPtr(new JSRestoredVisibleData(NULL, vis) );
}

JSAggregateVisibleData::~JSAggregateVisibleData() {
    clearFromParent();
}

const SpaceObjectReference& JSAggregateVisibleData::id() {
    return getBestChild()->id();
}

const SpaceObjectReference& JSAggregateVisibleData::observer() {
    // Can't specify one observer...
    static SpaceObjectReference n = SpaceObjectReference::null();
    return n;
}

// IPresencePropertiesRead Interface
TimedMotionVector3f JSAggregateVisibleData::location() const{
    return getBestChild()->location();
}

TimedMotionQuaternion JSAggregateVisibleData::orientation() const{
    return getBestChild()->orientation();
}

AggregateBoundingInfo JSAggregateVisibleData::bounds() const{
    return getBestChild()->bounds();
}

Transfer::URI JSAggregateVisibleData::mesh() const{
    return getBestChild()->mesh();
}

String JSAggregateVisibleData::physics() const{
    return getBestChild()->physics();
}

bool JSAggregateVisibleData::isAggregate() const{
    return getBestChild()->isAggregate();
}

ObjectReference JSAggregateVisibleData::parent() const{
    return getBestChild()->parent();
}

void JSAggregateVisibleData::removeVisibleData(JSVisibleData* data) {
    Mutex::scoped_lock locker (childMutex);
    mChildren.erase(data->observer());
}

void JSAggregateVisibleData::updateFrom(ProxyObjectPtr proxy) {
    Mutex::scoped_lock locker (childMutex);
    if (mChildren.find(proxy->getObjectReference()) == mChildren.end()) {
        // Note that we currently pass in NULL so we don't get
        // notifications. We'd only get them upon clearing our children list in
        // the destructor anyway.
        JSVisibleDataPtr jsvisdata(new JSProxyVisibleData(NULL, proxy));
        jsvisdata->addListener(this); // JSVisibleDataEventListener
        mChildren[proxy->getObjectReference()] = jsvisdata;
    }
    mBest = proxy->getObjectReference();
}

void JSAggregateVisibleData::updateFrom(const IPresencePropertiesRead& props) {
    Mutex::scoped_lock locker (childMutex);
    if (mChildren.find(SpaceObjectReference::null()) != mChildren.end()) {
        std::tr1::dynamic_pointer_cast<JSRestoredVisibleData>(mChildren[SpaceObjectReference::null()])->updateFrom(props);
    }
    // We don't update mBest because either it's already this, or we have a
    // Proxy, which is preferable.
}

JSVisibleDataPtr JSAggregateVisibleData::getBestChild() const{
    Mutex::scoped_lock locker (const_cast<Mutex&>(childMutex));
    assert(!mChildren.empty());
    assert(mChildren.find(mBest) != mChildren.end());
    return mChildren.find(mBest)->second;
}

void JSAggregateVisibleData::incref(JSVisibleDataPtr self) {
    selfPtr = self;
    refcount++;
}

void JSAggregateVisibleData::decref() {
    assert(refcount > 0);
    refcount--;
    if (refcount == 0) selfPtr.reset();
}

bool JSAggregateVisibleData::visibleToPresence() const {
    return refcount > 0;
}

void JSAggregateVisibleData::disable() {
    Mutex::scoped_lock locker (childMutex);
    mChildren.clear();
    JSVisibleData::disable();
}

void JSAggregateVisibleData::visiblePositionChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visiblePositionChanged, this);
}

void JSAggregateVisibleData::visibleVelocityChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleVelocityChanged, this);
}

void JSAggregateVisibleData::visibleOrientationChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleOrientationChanged, this);
}

void JSAggregateVisibleData::visibleOrientationVelChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleOrientationVelChanged, this);
}

void JSAggregateVisibleData::visibleScaleChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleScaleChanged, this);
}

void JSAggregateVisibleData::visibleMeshChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visibleMeshChanged, this);
}

void JSAggregateVisibleData::visiblePhysicsChanged(JSVisibleData* data) {
    notify(&JSVisibleDataEventListener::visiblePhysicsChanged, this);
}

} // namespace JS
} // namespace Sirikata
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////
//  Button.cpp
//  Implementation of the Class Button
//  Created on:      02-Mar-2015 9:17:12 PM
///////////////////////////////////////////////////////////

#include "Button.h"

Button::Button(){}

Button::Button(unsigned int width, unsigned int height, int backgroundColor, int textColor, int borderColor){
	x = 0;
	y = 0;
	this->setSize(width,height);
	this->setColors(backgroundColor,textColor,borderColor);
	this->isRound = false;
	init();
}

Button::Button(unsigned int radius, int backgroundColor, int textColor, int borderColor){
	x = radius;
	y = radius;
	this->setSize(2*radius,2*radius);
	this->setColors(backgroundColor,textColor,borderColor);
	this->isRound = true;
	init();
}

Button::~Button(){

}

/*
 * Initialization of several common parameters
 */
void Button::init(){
	type = 0x30;
	isButton = true;
	touched = false;
	borderWidth = 2;
	debounceTime = DEBOUNCE;
	lastMillis = millis();
}

void Button::drawBackground(int color){
	//Fill background
	if(!isRound){
		Tft.fillRectangle(x+borderWidth, y+borderWidth, w-(2*borderWidth),h-(2*borderWidth),color);
  }else{
  	int radius = (w>>1)-borderWidth;
  	Tft.fillCircle(x+radius+borderWidth,y+radius+borderWidth,radius,color);
  }
}

void Button::drawBorder(){
  int xPos = x;
  int width = w;
  byte yPos = y;
  byte height = h;
	for(byte i=borderWidth; i!=0;i--){
		if(!isRound){
			Tft.drawRectangle(xPos++,yPos++,width--,height--,borderColor);
			width--;
			height--;
		}else{
			int radius = width>>1;
			Tft.drawCircle(x+radius,y+radius,(radius)-i,borderColor);
		}
	}
}

void Button::drawText(){
	//Count characters to center on the button - Nice trick from the Tft2 library
	if(*text){
		char* chars = text;
		char size = 0;
		while(*chars){
			*chars++;
			size++;
		}
		//Calculate centered position of the text
		int stringX = x+(w-size*6*borderWidth)/2;
		int stringY = y+(h-8*borderWidth)/2;
		Tft.drawString(text,stringX,stringY,borderWidth,fgColor);
	}
}

void Button::clear(){
	byte textSize = getTextSize();
	if(textSize){
		for(int i = textSize-1; i >= 0; i--)
		{
				text[i] = 0;
		}
	}
}

byte Button::getTextLength(char* c){
	char size = 0;
	if(*c){
    char* chars = c;
    while(*chars){
      *chars++;
      size++;
    }
  }
  return size;
}

byte Button::getTextSize(){
  return getTextLength(text);
}

void Button::setDebounce(unsigned int d){
	debounceTime = d;
}

/**
 * Sets the event handler: The function that should be called whenever the touched
 * event is detected.
 */
void Button::setEventHandler(void (*functionPointer)(Button *)){
	eventHandler = functionPointer;
}

/**
 * Shows the widget on the screen. This method must be overriden by the widget to
 * show the particular widget. It should be a pure virtual function: (i.e. virtual
 * void function() = 0;
 */
void Button::show(){
	drawBackground(bgColor);
	drawText();
	update();
}

void Button::setNum(int num){
	clear();
	char numChar[DISPLAY_SIZE];
	char chars = 0;
	while(num >= 10)	// Extract characters representing the powers of ten
	{
		numChar[chars++] = num%10;
		num /= 10;
	}
	numChar[chars++] = num;
	for(int j = 0; j < chars; j++)//DISPLAY_SIZE; j++)
	{
		text[chars-1-j] = '0'+numChar[j];
	}
	text[chars]=0;

	drawBackground(bgColor);
	update();
}

void Button::setText(char* _text){
  text = _text;
}

char* Button::getText(){
  return text;
}

long Button::getNum(){
	char size = getTextSize();
	long result = 0;
	for(int i = 0; i<size; i++){
		if(text[i] == '.') break;  // Only process integer side
		result = result * 10 + text[i]-'0';
	}
	return result;
}

void Button::fitToText(){
  if(*text){
    char* chars = text;
    char size = 0;
    while(*chars){
      *chars++;
      size++;
    }
    w = size * 6 * borderWidth + 6;
    h = 8 * borderWidth + 8;
    //drawString(text,x+5,y+5,2,textColor);
  }
}

//Overriden methods
/**
 * Check if the touched point is within bounds of this widget.
 */
bool Button::checkTouch(Point* p){
	//Serial.print("Checking button ");Serial.println(text);
	if(lastMillis + debounceTime < millis()){
		if((p->x > x) && (p->x < x + w) && (p->y > y) && (p->y < y+h)){
			touched = !touched;
			eventHandler(this);
			lastMillis = millis();
			//block = true;
			//Serial.print("Button ");Serial.print(text);Serial.println(" pressed");
			return false;
		}
	}
	// if block is true return false, so canvas will not continue to
	// process the event.
	return !block;
}

/*
 * This is the update() method.
 */
void Button::update(){
	//drawBackground(bgColor);
	drawText();
	drawBorder();
}

/*
 * This method is called by the canvas and passes a pointer to it.
 * The button class uses this pointer to get a pointer to the
 * touched point, if any, and calls the checkTouch routine to detect
 * if the button was touched.
 */
/*void Button::update(Canvas* c){
	checkTouch(c->touchedPoint);
}*/
<commit_msg>Fixed a missing memory allocation for text in Button.<commit_after>///////////////////////////////////////////////////////////
//  Button.cpp
//  Implementation of the Class Button
//  Created on:      02-Mar-2015 9:17:12 PM
///////////////////////////////////////////////////////////

#include "Button.h"

Button::Button(){}

Button::Button(unsigned int width, unsigned int height, int backgroundColor, int textColor, int borderColor){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	x = 0;
	y = 0;
	this->setSize(width,height);
	this->setColors(backgroundColor,textColor,borderColor);
	this->isRound = false;
	init();
}

Button::Button(unsigned int radius, int backgroundColor, int textColor, int borderColor){
	if(text = (char *)malloc(DISPLAY_SIZE+1)) memset(text,0,DISPLAY_SIZE+1); //Had to add one more, to avoid some bug
	x = radius;
	y = radius;
	this->setSize(2*radius,2*radius);
	this->setColors(backgroundColor,textColor,borderColor);
	this->isRound = true;
	init();
}

Button::~Button(){

}

/*
 * Initialization of several common parameters
 */
void Button::init(){
	type = 0x30;
	isButton = true;
	touched = false;
	borderWidth = 2;
	debounceTime = DEBOUNCE;
	lastMillis = millis();
}

void Button::drawBackground(int color){
	//Fill background
	if(!isRound){
		Tft.fillRectangle(x+borderWidth, y+borderWidth, w-(2*borderWidth),h-(2*borderWidth),color);
  }else{
  	int radius = (w>>1)-borderWidth;
  	Tft.fillCircle(x+radius+borderWidth,y+radius+borderWidth,radius,color);
  }
}

void Button::drawBorder(){
  int xPos = x;
  int width = w;
  byte yPos = y;
  byte height = h;
	for(byte i=borderWidth; i!=0;i--){
		if(!isRound){
			Tft.drawRectangle(xPos++,yPos++,width--,height--,borderColor);
			width--;
			height--;
		}else{
			int radius = width>>1;
			Tft.drawCircle(x+radius,y+radius,(radius)-i,borderColor);
		}
	}
}

void Button::drawText(){
	//Count characters to center on the button - Nice trick from the Tft2 library
	if(*text){
		char* chars = text;
		char size = 0;
		while(*chars){
			*chars++;
			size++;
		}
		//Calculate centered position of the text
		int stringX = x+(w-size*6*borderWidth)/2;
		int stringY = y+(h-8*borderWidth)/2;
		Tft.drawString(text,stringX,stringY,borderWidth,fgColor);
	}
}

void Button::clear(){
	byte textSize = getTextSize();
	if(textSize){
		for(int i = textSize-1; i >= 0; i--)
		{
				text[i] = 0;
		}
	}
}

byte Button::getTextLength(char* c){
	char size = 0;
	if(*c){
    char* chars = c;
    while(*chars){
      *chars++;
      size++;
    }
  }
  return size;
}

byte Button::getTextSize(){
  return getTextLength(text);
}

void Button::setDebounce(unsigned int d){
	debounceTime = d;
}

/**
 * Sets the event handler: The function that should be called whenever the touched
 * event is detected.
 */
void Button::setEventHandler(void (*functionPointer)(Button *)){
	eventHandler = functionPointer;
}

/**
 * Shows the widget on the screen. This method must be overriden by the widget to
 * show the particular widget. It should be a pure virtual function: (i.e. virtual
 * void function() = 0;
 */
void Button::show(){
	drawBackground(bgColor);
	drawText();
	update();
}

void Button::setNum(int num){
	clear();
	//Serial.println("Text cleared in setNum");Serial.print("Num to be processed: ");Serial.println(num);
	char numChar[DISPLAY_SIZE];
	char chars = 0;

	while(num > 0)	// Extract characters representing the powers of ten
	{
		numChar[chars++] = '0'+num%10;
		num /= 10;
		//Serial.print("Num after loop: ");Serial.println(numChar[chars-1]);
	}

	// Reverse the order of the characters
	for(int j = chars-1; j >= 0; j--)//DISPLAY_SIZE; j++)
	{
		text[j] = numChar[chars-1-j];
	}
	text[chars]=0;

	//Serial.print("Num entered: ");Serial.println(text);
	drawBackground(bgColor);
	update();
}

void Button::setText(char* _text){
  text = _text;
}

char* Button::getText(){
  return text;
}

long Button::getNum(){
	char size = getTextSize();
	long result = 0;
	for(int i = 0; i<size; i++){
		if(text[i] == '.') break;  // Only process integer side
		result = result * 10 + text[i]-'0';
	}
	return result;
}

void Button::fitToText(){
  if(*text){
    char* chars = text;
    char size = 0;
    while(*chars){
      *chars++;
      size++;
    }
    w = size * 6 * borderWidth + 6;
    h = 8 * borderWidth + 8;
    //drawString(text,x+5,y+5,2,textColor);
  }
}

//Overriden methods
/**
 * Check if the touched point is within bounds of this widget.
 */
bool Button::checkTouch(Point* p){
	//Serial.print("Checking button ");Serial.println(text);
	if(lastMillis + debounceTime < millis()){
		if((p->x > x) && (p->x < x + w) && (p->y > y) && (p->y < y+h)){
			touched = !touched;
			eventHandler(this);
			lastMillis = millis();
			//block = true;
			//Serial.print("Button ");Serial.print(text);Serial.println(" pressed");
			return false;
		}
	}
	// if block is true return false, so canvas will not continue to
	// process the event.
	return !block;
}

/*
 * This is the update() method.
 */
void Button::update(){
	//drawBackground(bgColor);
	drawText();
	drawBorder();
}

/*
 * This method is called by the canvas and passes a pointer to it.
 * The button class uses this pointer to get a pointer to the
 * touched point, if any, and calls the checkTouch routine to detect
 * if the button was touched.
 */
/*void Button::update(Canvas* c){
	checkTouch(c->touchedPoint);
}*/
<|endoftext|>


<commit_before>#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_MUTEX_HPP
// (C) Copyright 2007-8 Anthony Williams
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <pthread.h>
#include <boost/utility.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/assert.hpp>
#include <errno.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"

#ifdef _POSIX_TIMEOUTS
#if _POSIX_TIMEOUTS >= 0
#define BOOST_PTHREAD_HAS_TIMEDLOCK
#endif
#endif

#include <boost/config/abi_prefix.hpp>

namespace boost
{
    class mutex:
        boost::noncopyable
    {
    private:
        pthread_mutex_t m;
    public:
        mutex()
        {
            int const res=pthread_mutex_init(&m,NULL);
            if(res)
            {
                throw thread_resource_error("Cannot initialize a mutex", res);
            }
        }
        ~mutex()
        {
            int ret;
            do {
                ret = pthread_mutex_destroy(&m);
            } while (ret == EINTR);
            BOOST_VERIFY(!ret);
        }

        void lock()
        {
            int ret;
            do {
                ret = pthread_mutex_lock(&m);
            } while (ret == EINTR);
            BOOST_VERIFY(!ret);
        }

        void unlock()
        {
            int ret;
            do {
                ret = pthread_mutex_unlock(&m);
            } while (ret == EINTR);
            BOOST_VERIFY(!ret);
        }

        bool try_lock()
        {
            int res;
            do {
                res = pthread_mutex_trylock(&m);
            } while (res == EINTR);
            BOOST_ASSERT(!res || res==EBUSY);
            return !res;
        }

        typedef pthread_mutex_t* native_handle_type;
        native_handle_type native_handle()
        {
            return &m;
        }

        typedef unique_lock<mutex> scoped_lock;
        typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
    };

    typedef mutex try_mutex;

    class timed_mutex:
        boost::noncopyable
    {
    private:
        pthread_mutex_t m;
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
        pthread_cond_t cond;
        bool is_locked;
#endif
    public:
        timed_mutex()
        {
            int const res=pthread_mutex_init(&m,NULL);
            if(res)
            {
                throw thread_resource_error("Cannot initialize a mutex", res);
            }
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
            int const res2=pthread_cond_init(&cond,NULL);
            if(res2)
            {
                BOOST_VERIFY(!pthread_mutex_destroy(&m));
                throw thread_resource_error("Cannot initialize a condition variable", res2);
            }
            is_locked=false;
#endif
        }
        ~timed_mutex()
        {
            BOOST_VERIFY(!pthread_mutex_destroy(&m));
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
            BOOST_VERIFY(!pthread_cond_destroy(&cond));
#endif
        }

        template<typename TimeDuration>
        bool timed_lock(TimeDuration const & relative_time)
        {
            return timed_lock(get_system_time()+relative_time);
        }
        bool timed_lock(boost::xtime const & absolute_time)
        {
            return timed_lock(system_time(absolute_time));
        }

#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
        void lock()
        {
            BOOST_VERIFY(!pthread_mutex_lock(&m));
        }

        void unlock()
        {
            BOOST_VERIFY(!pthread_mutex_unlock(&m));
        }

        bool try_lock()
        {
            int const res=pthread_mutex_trylock(&m);
            BOOST_ASSERT(!res || res==EBUSY);
            return !res;
        }
        bool timed_lock(system_time const & abs_time)
        {
            struct timespec const timeout=detail::get_timespec(abs_time);
            int const res=pthread_mutex_timedlock(&m,&timeout);
            BOOST_ASSERT(!res || res==ETIMEDOUT);
            return !res;
        }

        typedef pthread_mutex_t* native_handle_type;
        native_handle_type native_handle()
        {
            return &m;
        }

#else
        void lock()
        {
            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
            while(is_locked)
            {
                BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
            }
            is_locked=true;
        }

        void unlock()
        {
            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
            is_locked=false;
            BOOST_VERIFY(!pthread_cond_signal(&cond));
        }

        bool try_lock()
        {
            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
            if(is_locked)
            {
                return false;
            }
            is_locked=true;
            return true;
        }

        bool timed_lock(system_time const & abs_time)
        {
            struct timespec const timeout=detail::get_timespec(abs_time);
            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
            while(is_locked)
            {
                int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
                if(cond_res==ETIMEDOUT)
                {
                    return false;
                }
                BOOST_ASSERT(!cond_res);
            }
            is_locked=true;
            return true;
        }
#endif

        typedef unique_lock<timed_mutex> scoped_timed_lock;
        typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
        typedef scoped_timed_lock scoped_lock;
    };

}

#include <boost/config/abi_suffix.hpp>

#endif
<commit_msg>boost::mutex should not check for error upon destroying the pthread mutex because that's kinda useless.<commit_after>#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_MUTEX_HPP
// (C) Copyright 2007-8 Anthony Williams
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <pthread.h>
#include <boost/utility.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/assert.hpp>
#include <errno.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"

#ifdef _POSIX_TIMEOUTS
#if _POSIX_TIMEOUTS >= 0
#define BOOST_PTHREAD_HAS_TIMEDLOCK
#endif
#endif

#include <boost/config/abi_prefix.hpp>

namespace boost
{
    class mutex:
        boost::noncopyable
    {
    private:
        pthread_mutex_t m;
    public:
        mutex()
        {
            int const res=pthread_mutex_init(&m,NULL);
            if(res)
            {
                throw thread_resource_error("Cannot initialize a mutex", res);
            }
        }
        ~mutex()
        {
            int ret;
            do {
                ret = pthread_mutex_destroy(&m);
            } while (ret == EINTR);
        }

        void lock()
        {
            int ret;
            do {
                ret = pthread_mutex_lock(&m);
            } while (ret == EINTR);
            BOOST_VERIFY(!ret);
        }

        void unlock()
        {
            int ret;
            do {
                ret = pthread_mutex_unlock(&m);
            } while (ret == EINTR);
            BOOST_VERIFY(!ret);
        }

        bool try_lock()
        {
            int res;
            do {
                res = pthread_mutex_trylock(&m);
            } while (res == EINTR);
            BOOST_ASSERT(!res || res==EBUSY);
            return !res;
        }

        typedef pthread_mutex_t* native_handle_type;
        native_handle_type native_handle()
        {
            return &m;
        }

        typedef unique_lock<mutex> scoped_lock;
        typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
    };

    typedef mutex try_mutex;

    class timed_mutex:
        boost::noncopyable
    {
    private:
        pthread_mutex_t m;
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
        pthread_cond_t cond;
        bool is_locked;
#endif
    public:
        timed_mutex()
        {
            int const res=pthread_mutex_init(&m,NULL);
            if(res)
            {
                throw thread_resource_error("Cannot initialize a mutex", res);
            }
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
            int const res2=pthread_cond_init(&cond,NULL);
            if(res2)
            {
                BOOST_VERIFY(!pthread_mutex_destroy(&m));
                throw thread_resource_error("Cannot initialize a condition variable", res2);
            }
            is_locked=false;
#endif
        }
        ~timed_mutex()
        {
            BOOST_VERIFY(!pthread_mutex_destroy(&m));
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
            BOOST_VERIFY(!pthread_cond_destroy(&cond));
#endif
        }

        template<typename TimeDuration>
        bool timed_lock(TimeDuration const & relative_time)
        {
            return timed_lock(get_system_time()+relative_time);
        }
        bool timed_lock(boost::xtime const & absolute_time)
        {
            return timed_lock(system_time(absolute_time));
        }

#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
        void lock()
        {
            BOOST_VERIFY(!pthread_mutex_lock(&m));
        }

        void unlock()
        {
            BOOST_VERIFY(!pthread_mutex_unlock(&m));
        }

        bool try_lock()
        {
            int const res=pthread_mutex_trylock(&m);
            BOOST_ASSERT(!res || res==EBUSY);
            return !res;
        }
        bool timed_lock(system_time const & abs_time)
        {
            struct timespec const timeout=detail::get_timespec(abs_time);
            int const res=pthread_mutex_timedlock(&m,&timeout);
            BOOST_ASSERT(!res || res==ETIMEDOUT);
            return !res;
        }

        typedef pthread_mutex_t* native_handle_type;
        native_handle_type native_handle()
        {
            return &m;
        }

#else
        void lock()
        {
            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
            while(is_locked)
            {
                BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
            }
            is_locked=true;
        }

        void unlock()
        {
            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
            is_locked=false;
            BOOST_VERIFY(!pthread_cond_signal(&cond));
        }

        bool try_lock()
        {
            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
            if(is_locked)
            {
                return false;
            }
            is_locked=true;
            return true;
        }

        bool timed_lock(system_time const & abs_time)
        {
            struct timespec const timeout=detail::get_timespec(abs_time);
            boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
            while(is_locked)
            {
                int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
                if(cond_res==ETIMEDOUT)
                {
                    return false;
                }
                BOOST_ASSERT(!cond_res);
            }
            is_locked=true;
            return true;
        }
#endif

        typedef unique_lock<timed_mutex> scoped_timed_lock;
        typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
        typedef scoped_timed_lock scoped_lock;
    };

}

#include <boost/config/abi_suffix.hpp>

#endif
<|endoftext|>