<commit_before>//===- DlltoolDriver.cpp - dlltool.exe-compatible driver ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines an interface to a dlltool.exe-compatible driver.
//
//===----------------------------------------------------------------------===//

#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/COFFModuleDefinition.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Path.h"

#include <string>
#include <vector>

using namespace llvm;
using namespace llvm::object;
using namespace llvm::COFF;

namespace {

enum {
  OPT_INVALID = 0,
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
#include "Options.inc"
#undef OPTION
};

#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Options.inc"
#undef PREFIX

static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
  {X1, X2, X10,         X11,         OPT_##ID, llvm::opt::Option::KIND##Class, \
   X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
#include "Options.inc"
#undef OPTION
};

class DllOptTable : public llvm::opt::OptTable {
public:
  DllOptTable() : OptTable(infoTable, false) {}
};

} // namespace

std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;

// Opens a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
Optional<MemoryBufferRef> openFile(StringRef Path) {
  ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = MemoryBuffer::getFile(Path);

  if (std::error_code EC = MB.getError()) {
    llvm::errs() << "fail openFile: " << EC.message() << "\n";
    return None;
  }

  MemoryBufferRef MBRef = MB.get()->getMemBufferRef();
  OwningMBs.push_back(std::move(MB.get())); // take ownership
  return MBRef;
}

static MachineTypes getEmulation(StringRef S) {
  return StringSwitch<MachineTypes>(S)
      .Case("i386", IMAGE_FILE_MACHINE_I386)
      .Case("i386:x86-64", IMAGE_FILE_MACHINE_AMD64)
      .Case("arm", IMAGE_FILE_MACHINE_ARMNT)
      .Case("arm64", IMAGE_FILE_MACHINE_ARM64)
      .Default(IMAGE_FILE_MACHINE_UNKNOWN);
}

static std::string getImplibPath(std::string Path) {
  SmallString<128> Out = StringRef("lib");
  Out.append(Path);
  sys::path::replace_extension(Out, ".a");
  return Out.str();
}

int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
  DllOptTable Table;
  unsigned MissingIndex;
  unsigned MissingCount;
  llvm::opt::InputArgList Args =
      Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
  if (MissingCount) {
    llvm::errs() << Args.getArgString(MissingIndex) << ": missing argument\n";
    return 1;
  }

  // Handle when no input or output is specified
  if (Args.hasArgNoClaim(OPT_INPUT) ||
      (!Args.hasArgNoClaim(OPT_d) && !Args.hasArgNoClaim(OPT_l))) {
    Table.PrintHelp(outs(), ArgsArr[0], "dlltool", false);
    llvm::outs() << "\nTARGETS: i386, i386:x86-64, arm\n";
    return 1;
  }

  if (!Args.hasArgNoClaim(OPT_m) && Args.hasArgNoClaim(OPT_d)) {
    llvm::errs() << "error: no target machine specified\n"
                 << "supported targets: i386, i386:x86-64, arm\n";
    return 1;
  }

  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
    llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";

  if (!Args.hasArg(OPT_d)) {
    llvm::errs() << "no definition file specified\n";
    return 1;
  }

  Optional<MemoryBufferRef> MB = openFile(Args.getLastArg(OPT_d)->getValue());
  if (!MB)
    return 1;

  if (!MB->getBufferSize()) {
    llvm::errs() << "definition file empty\n";
    return 1;
  }

  COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
  if (auto *Arg = Args.getLastArg(OPT_m))
    Machine = getEmulation(Arg->getValue());

  if (Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
    llvm::errs() << "unknown target\n";
    return 1;
  }

  Expected<COFFModuleDefinition> Def =
      parseCOFFModuleDefinition(*MB, Machine, true);

  if (!Def) {
    llvm::errs() << "error parsing definition\n"
                 << errorToErrorCode(Def.takeError()).message();
    return 1;
  }

  // Do this after the parser because parseCOFFModuleDefinition sets OutputFile.
  if (auto *Arg = Args.getLastArg(OPT_D))
    Def->OutputFile = Arg->getValue();

  if (Def->OutputFile.empty()) {
    llvm::errs() << "no output file specified\n";
    return 1;
  }

  std::string Path = Args.getLastArgValue(OPT_l);
  if (Path.empty())
    Path = getImplibPath(Def->OutputFile);

  if (Machine == IMAGE_FILE_MACHINE_I386 && Args.getLastArg(OPT_k)) {
    for (COFFShortExport& E : Def->Exports) {
      if (E.isWeak() || (!E.Name.empty() && E.Name[0] == '?'))
        continue;
      E.SymbolName = E.Name;
      // Trim off the trailing decoration. Symbols will always have a
      // starting prefix here (either _ for cdecl/stdcall, @ for fastcall
      // or ? for C++ functions). (Vectorcall functions also will end up having
      // a prefix here, even if they shouldn't.)
      E.Name = E.Name.substr(0, E.Name.find('@', 1));
      // By making sure E.SymbolName != E.Name for decorated symbols,
      // writeImportLibrary writes these symbols with the type
      // IMPORT_NAME_UNDECORATE.
    }
  }

  if (writeImportLibrary(Def->OutputFile, Path, Def->Exports, Machine, true))
    return 1;
  return 0;
}
<commit_msg>[llvm-dlltool] Improve an error message when unable to open files. NFC.<commit_after>//===- DlltoolDriver.cpp - dlltool.exe-compatible driver ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines an interface to a dlltool.exe-compatible driver.
//
//===----------------------------------------------------------------------===//

#include "llvm/ToolDrivers/llvm-dlltool/DlltoolDriver.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/COFFModuleDefinition.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Path.h"

#include <string>
#include <vector>

using namespace llvm;
using namespace llvm::object;
using namespace llvm::COFF;

namespace {

enum {
  OPT_INVALID = 0,
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
#include "Options.inc"
#undef OPTION
};

#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Options.inc"
#undef PREFIX

static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
  {X1, X2, X10,         X11,         OPT_##ID, llvm::opt::Option::KIND##Class, \
   X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
#include "Options.inc"
#undef OPTION
};

class DllOptTable : public llvm::opt::OptTable {
public:
  DllOptTable() : OptTable(infoTable, false) {}
};

} // namespace

std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;

// Opens a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
Optional<MemoryBufferRef> openFile(StringRef Path) {
  ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> MB = MemoryBuffer::getFile(Path);

  if (std::error_code EC = MB.getError()) {
    llvm::errs() << "cannot open file " << Path << ": " << EC.message() << "\n";
    return None;
  }

  MemoryBufferRef MBRef = MB.get()->getMemBufferRef();
  OwningMBs.push_back(std::move(MB.get())); // take ownership
  return MBRef;
}

static MachineTypes getEmulation(StringRef S) {
  return StringSwitch<MachineTypes>(S)
      .Case("i386", IMAGE_FILE_MACHINE_I386)
      .Case("i386:x86-64", IMAGE_FILE_MACHINE_AMD64)
      .Case("arm", IMAGE_FILE_MACHINE_ARMNT)
      .Case("arm64", IMAGE_FILE_MACHINE_ARM64)
      .Default(IMAGE_FILE_MACHINE_UNKNOWN);
}

static std::string getImplibPath(std::string Path) {
  SmallString<128> Out = StringRef("lib");
  Out.append(Path);
  sys::path::replace_extension(Out, ".a");
  return Out.str();
}

int llvm::dlltoolDriverMain(llvm::ArrayRef<const char *> ArgsArr) {
  DllOptTable Table;
  unsigned MissingIndex;
  unsigned MissingCount;
  llvm::opt::InputArgList Args =
      Table.ParseArgs(ArgsArr.slice(1), MissingIndex, MissingCount);
  if (MissingCount) {
    llvm::errs() << Args.getArgString(MissingIndex) << ": missing argument\n";
    return 1;
  }

  // Handle when no input or output is specified
  if (Args.hasArgNoClaim(OPT_INPUT) ||
      (!Args.hasArgNoClaim(OPT_d) && !Args.hasArgNoClaim(OPT_l))) {
    Table.PrintHelp(outs(), ArgsArr[0], "dlltool", false);
    llvm::outs() << "\nTARGETS: i386, i386:x86-64, arm\n";
    return 1;
  }

  if (!Args.hasArgNoClaim(OPT_m) && Args.hasArgNoClaim(OPT_d)) {
    llvm::errs() << "error: no target machine specified\n"
                 << "supported targets: i386, i386:x86-64, arm\n";
    return 1;
  }

  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
    llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";

  if (!Args.hasArg(OPT_d)) {
    llvm::errs() << "no definition file specified\n";
    return 1;
  }

  Optional<MemoryBufferRef> MB = openFile(Args.getLastArg(OPT_d)->getValue());
  if (!MB)
    return 1;

  if (!MB->getBufferSize()) {
    llvm::errs() << "definition file empty\n";
    return 1;
  }

  COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN;
  if (auto *Arg = Args.getLastArg(OPT_m))
    Machine = getEmulation(Arg->getValue());

  if (Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
    llvm::errs() << "unknown target\n";
    return 1;
  }

  Expected<COFFModuleDefinition> Def =
      parseCOFFModuleDefinition(*MB, Machine, true);

  if (!Def) {
    llvm::errs() << "error parsing definition\n"
                 << errorToErrorCode(Def.takeError()).message();
    return 1;
  }

  // Do this after the parser because parseCOFFModuleDefinition sets OutputFile.
  if (auto *Arg = Args.getLastArg(OPT_D))
    Def->OutputFile = Arg->getValue();

  if (Def->OutputFile.empty()) {
    llvm::errs() << "no output file specified\n";
    return 1;
  }

  std::string Path = Args.getLastArgValue(OPT_l);
  if (Path.empty())
    Path = getImplibPath(Def->OutputFile);

  if (Machine == IMAGE_FILE_MACHINE_I386 && Args.getLastArg(OPT_k)) {
    for (COFFShortExport& E : Def->Exports) {
      if (E.isWeak() || (!E.Name.empty() && E.Name[0] == '?'))
        continue;
      E.SymbolName = E.Name;
      // Trim off the trailing decoration. Symbols will always have a
      // starting prefix here (either _ for cdecl/stdcall, @ for fastcall
      // or ? for C++ functions). (Vectorcall functions also will end up having
      // a prefix here, even if they shouldn't.)
      E.Name = E.Name.substr(0, E.Name.find('@', 1));
      // By making sure E.SymbolName != E.Name for decorated symbols,
      // writeImportLibrary writes these symbols with the type
      // IMPORT_NAME_UNDECORATE.
    }
  }

  if (writeImportLibrary(Def->OutputFile, Path, Def->Exports, Machine, true))
    return 1;
  return 0;
}
<|endoftext|>


<commit_before>#include "AppDelegate.h"
#include "Chapter9.h"

USING_NS_CC;

AppDelegate::AppDelegate() {

}

AppDelegate::~AppDelegate()
{
}

//if you want a different context,just modify the value of glContextAttrs
//it will takes effect on all platforms
void AppDelegate::initGLContextAttrs()
{
    //set OpenGL context attributions,now can only set six attributions:
    //red,green,blue,alpha,depth,stencil
    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};

    GLView::setGLContextAttrs(glContextAttrs);
}

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        glview = GLViewImpl::create("My Game");
        director->setOpenGLView(glview);
    }

    // turn on display FPS
    director->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0 / 60);

    // create a scene. it's an autorelease object
    auto scene = Chapter9::createScene();

    // run
    director->runWithScene(scene);

    return true;
}

// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground() {
    Director::getInstance()->stopAnimation();

    // if you use SimpleAudioEngine, it must be pause
    // SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
    Director::getInstance()->startAnimation();

    // if you use SimpleAudioEngine, it must resume here
    // SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}
<commit_msg>comment out showing display stats<commit_after>#include "AppDelegate.h"
#include "Chapter9.h"

USING_NS_CC;

AppDelegate::AppDelegate() {

}

AppDelegate::~AppDelegate()
{
}

//if you want a different context,just modify the value of glContextAttrs
//it will takes effect on all platforms
void AppDelegate::initGLContextAttrs()
{
    //set OpenGL context attributions,now can only set six attributions:
    //red,green,blue,alpha,depth,stencil
    GLContextAttrs glContextAttrs = {8, 8, 8, 8, 24, 8};

    GLView::setGLContextAttrs(glContextAttrs);
}

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
        glview = GLViewImpl::create("My Game");
        director->setOpenGLView(glview);
    }

    // turn on display FPS
    //director->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    director->setAnimationInterval(1.0 / 60);

    // create a scene. it's an autorelease object
    auto scene = Chapter9::createScene();

    // run
    director->runWithScene(scene);

    return true;
}

// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground() {
    Director::getInstance()->stopAnimation();

    // if you use SimpleAudioEngine, it must be pause
    // SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}

// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
    Director::getInstance()->startAnimation();

    // if you use SimpleAudioEngine, it must resume here
    // SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}
<|endoftext|>


<commit_before>// Copyright 2016 Chirstopher Torres (Raven), L3nn0x
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ccharserver.h"
#include "ccharclient.h"
#include "ccharisc.h"
#include "epackettype.h"
#include "platform_defines.h"
#include "connection.h"
#include <unordered_set>
#include "isc_client_status.h"
#include "logconsole.h"

using namespace RoseCommon;

void update_status(const Packet::IscClientStatus& packet, CCharServer& server) {
    auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
    if (auto user = server.get_user(packet.get_charId()); user) {
        logger->debug("Char {} now has status {}", packet.get_charId(), packet.get_status());
        const bool isSwitching = user.value()->get_status() == User::Status::SWITCHING ? true : false;
        user.value()->set_status(packet.get_status());
        if (user.value()->get_status() == User::Status::CONNECTED && isSwitching) {
            // reload the map
            Core::CharacterTable characterTable{};
            auto conn = Core::connectionPool.getConnection<Core::Osirose>();

            auto charRes = conn(sqlpp::select(characterTable.map)
                                  .from(characterTable).where(characterTable.id == user.value()->get_charId()));

            if (charRes.empty()) {
                logger->error("Error while trying to access the updated map of {}", user.value()->get_charId());
                return;
            }
            user.value()->set_mapId(charRes.front().map);
        }
    } else {
        logger->error("Error, got status packet for un-loaded {} client", packet.get_charId());
    }
}

CCharServer::CCharServer(bool _isc, CCharServer *server) : CRoseServer(_isc), client_count_(0), server_count_(0), iscServer_(server) {
    register_dispatcher(std::function{update_status});

    reactor_thread = std::thread([this]() {
        for (auto [res, task] = work_queue.pop_front(); res;) {
            {
                std::lock_guard<std::recursive_mutex> lock(access);
                std::invoke(std::move(task), *this);
            }
            auto [tmp_res, tmp_task] = work_queue.pop_front();
            res = tmp_res;
            task = std::move(tmp_task);
        }
    });
}

CCharServer::~CCharServer() {
    socket_[SocketType::Client]->shutdown();
    work_queue.kill();
    reactor_thread.join();
}

void CCharServer::OnAccepted(std::unique_ptr<Core::INetwork> _sock) {
  //if (_sock->is_active()) {
    // Do Something?
    std::string _address = _sock->get_address();
    if (IsISCServer() == false) {
      std::lock_guard<std::mutex> lock(client_list_mutex_);
      std::shared_ptr<CCharClient> nClient = std::make_shared<CCharClient>(this, std::move(_sock));
      nClient->set_id(client_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "[{}] Client connected from: {}", nClient->get_id(),
                       _address.c_str());
      client_list_.push_front(std::move(nClient));
    } else {
      std::lock_guard<std::mutex> lock(isc_list_mutex_);
      std::shared_ptr<CCharISC> nClient = std::make_shared<CCharISC>(this, std::move(_sock));
      nClient->set_id(server_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "Server connected from: {}", _address.c_str() );
      isc_list_.push_front(std::move(nClient));
    }
  //}
}

void CCharServer::register_maps(CCharISC* isc, const std::vector<uint16_t>& maps) {
    std::shared_ptr<RoseCommon::CRoseClient> ptr;
    for (const auto& p : isc_list_) {
        if (p.get() == isc) {
            ptr = p;
            break;
        }
    }
    if (!ptr) {
        logger_->error("ISC server not found when registering maps!");
        return;
    }
    for (const auto& m : maps) {
        this->maps[m] = ptr;
    }
}

void CCharServer::transfer(RoseCommon::Packet::IscTransfer&& P) {
    const auto& m = P.get_maps();
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    if (m.empty()) {
        for (const auto& [m, p] : maps) {
            if (auto ptr = p.lock()) {
                set.insert(ptr);
            }
        }
    } else if (m.size() == 1 && m[0] == 0) {
        dispatch_packet(RoseCommon::fetchPacket<true>(static_cast<const uint8_t*>(P.get_blob().data())));
        return;
    } else {
        for (const auto& mm : m) {
            if (auto ptr = maps[mm].lock()) {
                set.insert(ptr);
            }
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::transfer_char(RoseCommon::Packet::IscTransferChar&& P) {
    std::vector<uint16_t> maps;
    for (auto name : P.get_names()) {
        if (const auto user = get_user(name); user) {
            maps.push_back(user.value()->get_mapId());
        }
    }
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    for (auto map : maps) {
        if (auto ptr = this->maps[map].lock()) {
            set.insert(ptr);
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::send_map(uint16_t map, const RoseCommon::CRosePacket& p) {
    auto packet = RoseCommon::Packet::IscTransfer::create({map});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);
    if (auto ptr = maps[map].lock()) {
        ptr->send(packet);
    }
}

void CCharServer::send_char(uint32_t character, const RoseCommon::CRosePacket& p) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    auto packet = RoseCommon::Packet::IscTransferChar::create({user.value()->get_name()});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);

    if (auto ptr = maps[user.value()->get_mapId()].lock()) {
        ptr->send(packet);
    }
}

void CCharServer::send_char(const std::string& character, const RoseCommon::CRosePacket& p) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    auto packet = RoseCommon::Packet::IscTransferChar::create({character});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);

    if (auto ptr = maps[user.value()->get_mapId()].lock()) {
        ptr->send(packet);
    }
}

bool CCharServer::dispatch_packet(std::unique_ptr<RoseCommon::CRosePacket>&& packet) {
    if (!packet) {
        return false;
    }
    if (!dispatcher.is_supported(*packet.get())) {
        return false;
    }
    work_queue.push_back([packet = std::move(packet)](CCharServer& server) mutable {
        server.dispatcher.dispatch(std::move(packet), server);
    });
    return true;
}

std::optional<const User*const> CCharServer::get_user(const std::string& name) const {
    for (auto [k, v] : users) {
        if (v.get_name() == name) {
            return {&v};
        }
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint32_t id) const {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(const std::string& name) {
    for (auto [k, v] : users) {
        if (v.get_name() == name) {
            return {&v};
        }
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint32_t id) {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

void CCharServer::load_user(uint32_t id) {
    Core::CharacterTable characterTable{};

    auto conn = Core::connectionPool.getConnection<Core::Osirose>();

    auto charRes = conn(sqlpp::select(characterTable.name, characterTable.map)
                          .from(characterTable).where(characterTable.id == id));

    if (charRes.empty()) {
        return;
    }
    User user(charRes.front().name, id, charRes.front().map);
    user.set_party(partys.get_party(id)); // we load the party if there is one for that character
}

void CCharServer::unload_user(uint32_t id) {
    users.erase(id);
}
<commit_msg>Update ccharserver.cpp<commit_after>// Copyright 2016 Chirstopher Torres (Raven), L3nn0x
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http ://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "ccharserver.h"
#include "ccharclient.h"
#include "ccharisc.h"
#include "epackettype.h"
#include "platform_defines.h"
#include "connection.h"
#include <unordered_set>
#include "isc_client_status.h"
#include "logconsole.h"

using namespace RoseCommon;

void update_status(const Packet::IscClientStatus& packet, CCharServer& server) {
    auto logger = Core::CLog::GetLogger(Core::log_type::GENERAL).lock();
    if (auto user = server.get_user(packet.get_charId()); user) {
        logger->debug("Char {} now has status {}", packet.get_charId(), packet.get_status());
        const bool isSwitching = user.value()->get_status() == User::Status::SWITCHING ? true : false;
        user.value()->set_status(packet.get_status());
        if (user.value()->get_status() == User::Status::CONNECTED && isSwitching) {
            // reload the map
            Core::CharacterTable characterTable{};
            auto conn = Core::connectionPool.getConnection<Core::Osirose>();

            auto charRes = conn(sqlpp::select(characterTable.map)
                                  .from(characterTable).where(characterTable.id == user.value()->get_charId()));

            if (charRes.empty()) {
                logger->error("Error while trying to access the updated map of {}", user.value()->get_charId());
                return;
            }
            user.value()->set_mapId(charRes.front().map);
        }
    } else {
        logger->error("Error, got status packet for un-loaded {} client", packet.get_charId());
    }
}

CCharServer::CCharServer(bool _isc, CCharServer *server) : CRoseServer(_isc), client_count_(0), server_count_(0), iscServer_(server) {
    register_dispatcher(std::function{update_status});

    reactor_thread = std::thread([this]() {
        for (auto [res, task] = work_queue.pop_front(); res;) {
            {
                std::lock_guard<std::recursive_mutex> lock(access);
                std::invoke(std::move(task), *this);
            }
            auto [tmp_res, tmp_task] = work_queue.pop_front();
            res = tmp_res;
            task = std::move(tmp_task);
        }
    });
}

CCharServer::~CCharServer() {
    socket_[SocketType::Client]->shutdown();
    work_queue.kill();
    reactor_thread.join();
}

void CCharServer::OnAccepted(std::unique_ptr<Core::INetwork> _sock) {
  //if (_sock->is_active()) {
    // Do Something?
    std::string _address = _sock->get_address();
    if (IsISCServer() == false) {
      std::lock_guard<std::mutex> lock(client_list_mutex_);
      std::shared_ptr<CCharClient> nClient = std::make_shared<CCharClient>(this, std::move(_sock));
      nClient->set_id(client_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "[{}] Client connected from: {}", nClient->get_id(),
                       _address.c_str());
      client_list_.push_front(std::move(nClient));
    } else {
      std::lock_guard<std::mutex> lock(isc_list_mutex_);
      std::shared_ptr<CCharISC> nClient = std::make_shared<CCharISC>(this, std::move(_sock));
      nClient->set_id(server_count_++);
      nClient->set_update_time( Core::Time::GetTickCount() );
      nClient->set_active(true);
      nClient->start_recv();
      logger_->info( "Server connected from: {}", _address.c_str() );
      isc_list_.push_front(std::move(nClient));
    }
  //}
}

void CCharServer::register_maps(CCharISC* isc, const std::vector<uint16_t>& maps) {
    std::shared_ptr<RoseCommon::CRoseClient> ptr;
    for (const auto& p : isc_list_) {
        if (p.get() == isc) {
            ptr = p;
            break;
        }
    }
    if (!ptr) {
        logger_->error("ISC server not found when registering maps!");
        return;
    }
    for (const auto& m : maps) {
        this->maps[m] = ptr;
    }
}

void CCharServer::transfer(RoseCommon::Packet::IscTransfer&& P) {
    const auto& m = P.get_maps();
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    if (m.empty()) {
        for (const auto& [m, p] : maps) {
            if (auto ptr = p.lock()) {
                set.insert(ptr);
            }
        }
    } else if (m.size() == 1 && m[0] == 0) {
        dispatch_packet(RoseCommon::fetchPacket<true>(static_cast<const uint8_t*>(P.get_blob().data())));
        return;
    } else {
        for (const auto& mm : m) {
            if (auto ptr = maps[mm].lock()) {
                set.insert(ptr);
            }
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::transfer_char(RoseCommon::Packet::IscTransferChar&& P) {
    std::vector<uint16_t> maps;
    for (auto name : P.get_names()) {
        if (const auto user = get_user(name); user) {
            maps.push_back(user.value()->get_mapId());
        }
    }
    std::unordered_set<std::shared_ptr<CRoseClient>> set;
    for (auto map : maps) {
        if (auto ptr = this->maps[map].lock()) {
            set.insert(ptr);
        }
    }
    for (auto ptr : set) {
        ptr->send(P);
    }
}

void CCharServer::send_map(uint16_t map, const RoseCommon::CRosePacket& p) {
    auto packet = RoseCommon::Packet::IscTransfer::create({map});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);
    if (auto ptr = maps[map].lock()) {
        ptr->send(packet);
    }
}

void CCharServer::send_char(uint32_t character, const RoseCommon::CRosePacket& p) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    auto packet = RoseCommon::Packet::IscTransferChar::create({user.value()->get_name()});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);

    if (auto ptr = maps[user.value()->get_mapId()].lock()) {
        ptr->send(packet);
    }
}

void CCharServer::send_char(const std::string& character, const RoseCommon::CRosePacket& p) {
    const auto user = get_user(character);
    if (!user) {
        return;
    }
    auto packet = RoseCommon::Packet::IscTransferChar::create({character});
    std::vector<uint8_t> blob;
    p.write_to_vector(blob);
    packet.set_blob(blob);

    if (auto ptr = maps[user.value()->get_mapId()].lock()) {
        ptr->send(packet);
    }
}

bool CCharServer::dispatch_packet(std::unique_ptr<RoseCommon::CRosePacket>&& packet) {
    if (!packet) {
        return false;
    }
    if (!dispatcher.is_supported(*packet.get())) {
        return false;
    }
    work_queue.push_back([packet = std::move(packet)](CCharServer& server) mutable {
        server.dispatcher.dispatch(std::move(packet), server);
    });
    return true;
}

std::optional<const User*const> CCharServer::get_user(const std::string& name) const {
    for (auto [k, v] : users) {
        if (v.get_name() == name) {
            return {&v};
        }
    }
    return {};
}

std::optional<const User*const> CCharServer::get_user(uint32_t id) const {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(const std::string& name) {
    for (auto [k, v] : users) {
        if (v.get_name() == name) {
            return {&v};
        }
    }
    return {};
}

std::optional<User*const> CCharServer::get_user(uint32_t id) {
    if (auto it = users.find(id); it != users.end()) {
        return {&it->second};
    }
    return {};
}

void CCharServer::load_user(std::weak_ptr<CCharClient> client, uint32_t id) {
    Core::CharacterTable characterTable{};

    auto conn = Core::connectionPool.getConnection<Core::Osirose>();

    auto charRes = conn(sqlpp::select(characterTable.name, characterTable.map)
                          .from(characterTable).where(characterTable.id == id));

    if (charRes.empty()) {
        return;
    }
    User user(client, charRes.front().name, id, charRes.front().map);
    user.set_party(partys.get_party(id)); // we load the party if there is one for that character
}

void CCharServer::unload_user(uint32_t id) {
    users.erase(id);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 David Wicks, sansumbrella.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "Phrase.hpp"
#include "phrase/Hold.hpp"
#include "phrase/Retime.hpp"

namespace choreograph
{

template<typename T>
class SequencePhrase;

template<typename T>
using SequencePhraseRef = std::shared_ptr<SequencePhrase<T>>;

template<typename T>
class Sequence;

template<typename T>
using SequenceRef = std::shared_ptr<Sequence<T>>;

template<typename T>
using SequenceUniqueRef = std::unique_ptr<Sequence<T>>;

///
/// A Sequence of motions.
/// Our essential compositional tool, describing all the transformations to one element.
/// A kind of platonic idea of an animation sequence; this describes a motion without giving it an output.
///
template<typename T>
class Sequence
{
public:
  // Sequences always need to have some valid value.
  Sequence() = delete;

  /// Construct a Sequence with an initial \a value.
  explicit Sequence( const T &value ):
    _initial_value( value )
  {}

  /// Construct a Sequence with and initial \a value.
  explicit Sequence( T &&value ):
    _initial_value( std::forward<T>( value ) )
  {}

  /// Construct a Sequence by duplicating the phrases in an \a other sequence.
  Sequence( const Sequence<T> &other ):
    _initial_value( other._initial_value ),
    _phrases( other._phrases ),
    _duration( calcDuration() )
  {}

  explicit Sequence( const std::vector<PhraseRef<T>> &phrases ):
    _initial_value( phrases.front()->getStartValue() ),
    _phrases( phrases ),
    _duration( calcDuration() )
  {}

  explicit Sequence( const PhraseRef<T> &phrase ):
    _initial_value( phrase->getStartValue() ),
    _duration( phrase->getDuration() ),
    _phrases( 1, phrase )
  {}

  //
  // Sequence manipulation and expansion.
  //

  /// Set the end \a value of Sequence.
  /// If there are no Phrases, this is the initial value.
  /// Otherwise, this is an instantaneous hold at \a value.
  Sequence<T>& set( const T &value );

  /// Append a Phrase to the sequence.
  /// Constructs a Phrase starting with Sequence's end value and
  /// ending with \a value after \a duration.
  /// Forwards additional arguments to the end of the Phrase constructor.
  /// Example calls look like:
  /// sequence.then<RampTo>( targetValue, duration, EaseInOutQuad() ).then<Hold>( holdValue, duration );
  template<template <typename> class PhraseT, typename... Args>
  Sequence<T>& then( const T &value, Time duration, Args&&... args );

  /// Append an existing phrase to the Sequence.
  Sequence<T>& then( const PhraseRef<T> &phrase_ptr );

  /// Append all Phrases from another Sequence to this Sequence.
  Sequence<T>& then( const Sequence<T> &next );

  //
  // Sequence conversion.
  //

  /// Returns a Phrase that encapsulates this Sequence.
  /// Duplicates the Sequence, so future changes to this do not affect the Phrase.
  PhraseRef<T> asPhrase() const { return std::make_shared<SequencePhrase<T>>( *this ); }

  /// Returns a Sequence containing the phrases between Times from and to.
  /// Partial phrases at the beginning and end are wrapped in ClipPhrases.
  Sequence slice( Time from, Time to );

  //
  // Phrase<T> Equivalents.
  //

  /// Returns the Sequence value at \a atTime.
  T getValue( Time atTime ) const;

  /// Returns the Sequence value at \a atTime, wrapped past the end of .
  T getValueWrapped( Time time, Time inflectionPoint = 0.0f ) const { return getValue( wrapTime( time, getDuration(), inflectionPoint ) ); }

  /// Returns the value at the end of the Sequence.
  T getEndValue() const { return _phrases.empty() ? _initial_value : _phrases.back()->getEndValue(); }

  /// Returns the value at the beginning of the Sequence.
  T getStartValue() const { return _phrases.empty() ? _initial_value : _phrases.front()->getStartValue(); }

  /// Returns the Sequence duration.
  Time getDuration() const { return _duration; }

  //
  //
  //

  /// Returns which phrase we are in at each point in time.
  /// Note that you cannot inflect over the start or finish.
  std::pair<size_t, size_t> getInflectionPoints( Time t1, Time t2 ) const;

  Time getTimeAtInflection( size_t inflection ) const;

  /// Returns the number of phrases in the Sequence.
  size_t getPhraseCount() const { return _phrases.size(); }

  /// Calculate and return the Sequence duration.
  Time calcDuration() const;

private:
  // Storing shared_ptr's to Phrases requires their duration to be immutable.
  std::vector<PhraseRef<T>> _phrases;
  T                         _initial_value;
  Time                      _duration = 0;
};

//=================================================
// Sequence Template Implementation.
//=================================================

template<typename T>
Sequence<T>& Sequence<T>::set( const T &value )
{
  if( _phrases.empty() ) {
    _initial_value = value;
  }
  else {
    then<Hold>( value, 0.0f );
  }
  return *this;
}

template<typename T>
template<template <typename> class PhraseT, typename... Args>
Sequence<T>& Sequence<T>::then( const T &value, Time duration, Args&&... args )
{
  _phrases.emplace_back( std::make_unique<PhraseT<T>>( duration, this->getEndValue(), value, std::forward<Args>(args)... ) );
  _duration += duration;

  return *this;
}

template<typename T>
Sequence<T>& Sequence<T>::then( const PhraseRef<T> &phrase )
{
  _phrases.push_back( phrase );
  _duration += phrase->getDuration();

  return *this;
}

template<typename T>
Sequence<T>& Sequence<T>::then( const Sequence<T> &next )
{
  _phrases.insert( _phrases.end(), next._phrases.cbegin(), next._phrases.cend() );
  _duration = calcDuration();

  return *this;
}

template<typename T>
T Sequence<T>::getValue( Time atTime ) const
{
  if( atTime < 0.0f )
  {
    return _initial_value;
  }
  else if ( atTime >= this->getDuration() )
  {
    return getEndValue();
  }

  for( const auto &phrase : _phrases )
  {
    if( phrase->getDuration() < atTime ) {
      atTime -= phrase->getDuration();
    }
    else {
      return phrase->getValue( atTime );
    }
  }
  // past the end, get the final value
  // this should be unreachable, given that we return early if time >= duration
  return getEndValue();
}

template<typename T>
Time Sequence<T>::calcDuration() const
{
  Time sum = 0;
  for( const auto &phrase : _phrases ) {
    sum += phrase->getDuration();
  }
  return sum;
}

template<typename T>
std::pair<size_t, size_t> Sequence<T>::getInflectionPoints( Time t1, Time t2 ) const
{
  auto output = std::make_pair<size_t, size_t>( 0, 0 );
  auto set = std::make_pair( false, false );

  for( size_t i = 0; i < _phrases.size(); i += 1 )
  {
    const auto duration = _phrases.at( i )->getDuration();

    if( duration < t1 ) {
      t1 -= duration;
    }
    else if( ! set.first ) {
      output.first = i;
      set.first = true;
    }

    if( duration < t2 ) {
      t2 -= duration;
    }
    else if( ! set.second ) {
      output.second = i;
      set.second = true;
    }

    if( set.first && set.second ) {
      break;
    }
  }

  if( ! set.second ) {
    output.second = _phrases.size() - 1;
  }

  return output;
}

template<typename T>
Time Sequence<T>::getTimeAtInflection( size_t inflection ) const
{
  Time t = 0;
  while( inflection != 0 ) {
    t += _phrases.at( inflection - 1 )->getDuration();
    inflection -= 1;
  }
  return t;
}

template<typename T>
Sequence<T> Sequence<T>::slice( Time from, Time to )
{
  if( _phrases.empty() ) {
    return Sequence<T>( std::make_shared<Hold<T>>( to - from, _initial_value ) );
  }

  // the indices of the first and last Phrases in our time range.
  auto points = getInflectionPoints( from, to );
  const auto &first = _phrases.at( points.first );
  const auto &last = _phrases.at( points.second );

  if( points.first < points.second ) {
    // construct vector from range [begin, end)
    auto begin = _phrases.begin() + points.first;
    auto end = _phrases.begin() + points.second + 1;
    std::vector<PhraseRef<T>> phrases( begin, end );

    Time t1 = from - getTimeAtInflection( points.first );
    Time t2 = to - getTimeAtInflection( points.second );

    phrases[0] = std::make_shared<ClipPhrase<T>>( first, t1, first->getDuration() );
    phrases[phrases.size() - 1] = std::make_shared<ClipPhrase<T>>( last, 0, t2 );

    return Sequence<T>( phrases );
  }
  else {
    Time t = getTimeAtInflection( points.first );
    return Sequence<T>( std::make_shared<ClipPhrase<T>>( first, from - t, to - t ) );
  }
}

//=================================================
// Convenience functions.
//=================================================

template<typename T>
SequenceRef<T> createSequence( T &&initialValue )
{
  return std::make_shared<Sequence<T>>( std::forward<T>( initialValue ) );
}

template<typename T>
SequenceRef<T> createSequence( const T &initialValue )
{
  return std::make_shared<Sequence<T>>( initialValue );
}

//=================================================
// Sequence Decorator Phrase.
//=================================================

/// A Phrase that wraps up a Sequence.
/// Note that the Sequence becomes immutable, as it is inaccessible outside of the phrase.
template<typename T>
class SequencePhrase: public Phrase<T>
{
public:
  /// Construct a Phrase that wraps a Sequence, allowing it to be passed into meta-Phrases.
  SequencePhrase( const Sequence<T> &sequence ):
    Phrase<T>( sequence.getDuration() ),
    _sequence( sequence )
  {}

  /// Returns the interpolated value at the given time.
  T getValue( Time atTime ) const override { return _sequence.getValue( atTime ); }

  T getStartValue() const override { return _sequence.getStartValue(); }

  T getEndValue() const override { return _sequence.getEndValue(); }
private:
  Sequence<T>  _sequence;
};

} // namespace choreograph
<commit_msg>Explicitly use default constructors for Sequence.<commit_after>/*
 * Copyright (c) 2014 David Wicks, sansumbrella.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "Phrase.hpp"
#include "phrase/Hold.hpp"
#include "phrase/Retime.hpp"

namespace choreograph
{

template<typename T>
class SequencePhrase;

template<typename T>
using SequencePhraseRef = std::shared_ptr<SequencePhrase<T>>;

template<typename T>
class Sequence;

template<typename T>
using SequenceRef = std::shared_ptr<Sequence<T>>;

template<typename T>
using SequenceUniqueRef = std::unique_ptr<Sequence<T>>;

///
/// A Sequence of motions.
/// Our essential compositional tool, describing all the transformations to one element.
/// A kind of platonic idea of an animation sequence; this describes a motion without giving it an output.
///
template<typename T>
class Sequence
{
public:
  // Sequences always need to have some valid value.
  Sequence() = delete;

  /// Construct a Sequence with an initial \a value.
  explicit Sequence( const T &value ):
    _initial_value( value )
  {}

  /// Construct a Sequence with and initial \a value.
  explicit Sequence( T &&value ):
    _initial_value( std::forward<T>( value ) )
  {}

  /// Default copy and move assignment and construction work fine.
  Sequence( const Sequence<T> &other ) = default;
  Sequence( Sequence<T> &&other ) = default;
  Sequence& operator= (const Sequence<T> &rhs) = default;
  Sequence& operator= (Sequence<T> &&rhs) = default;

  explicit Sequence( const std::vector<PhraseRef<T>> &phrases ):
    _phrases( phrases ),
    _initial_value( phrases.front()->getStartValue() ),
    _duration( calcDuration() )
  {}

  explicit Sequence( const PhraseRef<T> &phrase ):
    _duration( phrase->getDuration() ),
    _initial_value( phrase->getStartValue() ),
    _phrases( 1, phrase )
  {}

  //
  // Sequence manipulation and expansion.
  //

  /// Set the end \a value of Sequence.
  /// If there are no Phrases, this is the initial value.
  /// Otherwise, this is an instantaneous hold at \a value.
  Sequence<T>& set( const T &value );

  /// Append a Phrase to the sequence.
  /// Constructs a Phrase starting with Sequence's end value and
  /// ending with \a value after \a duration.
  /// Forwards additional arguments to the end of the Phrase constructor.
  /// Example calls look like:
  /// sequence.then<RampTo>( targetValue, duration, EaseInOutQuad() ).then<Hold>( holdValue, duration );
  template<template <typename> class PhraseT, typename... Args>
  Sequence<T>& then( const T &value, Time duration, Args&&... args );

  /// Append an existing phrase to the Sequence.
  Sequence<T>& then( const PhraseRef<T> &phrase_ptr );

  /// Append all Phrases from another Sequence to this Sequence.
  Sequence<T>& then( const Sequence<T> &next );

  //
  // Sequence conversion.
  //

  /// Returns a Phrase that encapsulates this Sequence.
  /// Duplicates the Sequence, so future changes to this do not affect the Phrase.
  PhraseRef<T> asPhrase() const { return std::make_shared<SequencePhrase<T>>( *this ); }

  /// Returns a Sequence containing the phrases between Times from and to.
  /// Partial phrases at the beginning and end are wrapped in ClipPhrases.
  Sequence slice( Time from, Time to );

  //
  // Phrase<T> Equivalents.
  //

  /// Returns the Sequence value at \a atTime.
  T getValue( Time atTime ) const;

  /// Returns the Sequence value at \a atTime, wrapped past the end of .
  T getValueWrapped( Time time, Time inflectionPoint = 0.0f ) const { return getValue( wrapTime( time, getDuration(), inflectionPoint ) ); }

  /// Returns the value at the end of the Sequence.
  T getEndValue() const { return _phrases.empty() ? _initial_value : _phrases.back()->getEndValue(); }

  /// Returns the value at the beginning of the Sequence.
  T getStartValue() const { return _phrases.empty() ? _initial_value : _phrases.front()->getStartValue(); }

  /// Returns the Sequence duration.
  Time getDuration() const { return _duration; }

  //
  //
  //

  /// Returns which phrase we are in at each point in time.
  /// Note that you cannot inflect over the start or finish.
  std::pair<size_t, size_t> getInflectionPoints( Time t1, Time t2 ) const;

  Time getTimeAtInflection( size_t inflection ) const;

  /// Returns the number of phrases in the Sequence.
  size_t getPhraseCount() const { return _phrases.size(); }

  /// Calculate and return the Sequence duration.
  Time calcDuration() const;

private:
  // Storing shared_ptr's to Phrases requires their duration to be immutable.
  std::vector<PhraseRef<T>> _phrases;
  T                         _initial_value;
  Time                      _duration = 0;
};

//=================================================
// Sequence Template Implementation.
//=================================================

template<typename T>
Sequence<T>& Sequence<T>::set( const T &value )
{
  if( _phrases.empty() ) {
    _initial_value = value;
  }
  else {
    then<Hold>( value, 0.0f );
  }
  return *this;
}

template<typename T>
template<template <typename> class PhraseT, typename... Args>
Sequence<T>& Sequence<T>::then( const T &value, Time duration, Args&&... args )
{
  _phrases.emplace_back( std::make_unique<PhraseT<T>>( duration, this->getEndValue(), value, std::forward<Args>(args)... ) );
  _duration += duration;

  return *this;
}

template<typename T>
Sequence<T>& Sequence<T>::then( const PhraseRef<T> &phrase )
{
  _phrases.push_back( phrase );
  _duration += phrase->getDuration();

  return *this;
}

template<typename T>
Sequence<T>& Sequence<T>::then( const Sequence<T> &next )
{
  _phrases.insert( _phrases.end(), next._phrases.cbegin(), next._phrases.cend() );
  _duration = calcDuration();

  return *this;
}

template<typename T>
T Sequence<T>::getValue( Time atTime ) const
{
  if( atTime < 0.0f )
  {
    return _initial_value;
  }
  else if ( atTime >= this->getDuration() )
  {
    return getEndValue();
  }

  for( const auto &phrase : _phrases )
  {
    if( phrase->getDuration() < atTime ) {
      atTime -= phrase->getDuration();
    }
    else {
      return phrase->getValue( atTime );
    }
  }
  // past the end, get the final value
  // this should be unreachable, given that we return early if time >= duration
  return getEndValue();
}

template<typename T>
Time Sequence<T>::calcDuration() const
{
  Time sum = 0;
  for( const auto &phrase : _phrases ) {
    sum += phrase->getDuration();
  }
  return sum;
}

template<typename T>
std::pair<size_t, size_t> Sequence<T>::getInflectionPoints( Time t1, Time t2 ) const
{
  auto output = std::make_pair<size_t, size_t>( 0, 0 );
  auto set = std::make_pair( false, false );

  for( size_t i = 0; i < _phrases.size(); i += 1 )
  {
    const auto duration = _phrases.at( i )->getDuration();

    if( duration < t1 ) {
      t1 -= duration;
    }
    else if( ! set.first ) {
      output.first = i;
      set.first = true;
    }

    if( duration < t2 ) {
      t2 -= duration;
    }
    else if( ! set.second ) {
      output.second = i;
      set.second = true;
    }

    if( set.first && set.second ) {
      break;
    }
  }

  if( ! set.second ) {
    output.second = _phrases.size() - 1;
  }

  return output;
}

template<typename T>
Time Sequence<T>::getTimeAtInflection( size_t inflection ) const
{
  Time t = 0;
  while( inflection != 0 ) {
    t += _phrases.at( inflection - 1 )->getDuration();
    inflection -= 1;
  }
  return t;
}

template<typename T>
Sequence<T> Sequence<T>::slice( Time from, Time to )
{
  if( _phrases.empty() ) {
    return Sequence<T>( std::make_shared<Hold<T>>( to - from, _initial_value ) );
  }

  // the indices of the first and last Phrases in our time range.
  auto points = getInflectionPoints( from, to );
  const auto &first = _phrases.at( points.first );
  const auto &last = _phrases.at( points.second );

  if( points.first < points.second ) {
    // construct vector from range [begin, end)
    auto begin = _phrases.begin() + points.first;
    auto end = _phrases.begin() + points.second + 1;
    std::vector<PhraseRef<T>> phrases( begin, end );

    Time t1 = from - getTimeAtInflection( points.first );
    Time t2 = to - getTimeAtInflection( points.second );

    phrases[0] = std::make_shared<ClipPhrase<T>>( first, t1, first->getDuration() );
    phrases[phrases.size() - 1] = std::make_shared<ClipPhrase<T>>( last, 0, t2 );

    return Sequence<T>( phrases );
  }
  else {
    Time t = getTimeAtInflection( points.first );
    return Sequence<T>( std::make_shared<ClipPhrase<T>>( first, from - t, to - t ) );
  }
}

//=================================================
// Convenience functions.
//=================================================

template<typename T>
SequenceRef<T> createSequence( T &&initialValue )
{
  return std::make_shared<Sequence<T>>( std::forward<T>( initialValue ) );
}

template<typename T>
SequenceRef<T> createSequence( const T &initialValue )
{
  return std::make_shared<Sequence<T>>( initialValue );
}

//=================================================
// Sequence Decorator Phrase.
//=================================================

/// A Phrase that wraps up a Sequence.
/// Note that the Sequence becomes immutable, as it is inaccessible outside of the phrase.
template<typename T>
class SequencePhrase: public Phrase<T>
{
public:
  /// Construct a Phrase that wraps a Sequence, allowing it to be passed into meta-Phrases.
  SequencePhrase( const Sequence<T> &sequence ):
    Phrase<T>( sequence.getDuration() ),
    _sequence( sequence )
  {}

  /// Returns the interpolated value at the given time.
  T getValue( Time atTime ) const override { return _sequence.getValue( atTime ); }

  T getStartValue() const override { return _sequence.getStartValue(); }

  T getEndValue() const override { return _sequence.getEndValue(); }
private:
  Sequence<T>  _sequence;
};

} // namespace choreograph
<|endoftext|>


<commit_before>//
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
//
#pragma once

#include <memory>
#include "acl.h"
#include "rocprogram.hpp"
#include "top.hpp"
#include "rocprintf.hpp"

#ifndef WITHOUT_HSA_BACKEND

namespace roc {

#define MAX_INFO_STRING_LEN 0x40

enum ROC_ARG_TYPE {
  ROC_ARGTYPE_ERROR = 0,
  ROC_ARGTYPE_POINTER,
  ROC_ARGTYPE_VALUE,
  ROC_ARGTYPE_REFERENCE,
  ROC_ARGTYPE_IMAGE,
  ROC_ARGTYPE_SAMPLER,
  ROC_ARGTYPE_HIDDEN_GLOBAL_OFFSET_X,
  ROC_ARGTYPE_HIDDEN_GLOBAL_OFFSET_Y,
  ROC_ARGTYPE_HIDDEN_GLOBAL_OFFSET_Z,
  ROC_ARGTYPE_HIDDEN_PRINTF_BUFFER,
  ROC_ARGTYPE_HIDDEN_DEFAULT_QUEUE,
  ROC_ARGTYPE_HIDDEN_COMPLETION_ACTION,
  ROC_ARGTYPE_HIDDEN_NONE,
  ROC_ARGMAX_ARG_TYPES
};

enum ROC_ADDRESS_QUALIFIER {
  ROC_ADDRESS_ERROR = 0,
  ROC_ADDRESS_GLOBAL,
  ROC_ADDRESS_CONSTANT,
  ROC_ADDRESS_LOCAL,
  ROC_MAX_ADDRESS_QUALIFIERS
};

enum ROC_DATA_TYPE {
  ROC_DATATYPE_ERROR = 0,
  ROC_DATATYPE_B1,
  ROC_DATATYPE_B8,
  ROC_DATATYPE_B16,
  ROC_DATATYPE_B32,
  ROC_DATATYPE_B64,
  ROC_DATATYPE_S8,
  ROC_DATATYPE_S16,
  ROC_DATATYPE_S32,
  ROC_DATATYPE_S64,
  ROC_DATATYPE_U8,
  ROC_DATATYPE_U16,
  ROC_DATATYPE_U32,
  ROC_DATATYPE_U64,
  ROC_DATATYPE_F16,
  ROC_DATATYPE_F32,
  ROC_DATATYPE_F64,
  ROC_DATATYPE_STRUCT,
  ROC_DATATYPE_OPAQUE,
  ROC_DATATYPE_MAX_TYPES
};

enum ROC_ACCESS_TYPE {
  ROC_ACCESS_TYPE_NONE = 0,
  ROC_ACCESS_TYPE_RO,
  ROC_ACCESS_TYPE_WO,
  ROC_ACCESS_TYPE_RW
};

class Kernel : public device::Kernel {
 public:
  struct Argument {
    uint index_;                      //!< Argument's index in the OCL signature
    std::string name_;                //!< Argument's name
    std::string typeName_;            //!< Argument's type name
    uint size_;                       //!< Size in bytes
    uint alignment_;                  //!< Argument's alignment
    uint pointeeAlignment_;           //!< Alignment of the data pointed to
    ROC_ARG_TYPE type_;               //!< Type of the argument
    ROC_ADDRESS_QUALIFIER addrQual_;  //!< Address qualifier of the argument
    ROC_DATA_TYPE dataType_;          //!< The type of data
    ROC_ACCESS_TYPE access_;          //!< Access type for the argument
  };

  Kernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle,
         const uint32_t workgroupGroupSegmentByteSize,
         const uint32_t workitemPrivateSegmentByteSize, const uint32_t kernargSegmentByteSize,
         const uint32_t kernargSegmentAlignment);

  const uint64_t& KernelCodeHandle() { return kernelCodeHandle_; }

  const uint32_t WorkgroupGroupSegmentByteSize() const { return workgroupGroupSegmentByteSize_; }

  const uint32_t workitemPrivateSegmentByteSize() const { return workitemPrivateSegmentByteSize_; }

  const uint64_t KernargSegmentByteSize() const { return kernargSegmentByteSize_; }

  const uint8_t KernargSegmentAlignment() const { return kernargSegmentAlignment_; }

  ~Kernel();

  //! Initializes the metadata required for this kernel
  virtual bool init() = 0;

  const Program* program() const { return static_cast<const Program*>(program_); }

  //! Returns the kernel argument list
  const std::vector<Argument*>& hsailArgs() const { return hsailArgList_; }

  //! Returns a pointer to the hsail argument at the specified index
  Argument* hsailArgAt(size_t index) const {
    for (auto arg : hsailArgList_)
      if (arg->index_ == index) return arg;
    assert(!"Should not reach here");
    return nullptr;
  }

  //! Return printf info array
  const std::vector<PrintfInfo>& printfInfo() const { return printf_; }

  //! Return TRUE if kernel is internal blit kernel
  bool isInternalKernel() const { return (flags_.internalKernel_) ? true : false; }

  //! set internal kernel flag
  void setInternalKernelFlag(bool flag) { flags_.internalKernel_ = flag; }

  //! Return TRUE if kernel uses images
  bool imageEnable() const { return (flags_.imageEnable_) ? true : false; }

  //! Return TRUE if kernel wirtes images
  bool imageWrite() const { return (flags_.imageWrite_) ? true : false; }

 protected:
  union Flags {
    struct {
      uint internalKernel_ : 1;  //!< Is a blit kernel?
      uint imageEnable_    : 1;  //!< Kernel uses images
      uint imageWrite_     : 1;  //!< Kernel writes images
    };
    uint value_;
    Flags() : value_(0) {}
  } flags_;

  Program* program_;                //!< The roc::Program context
  std::vector<Argument*> hsailArgList_;  //!< Vector list of HSAIL Arguments
  uint64_t kernelCodeHandle_;            //!< Kernel code handle (aka amd_kernel_code_t)
  const uint32_t workgroupGroupSegmentByteSize_;
  const uint32_t workitemPrivateSegmentByteSize_;
  const uint32_t kernargSegmentByteSize_;
  const uint32_t kernargSegmentAlignment_;
  size_t kernelDirectiveOffset_;
  std::vector<PrintfInfo> printf_;
};

#if defined(WITH_COMPILER_LIB)
class HSAILKernel : public roc::Kernel {
 public:
  HSAILKernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle,
              const uint32_t workgroupGroupSegmentByteSize,
              const uint32_t workitemPrivateSegmentByteSize,
              const uint32_t kernargSegmentByteSize,
              const uint32_t kernargSegmentAlignment)
   : roc::Kernel(name, prog, kernelCodeHandle, workgroupGroupSegmentByteSize,
                 workitemPrivateSegmentByteSize, kernargSegmentByteSize, kernargSegmentAlignment) {
  }

  //! Initializes the metadata required for this kernel
  virtual bool init() final;

 private:
  //! Populates hsailArgList_
  void initArguments(const aclArgData* aclArg);

  //! Initializes HSAIL Printf metadata and info
  void initPrintf(const aclPrintfFmt* aclPrintf);
};
#endif // defined(WITH_COMPILER_LIB)

#if defined(WITH_LIGHTNING_COMPILER)
class LightningKernel : public roc::Kernel {
 public:
  LightningKernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle,
                  const uint32_t workgroupGroupSegmentByteSize,
                  const uint32_t workitemPrivateSegmentByteSize,
                  const uint32_t kernargSegmentByteSize,
                  const uint32_t kernargSegmentAlignment)
   : roc::Kernel(name, prog, kernelCodeHandle, workgroupGroupSegmentByteSize,
                 workitemPrivateSegmentByteSize, kernargSegmentByteSize, kernargSegmentAlignment) {
  }
  //! Initializes the metadata required for this kernel
  virtual bool init() final;

private:
  //! Initializes Hsail Argument metadata and info for LC
  void initArguments(const KernelMD& kernelMD);

  //! Initializes HSAIL Printf metadata and info for LC
  void initPrintf(const std::vector<std::string>& printfInfoStrings);
};
#endif // defined(WITH_LIGHTNING_COMPILER)

}  // namespace roc

#endif  // WITHOUT_HSA_BACKEND
<commit_msg>P4 to Git Change 1549969 by skudchad@skudchad_rocm on 2018/05/03 18:37:35<commit_after>//
// Copyright (c) 2009 Advanced Micro Devices, Inc. All rights reserved.
//
#pragma once

#include <memory>
#include "acl.h"
#include "rocprogram.hpp"
#include "top.hpp"
#include "rocprintf.hpp"

#ifndef WITHOUT_HSA_BACKEND

namespace roc {

#define MAX_INFO_STRING_LEN 0x40

enum ROC_ARG_TYPE {
  ROC_ARGTYPE_ERROR = 0,
  ROC_ARGTYPE_POINTER,
  ROC_ARGTYPE_VALUE,
  ROC_ARGTYPE_REFERENCE,
  ROC_ARGTYPE_IMAGE,
  ROC_ARGTYPE_SAMPLER,
  ROC_ARGTYPE_HIDDEN_GLOBAL_OFFSET_X,
  ROC_ARGTYPE_HIDDEN_GLOBAL_OFFSET_Y,
  ROC_ARGTYPE_HIDDEN_GLOBAL_OFFSET_Z,
  ROC_ARGTYPE_HIDDEN_PRINTF_BUFFER,
  ROC_ARGTYPE_HIDDEN_DEFAULT_QUEUE,
  ROC_ARGTYPE_HIDDEN_COMPLETION_ACTION,
  ROC_ARGTYPE_HIDDEN_NONE,
  ROC_ARGMAX_ARG_TYPES
};

enum ROC_ADDRESS_QUALIFIER {
  ROC_ADDRESS_ERROR = 0,
  ROC_ADDRESS_GLOBAL,
  ROC_ADDRESS_CONSTANT,
  ROC_ADDRESS_LOCAL,
  ROC_MAX_ADDRESS_QUALIFIERS
};

enum ROC_DATA_TYPE {
  ROC_DATATYPE_ERROR = 0,
  ROC_DATATYPE_B1,
  ROC_DATATYPE_B8,
  ROC_DATATYPE_B16,
  ROC_DATATYPE_B32,
  ROC_DATATYPE_B64,
  ROC_DATATYPE_S8,
  ROC_DATATYPE_S16,
  ROC_DATATYPE_S32,
  ROC_DATATYPE_S64,
  ROC_DATATYPE_U8,
  ROC_DATATYPE_U16,
  ROC_DATATYPE_U32,
  ROC_DATATYPE_U64,
  ROC_DATATYPE_F16,
  ROC_DATATYPE_F32,
  ROC_DATATYPE_F64,
  ROC_DATATYPE_STRUCT,
  ROC_DATATYPE_OPAQUE,
  ROC_DATATYPE_MAX_TYPES
};

enum ROC_ACCESS_TYPE {
  ROC_ACCESS_TYPE_NONE = 0,
  ROC_ACCESS_TYPE_RO,
  ROC_ACCESS_TYPE_WO,
  ROC_ACCESS_TYPE_RW
};

class Kernel : public device::Kernel {
 public:
  struct Argument {
    uint index_;                      //!< Argument's index in the OCL signature
    std::string name_;                //!< Argument's name
    std::string typeName_;            //!< Argument's type name
    uint size_;                       //!< Size in bytes
    uint alignment_;                  //!< Argument's alignment
    uint pointeeAlignment_;           //!< Alignment of the data pointed to
    ROC_ARG_TYPE type_;               //!< Type of the argument
    ROC_ADDRESS_QUALIFIER addrQual_;  //!< Address qualifier of the argument
    ROC_DATA_TYPE dataType_;          //!< The type of data
    ROC_ACCESS_TYPE access_;          //!< Access type for the argument
  };

  Kernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle,
         const uint32_t workgroupGroupSegmentByteSize,
         const uint32_t workitemPrivateSegmentByteSize, const uint32_t kernargSegmentByteSize,
         const uint32_t kernargSegmentAlignment);

  const uint64_t& KernelCodeHandle() { return kernelCodeHandle_; }

  const uint32_t WorkgroupGroupSegmentByteSize() const { return workgroupGroupSegmentByteSize_; }

  const uint32_t workitemPrivateSegmentByteSize() const { return workitemPrivateSegmentByteSize_; }

  const uint64_t KernargSegmentByteSize() const { return kernargSegmentByteSize_ + 48; }

  const uint8_t KernargSegmentAlignment() const { return kernargSegmentAlignment_; }

  ~Kernel();

  //! Initializes the metadata required for this kernel
  virtual bool init() = 0;

  const Program* program() const { return static_cast<const Program*>(program_); }

  //! Returns the kernel argument list
  const std::vector<Argument*>& hsailArgs() const { return hsailArgList_; }

  //! Returns a pointer to the hsail argument at the specified index
  Argument* hsailArgAt(size_t index) const {
    for (auto arg : hsailArgList_)
      if (arg->index_ == index) return arg;
    assert(!"Should not reach here");
    return nullptr;
  }

  //! Return printf info array
  const std::vector<PrintfInfo>& printfInfo() const { return printf_; }

  //! Return TRUE if kernel is internal blit kernel
  bool isInternalKernel() const { return (flags_.internalKernel_) ? true : false; }

  //! set internal kernel flag
  void setInternalKernelFlag(bool flag) { flags_.internalKernel_ = flag; }

  //! Return TRUE if kernel uses images
  bool imageEnable() const { return (flags_.imageEnable_) ? true : false; }

  //! Return TRUE if kernel wirtes images
  bool imageWrite() const { return (flags_.imageWrite_) ? true : false; }

 protected:
  union Flags {
    struct {
      uint internalKernel_ : 1;  //!< Is a blit kernel?
      uint imageEnable_    : 1;  //!< Kernel uses images
      uint imageWrite_     : 1;  //!< Kernel writes images
    };
    uint value_;
    Flags() : value_(0) {}
  } flags_;

  Program* program_;                //!< The roc::Program context
  std::vector<Argument*> hsailArgList_;  //!< Vector list of HSAIL Arguments
  uint64_t kernelCodeHandle_;            //!< Kernel code handle (aka amd_kernel_code_t)
  const uint32_t workgroupGroupSegmentByteSize_;
  const uint32_t workitemPrivateSegmentByteSize_;
  const uint32_t kernargSegmentByteSize_;
  const uint32_t kernargSegmentAlignment_;
  size_t kernelDirectiveOffset_;
  std::vector<PrintfInfo> printf_;
};

#if defined(WITH_COMPILER_LIB)
class HSAILKernel : public roc::Kernel {
 public:
  HSAILKernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle,
              const uint32_t workgroupGroupSegmentByteSize,
              const uint32_t workitemPrivateSegmentByteSize,
              const uint32_t kernargSegmentByteSize,
              const uint32_t kernargSegmentAlignment)
   : roc::Kernel(name, prog, kernelCodeHandle, workgroupGroupSegmentByteSize,
                 workitemPrivateSegmentByteSize, kernargSegmentByteSize, kernargSegmentAlignment) {
  }

  //! Initializes the metadata required for this kernel
  virtual bool init() final;

 private:
  //! Populates hsailArgList_
  void initArguments(const aclArgData* aclArg);

  //! Initializes HSAIL Printf metadata and info
  void initPrintf(const aclPrintfFmt* aclPrintf);
};
#endif // defined(WITH_COMPILER_LIB)

#if defined(WITH_LIGHTNING_COMPILER)
class LightningKernel : public roc::Kernel {
 public:
  LightningKernel(std::string name, Program* prog, const uint64_t& kernelCodeHandle,
                  const uint32_t workgroupGroupSegmentByteSize,
                  const uint32_t workitemPrivateSegmentByteSize,
                  const uint32_t kernargSegmentByteSize,
                  const uint32_t kernargSegmentAlignment)
   : roc::Kernel(name, prog, kernelCodeHandle, workgroupGroupSegmentByteSize,
                 workitemPrivateSegmentByteSize, kernargSegmentByteSize, kernargSegmentAlignment) {
  }
  //! Initializes the metadata required for this kernel
  virtual bool init() final;

private:
  //! Initializes Hsail Argument metadata and info for LC
  void initArguments(const KernelMD& kernelMD);

  //! Initializes HSAIL Printf metadata and info for LC
  void initPrintf(const std::vector<std::string>& printfInfoStrings);
};
#endif // defined(WITH_LIGHTNING_COMPILER)

}  // namespace roc

#endif  // WITHOUT_HSA_BACKEND
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "reference_processor.h"

#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
#include "reflection.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change.h"
#include "well_known_classes.h"

namespace art {
namespace gc {

ReferenceProcessor::ReferenceProcessor()
    : process_references_args_(nullptr, nullptr, nullptr), slow_path_enabled_(false),
      preserving_references_(false), lock_("reference processor lock", kReferenceProcessorLock),
      condition_("reference processor condition", lock_) {
}

void ReferenceProcessor::EnableSlowPath() {
  Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
  slow_path_enabled_ = true;
}

void ReferenceProcessor::DisableSlowPath(Thread* self) {
  slow_path_enabled_ = false;
  // Set to null so that GetReferent knows to not attempt to use the callback for seeing if
  // referents are marked.
  process_references_args_.is_marked_callback_ = nullptr;
  condition_.Broadcast(self);
}

mirror::Object* ReferenceProcessor::GetReferent(Thread* self, mirror::Reference* reference) {
  mirror::Object* const referent = reference->GetReferent();
  if (LIKELY(!slow_path_enabled_)) {
    return referent;
  }
  // Another fast path, the referent is cleared, we can just return null since there is no scenario
  // where it becomes non-null.
  if (referent == nullptr) {
    return nullptr;
  }
  MutexLock mu(self, lock_);
  while (slow_path_enabled_) {
    // Try to see if the referent is already marked by using the is_marked_callback. We can return
    // it to the mutator as long as the GC is not preserving references. If the GC is
    // preserving references, the mutator could take a white field and move it somewhere else
    // in the heap causing corruption since this field would get swept.
    IsMarkedCallback* const is_marked_callback = process_references_args_.is_marked_callback_;
    if (!preserving_references_ && is_marked_callback != nullptr) {
      mirror::Object* const referent = reference->GetReferent();
      mirror::Object* const obj = is_marked_callback(referent, process_references_args_.arg_);
      // If it's null it means not marked, but it could become marked if the referent is reachable
      // by finalizer referents. So we can not return in this case and must block.
      if (obj != nullptr) {
        return obj;
      }
    }
    condition_.WaitHoldingLocks(self);
  }
  return reference->GetReferent();
}

mirror::Object* ReferenceProcessor::PreserveSoftReferenceCallback(mirror::Object* obj, void* arg) {
  auto* const args = reinterpret_cast<ProcessReferencesArgs*>(arg);
  // TODO: Not preserve all soft references.
  return args->mark_callback_(obj, args->arg_);
}

void ReferenceProcessor::StartPreservingReferences(Thread* self) {
  MutexLock mu(self, lock_);
  preserving_references_ = true;
}

void ReferenceProcessor::StopPreservingReferences(Thread* self) {
  MutexLock mu(self, lock_);
  preserving_references_ = false;
  // We are done preserving references, some people who are blocked may see a marked referent.
  condition_.Broadcast(self);
}

// Process reference class instances and schedule finalizations.
void ReferenceProcessor::ProcessReferences(bool concurrent, TimingLogger* timings,
                                           bool clear_soft_references,
                                           IsMarkedCallback* is_marked_callback,
                                           MarkObjectCallback* mark_object_callback,
                                           ProcessMarkStackCallback* process_mark_stack_callback,
                                           void* arg) {
  Thread* self = Thread::Current();
  {
    MutexLock mu(self, lock_);
    process_references_args_.is_marked_callback_ = is_marked_callback;
    process_references_args_.mark_callback_ = mark_object_callback;
    process_references_args_.arg_ = arg;
  }
  if (concurrent) {
    MutexLock mu(self, lock_);
    CHECK(slow_path_enabled_) << "Slow path must be enabled for concurrent reference processing";
    timings->StartSplit("ProcessReferences");
  } else {
    timings->StartSplit("(Paused)ProcessReferences");
  }
  // Unless required to clear soft references with white references, preserve some white referents.
  if (!clear_soft_references) {
    TimingLogger::ScopedSplit split(concurrent ? "PreserveSomeSoftReferences" :
        "(Paused)PreserveSomeSoftReferences", timings);
    if (concurrent) {
      StartPreservingReferences(self);
    }
    // References with a marked referent are removed from the list.
    soft_reference_queue_.PreserveSomeSoftReferences(&PreserveSoftReferenceCallback,
                                                     &process_references_args_);

    process_mark_stack_callback(arg);
    if (concurrent) {
      StopPreservingReferences(self);
    }
  }
  // Clear all remaining soft and weak references with white referents.
  soft_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  weak_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  {
    TimingLogger::ScopedSplit split(concurrent ? "EnqueueFinalizerReferences" :
        "(Paused)EnqueueFinalizerReferences", timings);
    if (concurrent) {
      StartPreservingReferences(self);
    }
    // Preserve all white objects with finalize methods and schedule them for finalization.
    finalizer_reference_queue_.EnqueueFinalizerReferences(cleared_references_, is_marked_callback,
                                                          mark_object_callback, arg);
    process_mark_stack_callback(arg);
    if (concurrent) {
      StopPreservingReferences(self);
    }
  }
  // Clear all finalizer referent reachable soft and weak references with white referents.
  soft_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  weak_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  // Clear all phantom references with white referents.
  phantom_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  // At this point all reference queues other than the cleared references should be empty.
  DCHECK(soft_reference_queue_.IsEmpty());
  DCHECK(weak_reference_queue_.IsEmpty());
  DCHECK(finalizer_reference_queue_.IsEmpty());
  DCHECK(phantom_reference_queue_.IsEmpty());
  if (concurrent) {
    MutexLock mu(self, lock_);
    // Done processing, disable the slow path and broadcast to the waiters.
    DisableSlowPath(self);
  }
  timings->EndSplit();
}

// Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
// marked, put it on the appropriate list in the heap for later processing.
void ReferenceProcessor::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref,
                                                IsMarkedCallback is_marked_callback, void* arg) {
  // klass can be the class of the old object if the visitor already updated the class of ref.
  DCHECK(klass->IsReferenceClass());
  mirror::Object* referent = ref->GetReferent();
  if (referent != nullptr) {
    mirror::Object* forward_address = is_marked_callback(referent, arg);
    // Null means that the object is not currently marked.
    if (forward_address == nullptr) {
      Thread* self = Thread::Current();
      // TODO: Remove these locks, and use atomic stacks for storing references?
      // We need to check that the references haven't already been enqueued since we can end up
      // scanning the same reference multiple times due to dirty cards.
      if (klass->IsSoftReferenceClass()) {
        soft_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
      } else if (klass->IsWeakReferenceClass()) {
        weak_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
      } else if (klass->IsFinalizerReferenceClass()) {
        finalizer_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
      } else if (klass->IsPhantomReferenceClass()) {
        phantom_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
      } else {
        LOG(FATAL) << "Invalid reference type " << PrettyClass(klass) << " " << std::hex
                   << klass->GetAccessFlags();
      }
    } else if (referent != forward_address) {
      // Referent is already marked and we need to update it.
      ref->SetReferent<false>(forward_address);
    }
  }
}

void ReferenceProcessor::EnqueueClearedReferences() {
  Thread* self = Thread::Current();
  Locks::mutator_lock_->AssertNotHeld(self);
  if (!cleared_references_.IsEmpty()) {
    // When a runtime isn't started there are no reference queues to care about so ignore.
    if (LIKELY(Runtime::Current()->IsStarted())) {
      ScopedObjectAccess soa(self);
      ScopedLocalRef<jobject> arg(self->GetJniEnv(),
                                  soa.AddLocalReference<jobject>(cleared_references_.GetList()));
      jvalue args[1];
      args[0].l = arg.get();
      InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_ReferenceQueue_add, args);
    }
    cleared_references_.Clear();
  }
}

}  // namespace gc
}  // namespace art

<commit_msg>am b6050839: Merge "Fix race condition in ProcessReferences."<commit_after>/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "reference_processor.h"

#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
#include "reflection.h"
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change.h"
#include "well_known_classes.h"

namespace art {
namespace gc {

ReferenceProcessor::ReferenceProcessor()
    : process_references_args_(nullptr, nullptr, nullptr), slow_path_enabled_(false),
      preserving_references_(false), lock_("reference processor lock", kReferenceProcessorLock),
      condition_("reference processor condition", lock_) {
}

void ReferenceProcessor::EnableSlowPath() {
  Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
  slow_path_enabled_ = true;
}

void ReferenceProcessor::DisableSlowPath(Thread* self) {
  slow_path_enabled_ = false;
  condition_.Broadcast(self);
}

mirror::Object* ReferenceProcessor::GetReferent(Thread* self, mirror::Reference* reference) {
  mirror::Object* const referent = reference->GetReferent();
  if (LIKELY(!slow_path_enabled_)) {
    return referent;
  }
  // Another fast path, the referent is cleared, we can just return null since there is no scenario
  // where it becomes non-null.
  if (referent == nullptr) {
    return nullptr;
  }
  MutexLock mu(self, lock_);
  while (slow_path_enabled_) {
    mirror::Object* const referent = reference->GetReferent();
    // If the referent became cleared, return it.
    if (referent == nullptr) {
      return nullptr;
    }
    // Try to see if the referent is already marked by using the is_marked_callback. We can return
    // it to the mutator as long as the GC is not preserving references. If the GC is
    // preserving references, the mutator could take a white field and move it somewhere else
    // in the heap causing corruption since this field would get swept.
    IsMarkedCallback* const is_marked_callback = process_references_args_.is_marked_callback_;
    if (!preserving_references_ && is_marked_callback != nullptr) {
      mirror::Object* const obj = is_marked_callback(referent, process_references_args_.arg_);
      // If it's null it means not marked, but it could become marked if the referent is reachable
      // by finalizer referents. So we can not return in this case and must block.
      if (obj != nullptr) {
        return obj;
      }
    }
    condition_.WaitHoldingLocks(self);
  }
  return reference->GetReferent();
}

mirror::Object* ReferenceProcessor::PreserveSoftReferenceCallback(mirror::Object* obj, void* arg) {
  auto* const args = reinterpret_cast<ProcessReferencesArgs*>(arg);
  // TODO: Not preserve all soft references.
  return args->mark_callback_(obj, args->arg_);
}

void ReferenceProcessor::StartPreservingReferences(Thread* self) {
  MutexLock mu(self, lock_);
  preserving_references_ = true;
}

void ReferenceProcessor::StopPreservingReferences(Thread* self) {
  MutexLock mu(self, lock_);
  preserving_references_ = false;
  // We are done preserving references, some people who are blocked may see a marked referent.
  condition_.Broadcast(self);
}

// Process reference class instances and schedule finalizations.
void ReferenceProcessor::ProcessReferences(bool concurrent, TimingLogger* timings,
                                           bool clear_soft_references,
                                           IsMarkedCallback* is_marked_callback,
                                           MarkObjectCallback* mark_object_callback,
                                           ProcessMarkStackCallback* process_mark_stack_callback,
                                           void* arg) {
  Thread* self = Thread::Current();
  {
    MutexLock mu(self, lock_);
    process_references_args_.is_marked_callback_ = is_marked_callback;
    process_references_args_.mark_callback_ = mark_object_callback;
    process_references_args_.arg_ = arg;
    CHECK_EQ(slow_path_enabled_, concurrent) << "Slow path must be enabled iff concurrent";
  }
  timings->StartSplit(concurrent ? "ProcessReferences" : "(Paused)ProcessReferences");
  // Unless required to clear soft references with white references, preserve some white referents.
  if (!clear_soft_references) {
    TimingLogger::ScopedSplit split(concurrent ? "PreserveSomeSoftReferences" :
        "(Paused)PreserveSomeSoftReferences", timings);
    if (concurrent) {
      StartPreservingReferences(self);
    }
    // References with a marked referent are removed from the list.
    soft_reference_queue_.PreserveSomeSoftReferences(&PreserveSoftReferenceCallback,
                                                     &process_references_args_);
    process_mark_stack_callback(arg);
    if (concurrent) {
      StopPreservingReferences(self);
    }
  }
  // Clear all remaining soft and weak references with white referents.
  soft_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  weak_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  {
    TimingLogger::ScopedSplit split(concurrent ? "EnqueueFinalizerReferences" :
        "(Paused)EnqueueFinalizerReferences", timings);
    if (concurrent) {
      StartPreservingReferences(self);
    }
    // Preserve all white objects with finalize methods and schedule them for finalization.
    finalizer_reference_queue_.EnqueueFinalizerReferences(cleared_references_, is_marked_callback,
                                                          mark_object_callback, arg);
    process_mark_stack_callback(arg);
    if (concurrent) {
      StopPreservingReferences(self);
    }
  }
  // Clear all finalizer referent reachable soft and weak references with white referents.
  soft_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  weak_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  // Clear all phantom references with white referents.
  phantom_reference_queue_.ClearWhiteReferences(cleared_references_, is_marked_callback, arg);
  // At this point all reference queues other than the cleared references should be empty.
  DCHECK(soft_reference_queue_.IsEmpty());
  DCHECK(weak_reference_queue_.IsEmpty());
  DCHECK(finalizer_reference_queue_.IsEmpty());
  DCHECK(phantom_reference_queue_.IsEmpty());
  {
    MutexLock mu(self, lock_);
    // Need to always do this since the next GC may be concurrent. Doing this for only concurrent
    // could result in a stale is_marked_callback_ being called before the reference processing
    // starts since there is a small window of time where slow_path_enabled_ is enabled but the
    // callback isn't yet set.
    process_references_args_.is_marked_callback_ = nullptr;
    if (concurrent) {
      // Done processing, disable the slow path and broadcast to the waiters.
      DisableSlowPath(self);
    }
  }
  timings->EndSplit();
}

// Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
// marked, put it on the appropriate list in the heap for later processing.
void ReferenceProcessor::DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref,
                                                IsMarkedCallback is_marked_callback, void* arg) {
  // klass can be the class of the old object if the visitor already updated the class of ref.
  DCHECK(klass->IsReferenceClass());
  mirror::Object* referent = ref->GetReferent();
  if (referent != nullptr) {
    mirror::Object* forward_address = is_marked_callback(referent, arg);
    // Null means that the object is not currently marked.
    if (forward_address == nullptr) {
      Thread* self = Thread::Current();
      // TODO: Remove these locks, and use atomic stacks for storing references?
      // We need to check that the references haven't already been enqueued since we can end up
      // scanning the same reference multiple times due to dirty cards.
      if (klass->IsSoftReferenceClass()) {
        soft_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
      } else if (klass->IsWeakReferenceClass()) {
        weak_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
      } else if (klass->IsFinalizerReferenceClass()) {
        finalizer_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
      } else if (klass->IsPhantomReferenceClass()) {
        phantom_reference_queue_.AtomicEnqueueIfNotEnqueued(self, ref);
      } else {
        LOG(FATAL) << "Invalid reference type " << PrettyClass(klass) << " " << std::hex
                   << klass->GetAccessFlags();
      }
    } else if (referent != forward_address) {
      // Referent is already marked and we need to update it.
      ref->SetReferent<false>(forward_address);
    }
  }
}

void ReferenceProcessor::EnqueueClearedReferences() {
  Thread* self = Thread::Current();
  Locks::mutator_lock_->AssertNotHeld(self);
  if (!cleared_references_.IsEmpty()) {
    // When a runtime isn't started there are no reference queues to care about so ignore.
    if (LIKELY(Runtime::Current()->IsStarted())) {
      ScopedObjectAccess soa(self);
      ScopedLocalRef<jobject> arg(self->GetJniEnv(),
                                  soa.AddLocalReference<jobject>(cleared_references_.GetList()));
      jvalue args[1];
      args[0].l = arg.get();
      InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_ReferenceQueue_add, args);
    }
    cleared_references_.Clear();
  }
}

}  // namespace gc
}  // namespace art

<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <unistd.h>
#include <napi.h>

#define PSZ(s) (s).c_str()

using namespace std;

const int nFiles = 10;
const int nEntry = 2;
const int nData = 2;
int array_dims[2] = {512, 512};
const char szFile[] = "leak_test.nxs";
const int iBinarySize = 512*512;
int aiBinaryData[iBinarySize];

int main ()
{
  int i, iFile, iEntry, iData, iNXdata;

  for(i=0; i < iBinarySize; i++)
  {
	aiBinaryData[i] = rand();
  }
  for( iFile = 0; iFile < nFiles; iFile++ )
  {
    printf("file %d\n", iFile);

    NXhandle fileid;
    NXlink aLink;
    if( NXopen(szFile, NXACC_CREATE5, &fileid ) != NX_OK) return 1;
    for( iEntry = 0; iEntry < nEntry; iEntry++ )
    {
      ostringstream oss;
      oss << "entry_" << iEntry;
      if (NXmakegroup (fileid, PSZ(oss.str()), "NXentry") != NX_OK) return 1;
      if (NXopengroup (fileid, PSZ(oss.str()), "NXentry") != NX_OK) return 1;
      for( iNXdata = 0; iNXdata < nData; iNXdata++ )
      {
        ostringstream oss;
        oss << "data_" << iNXdata;
        if (NXmakegroup (fileid, PSZ(oss.str()), "NXdata") != NX_OK) return 1;
        if (NXopengroup (fileid, PSZ(oss.str()), "NXdata") != NX_OK) return 1;
        NXgetgroupID(fileid, &aLink);
        for( iData = 0; iData < nData; iData++ )
        {
          ostringstream oss;
          oss << "i2_data_" << iData;
          if (NXcompmakedata (fileid, PSZ(oss.str()), NX_INT16, 2, array_dims, NX_COMP_LZW, array_dims) != NX_OK)
//          if (NXmakedata (fileid, PSZ(oss.str()), NX_INT16, 2, array_dims) != NX_OK)
	  	return 1;
          if (NXopendata (fileid, PSZ(oss.str())) != NX_OK) return 1;
            if (NXputdata (fileid, aiBinaryData) != NX_OK) return 1;
          if (NXclosedata (fileid) != NX_OK) return 1;
        }
        if (NXclosegroup (fileid) != NX_OK) return 1;
      }
      if (NXclosegroup (fileid) != NX_OK) return 1;
    }
    if (NXclose (&fileid) != NX_OK) return 1;

    // Delete file
    remove(szFile);
  }

  printf("done...\n");
  _exit(EXIT_FAILURE);
}

<commit_msg>Added leak_test3.cxx<commit_after>#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <sstream>
#include <unistd.h>
#include <napi.h>

#define PSZ(s) (s).c_str()

using namespace std;

const int nFiles = 10;
const int nEntry = 2;
const int nData = 2;
int array_dims[2] = {512, 512};
const char szFile[] = "leak_test.nxs";
const int iBinarySize = 512*512;
int aiBinaryData[iBinarySize];

#define ON_ERROR(msgstr)\
{\
    std::cerr<<msgstr<<std::endl; \
    return 1; \
}

int main ()
{
    int i, iFile, iEntry, iData, iNXdata;

    for(i=0; i < iBinarySize; i++)
    {
        aiBinaryData[i] = rand();
    }

    for( iFile = 0; iFile < nFiles; iFile++ )
    {
        printf("file %d\n", iFile);

        NXhandle fileid;
        NXlink aLink;
        if( NXopen(szFile, NXACC_CREATE5, &fileid ) != NX_OK)
            ON_ERROR("NXopen_failed")

        for( iEntry = 0; iEntry < nEntry; iEntry++ )
        {
            ostringstream oss;
            oss << "entry_" << iEntry;

            if (NXmakegroup (fileid, PSZ(oss.str()), "NXentry") != NX_OK)
                ON_ERROR("NXmakegroup failed!")

            if (NXopengroup (fileid, PSZ(oss.str()), "NXentry") != NX_OK)
                ON_ERROR("NXopengroup failed!")

            for( iNXdata = 0; iNXdata < nData; iNXdata++ )
            {
                ostringstream oss;
                oss << "data_" << iNXdata;

                if (NXmakegroup (fileid, PSZ(oss.str()), "NXdata") != NX_OK)
                    ON_ERROR("NXmakegroup failed!")

                if (NXopengroup (fileid, PSZ(oss.str()), "NXdata") != NX_OK)
                    ON_ERROR("NXopengroup failed!")

                NXgetgroupID(fileid, &aLink);
                for( iData = 0; iData < nData; iData++ )
                {
                    ostringstream oss;
                    oss << "i2_data_" << iData;

                    if (NXcompmakedata (fileid, PSZ(oss.str()),
                                        NX_INT16, 2, array_dims, NX_COMP_LZW,
                                        array_dims) != NX_OK)
                        ON_ERROR("NXcompmakedata failed!")

                    if (NXopendata (fileid, PSZ(oss.str())) != NX_OK)
                        ON_ERROR("NXopendata failed!")

                    if (NXputdata (fileid, aiBinaryData) != NX_OK)
                        ON_ERROR("NXputdata failed!")

                    if (NXclosedata (fileid) != NX_OK)
                        ON_ERROR("NXclosedata failed!")
                }

                if (NXclosegroup (fileid) != NX_OK)
                    ON_ERROR("NXclosegroup failed!")
            }

            if (NXclosegroup (fileid) != NX_OK)
                ON_ERROR("NXclosegroup failed!")
        }

        if (NXclose (&fileid) != NX_OK)
            ON_ERROR("NXclose failed!")

        // Delete file
        remove(szFile);
    }

    return 0;
}

<|endoftext|>


<commit_before><commit_msg>修改测试代码<commit_after><|endoftext|>