<commit_before>//===-- XBeeSyncServer.cpp - XBee Syncing for GameModel ------------ c++ --===//
//
//                               UWH Timer
//
//           This file is distributed under the BSD 3-Clause License.
//                      See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "uwhd/sync/ModelSync.h"

#include "uwhd/model/GameModel.h"

#include <cassert>
#include <cstdint>
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <iomanip>
#include <iostream>
#include <memory>
#include <queue>
#include <semaphore.h>
#include <sstream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <termios.h>
#include <thread>
#include <time.h>
#include <unistd.h>

// Serial comm stuff copied from: http://stackoverflow.com/a/6947758
int set_interface_attribs(int fd, int speed, int parity) {
  struct termios tty;
  memset (&tty, 0, sizeof tty);
  if (tcgetattr (fd, &tty) != 0)
  {
    printf("error %d from tcgetattr", errno);
    return -1;
  }

  cfsetospeed (&tty, speed);
  cfsetispeed (&tty, speed);

  tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
  // disable IGNBRK for mismatched speed tests; otherwise receive break
  // as \000 chars
  tty.c_iflag &= ~IGNBRK;         // disable break processing
  tty.c_lflag = 0;                // no signaling chars, no echo,
  // no canonical processing
  tty.c_oflag = 0;                // no remapping, no delays
  tty.c_cc[VMIN]  = 0;            // read doesn't block
  tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

  tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

  tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
  // enable reading
  tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
  tty.c_cflag |= parity;
  tty.c_cflag &= ~CSTOPB;
  tty.c_cflag &= ~CRTSCTS;

  if (tcsetattr (fd, TCSANOW, &tty) != 0)
  {
    printf("error %d from tcsetattr", errno);
    return -1;
  }
  return 0;
}

void set_blocking(int fd, int should_block) {
  struct termios tty;
  memset(&tty, 0, sizeof tty);
  if (tcgetattr(fd, &tty) != 0)
  {
    printf("error %d from tggetattr", errno);
    return;
  }

  tty.c_cc[VMIN]  = should_block ? 1 : 0;
  tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

  if (tcsetattr(fd, TCSANOW, &tty) != 0)
    printf("error %d setting term attributes", errno);
}

namespace {

class XBeeSyncServer : public ModelSyncServer, GameModelManager {
public:
  XBeeSyncServer();
  ~XBeeSyncServer();

  virtual void Init() override;

  virtual void setMgr(GameModelManager *NewM) {
    assert(!M);
    M = NewM;
    M->registerListener(this);
  }

  virtual GameModelManager &getMgr() override { return *M; }

  virtual void modelChanged(GameModel Model) override;
private:
  int fd;
  GameModelManager *M;

  static const char *XBeeSerialConsole;
  static const int XBeeBaudRate;
};

class XBeeSyncClient : public ModelSync {
public:
  XBeeSyncClient();
  ~XBeeSyncClient();

  virtual void Init() override;

  virtual void setMgr(GameModelManager *NewM) {
    assert(!M);
    M = NewM;
    //M->registerListener(this);
  }

  virtual GameModelManager &getMgr() override { return *M; }

  void receivedModel(GameModel Model);

protected:

private:
  int fd;
  GameModelManager *M;

  static const char *XBeeSerialConsole;
  static const int   XBeeBaudRate;
};

} // anonymous namespace

const char *XBeeSyncServer::XBeeSerialConsole = "/dev/ttyAMA0";
const int   XBeeSyncServer::XBeeBaudRate      = 9600;
const char *XBeeSyncClient::XBeeSerialConsole = "/dev/ttyAMA0";
const int   XBeeSyncClient::XBeeBaudRate      = 9600;

XBeeSyncServer::XBeeSyncServer()
  : fd(0), M(nullptr) {
  printf("server ctor\n");
}

XBeeSyncServer::~XBeeSyncServer() {
  printf("server dtor\n");
}

void XBeeSyncServer::Init() {
  printf("server init\n");
  char *portname = "/dev/ttyAMA0";
  fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
  if (fd < 0) {
    printf("error %d opening %s: %s", errno, portname, strerror (errno));
    return;
  }
  set_interface_attribs(fd, B9600, 0);  // set speed to 9600 bps, 8n1 (no parity)
  set_blocking(fd, 0);                  // set no blocking
}

void XBeeSyncServer::modelChanged(GameModel Model) {
  std::string Message = Model.serialize();
  printf("server model changed: [%s]\n", Message.c_str());
  write(fd, Message.c_str(), Message.size());
}

XBeeSyncClient::XBeeSyncClient()
  : fd(0), M(nullptr) {
    printf("client ctor\n");
}

XBeeSyncClient::~XBeeSyncClient() {
  printf("client dtor\n");
}

void XBeeSyncClient::Init() {
  printf("client init\n");
  char *portname = "/dev/ttyAMA0";
  fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
  if (fd < 0) {
    printf("error %d opening %s: %s", errno, portname, strerror (errno));
    return;
  }
  set_interface_attribs(fd, B9600, 0);  // set speed to 9600 bps, 8n1 (no parity)
  set_blocking(fd, 1);                  // set no blocking

  std::thread([this]() {
    std::queue<char> Queue;
    std::stringstream Msg;
    do {
      char buf[128];
      memset(buf, 0, sizeof(buf));
      int n = read(fd, buf, sizeof(buf));

      //printf("read: [%s]\n", buf);

      for (int i = 0; i < n; ++i)
        Queue.push(buf[i]);

      while (!Queue.empty()) {
        char C = Queue.front();
        Msg << C;
        Queue.pop();

        if (C == 'E') {
          GameModel Model;
          if (GameModel::deSerialize(Msg.str(), Model)) {
            printf("failed to deserialize [%s]\n", Msg.str().c_str());
          } else {
            //printf("updating model:\n");
            receivedModel(Model);
          }

          Msg.str("");
          Msg.clear();
        }
      }

      usleep(100);
    } while (true);
  }).detach();
}

void XBeeSyncClient::receivedModel(GameModel Model) {
  M->setModel(Model);
}

ModelSyncServer *CreateXBeeSyncServer() {
  return new XBeeSyncServer();
}

ModelSync *CreateXBeeSyncClient() {
  return new XBeeSyncClient();
}

<commit_msg>[sync] Delete some debug printfs<commit_after>//===-- XBeeSyncServer.cpp - XBee Syncing for GameModel ------------ c++ --===//
//
//                               UWH Timer
//
//           This file is distributed under the BSD 3-Clause License.
//                      See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "uwhd/sync/ModelSync.h"

#include "uwhd/model/GameModel.h"

#include <cassert>
#include <cstdint>
#include <cstring>
#include <errno.h>
#include <fcntl.h>
#include <iomanip>
#include <iostream>
#include <memory>
#include <queue>
#include <semaphore.h>
#include <sstream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <termios.h>
#include <thread>
#include <time.h>
#include <unistd.h>

// Serial comm stuff copied from: http://stackoverflow.com/a/6947758
int set_interface_attribs(int fd, int speed, int parity) {
  struct termios tty;
  memset (&tty, 0, sizeof tty);
  if (tcgetattr (fd, &tty) != 0)
  {
    printf("error %d from tcgetattr", errno);
    return -1;
  }

  cfsetospeed (&tty, speed);
  cfsetispeed (&tty, speed);

  tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;     // 8-bit chars
  // disable IGNBRK for mismatched speed tests; otherwise receive break
  // as \000 chars
  tty.c_iflag &= ~IGNBRK;         // disable break processing
  tty.c_lflag = 0;                // no signaling chars, no echo,
  // no canonical processing
  tty.c_oflag = 0;                // no remapping, no delays
  tty.c_cc[VMIN]  = 0;            // read doesn't block
  tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

  tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl

  tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
  // enable reading
  tty.c_cflag &= ~(PARENB | PARODD);      // shut off parity
  tty.c_cflag |= parity;
  tty.c_cflag &= ~CSTOPB;
  tty.c_cflag &= ~CRTSCTS;

  if (tcsetattr (fd, TCSANOW, &tty) != 0)
  {
    printf("error %d from tcsetattr", errno);
    return -1;
  }
  return 0;
}

void set_blocking(int fd, int should_block) {
  struct termios tty;
  memset(&tty, 0, sizeof tty);
  if (tcgetattr(fd, &tty) != 0)
  {
    printf("error %d from tggetattr", errno);
    return;
  }

  tty.c_cc[VMIN]  = should_block ? 1 : 0;
  tty.c_cc[VTIME] = 5;            // 0.5 seconds read timeout

  if (tcsetattr(fd, TCSANOW, &tty) != 0)
    printf("error %d setting term attributes", errno);
}

namespace {

class XBeeSyncServer : public ModelSyncServer, GameModelManager {
public:
  XBeeSyncServer();
  ~XBeeSyncServer();

  virtual void Init() override;

  virtual void setMgr(GameModelManager *NewM) {
    assert(!M);
    M = NewM;
    M->registerListener(this);
  }

  virtual GameModelManager &getMgr() override { return *M; }

  virtual void modelChanged(GameModel Model) override;
private:
  int fd;
  GameModelManager *M;

  static const char *XBeeSerialConsole;
  static const int XBeeBaudRate;
};

class XBeeSyncClient : public ModelSync {
public:
  XBeeSyncClient();
  ~XBeeSyncClient();

  virtual void Init() override;

  virtual void setMgr(GameModelManager *NewM) {
    assert(!M);
    M = NewM;
    //M->registerListener(this);
  }

  virtual GameModelManager &getMgr() override { return *M; }

  void receivedModel(GameModel Model);

protected:

private:
  int fd;
  GameModelManager *M;

  static const char *XBeeSerialConsole;
  static const int   XBeeBaudRate;
};

} // anonymous namespace

const char *XBeeSyncServer::XBeeSerialConsole = "/dev/ttyAMA0";
const int   XBeeSyncServer::XBeeBaudRate      = 9600;
const char *XBeeSyncClient::XBeeSerialConsole = "/dev/ttyAMA0";
const int   XBeeSyncClient::XBeeBaudRate      = 9600;

XBeeSyncServer::XBeeSyncServer()
  : fd(0), M(nullptr) {
}

XBeeSyncServer::~XBeeSyncServer() {
}

void XBeeSyncServer::Init() {
  char *portname = "/dev/ttyAMA0";
  fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
  if (fd < 0) {
    printf("error %d opening %s: %s", errno, portname, strerror (errno));
    return;
  }
  set_interface_attribs(fd, B9600, 0);  // set speed to 9600 bps, 8n1 (no parity)
  set_blocking(fd, 0);                  // set no blocking
}

void XBeeSyncServer::modelChanged(GameModel Model) {
  std::string Message = Model.serialize();
  write(fd, Message.c_str(), Message.size());
}

XBeeSyncClient::XBeeSyncClient()
  : fd(0), M(nullptr) {
}

XBeeSyncClient::~XBeeSyncClient() {
}

void XBeeSyncClient::Init() {
  char *portname = "/dev/ttyAMA0";
  fd = open (portname, O_RDWR | O_NOCTTY | O_SYNC);
  if (fd < 0) {
    printf("error %d opening %s: %s", errno, portname, strerror (errno));
    return;
  }
  set_interface_attribs(fd, B9600, 0);  // set speed to 9600 bps, 8n1 (no parity)
  set_blocking(fd, 1);                  // set no blocking

  std::thread([this]() {
    std::queue<char> Queue;
    std::stringstream Msg;
    do {
      char buf[128];
      memset(buf, 0, sizeof(buf));
      int n = read(fd, buf, sizeof(buf));

      //printf("read: [%s]\n", buf);

      for (int i = 0; i < n; ++i)
        Queue.push(buf[i]);

      while (!Queue.empty()) {
        char C = Queue.front();
        Msg << C;
        Queue.pop();

        if (C == 'E') {
          GameModel Model;
          if (GameModel::deSerialize(Msg.str(), Model)) {
            printf("failed to deserialize [%s]\n", Msg.str().c_str());
          } else {
            //printf("updating model:\n");
            receivedModel(Model);
          }

          Msg.str("");
          Msg.clear();
        }
      }

      usleep(100);
    } while (true);
  }).detach();
}

void XBeeSyncClient::receivedModel(GameModel Model) {
  M->setModel(Model);
}

ModelSyncServer *CreateXBeeSyncServer() {
  return new XBeeSyncServer();
}

ModelSync *CreateXBeeSyncClient() {
  return new XBeeSyncClient();
}

<|endoftext|>


<commit_before>#include <b1/rodeos/rodeos.hpp>

#include <b1/rodeos/callbacks/kv.hpp>
#include <b1/rodeos/rodeos_tables.hpp>

namespace b1::rodeos {

namespace ship_protocol = eosio::ship_protocol;

using ship_protocol::get_blocks_result_v0;
using ship_protocol::signed_block;

rodeos_db_snapshot::rodeos_db_snapshot(std::shared_ptr<rodeos_db_partition> partition, bool persistent)
    : partition{ std::move(partition) }, db{ this->partition->db } {
   if (persistent) {
      undo_stack.emplace(*db, this->partition->undo_prefix);
      write_session.emplace(*db);
   } else {
      snap.emplace(db->rdb.get());
      write_session.emplace(*db, snap->snapshot());
   }

   db_view_state    view_state{ state_account, *db, *write_session, this->partition->contract_kv_prefix };
   fill_status_sing sing{ state_account, view_state, false };
   if (sing.exists()) {
      auto status     = std::get<0>(sing.get());
      chain_id        = status.chain_id;
      head            = status.head;
      head_id         = status.head_id;
      irreversible    = status.irreversible;
      irreversible_id = status.irreversible_id;
      first           = status.first;
   }
}

void rodeos_db_snapshot::refresh() {
   if (undo_stack)
      throw std::runtime_error("can not refresh a persistent snapshot");
   snap.emplace(db->rdb.get());
   write_session->snapshot = snap->snapshot();
   write_session->wipe_cache();
}

void rodeos_db_snapshot::write_fill_status() {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   fill_status status;
   if (irreversible < head)
      status = fill_status_v0{ .chain_id        = chain_id,
                               .head            = head,
                               .head_id         = head_id,
                               .irreversible    = irreversible,
                               .irreversible_id = irreversible_id,
                               .first           = first };
   else
      status = fill_status_v0{ .chain_id        = chain_id,
                               .head            = head,
                               .head_id         = head_id,
                               .irreversible    = head,
                               .irreversible_id = head_id,
                               .first           = first };

   db_view_state view_state{ state_account, *db, *write_session, partition->contract_kv_prefix };
   view_state.kv_state.enable_write = true;
   fill_status_sing sing{ state_account, view_state, false };
   sing.set(status);
   sing.store();
}

void rodeos_db_snapshot::end_write(bool write_fill) {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   if (write_fill)
      write_fill_status();
   write_session->write_changes(*undo_stack);
}

void rodeos_db_snapshot::start_block(const get_blocks_result_v0& result) {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   if (!result.this_block)
      throw std::runtime_error("get_blocks_result this_block is empty");

   if (result.this_block->block_num <= head) {
      ilog("switch forks at block ${b}; database contains revisions ${f} - ${h}",
           ("b", result.this_block->block_num)("f", undo_stack->first_revision())("h", undo_stack->revision()));
      if (undo_stack->first_revision() >= result.this_block->block_num)
         throw std::runtime_error("can't switch forks since database doesn't contain revision " +
                                  std::to_string(result.this_block->block_num - 1));
      write_session->wipe_cache();
      while (undo_stack->revision() >= result.this_block->block_num) //
         undo_stack->undo(true);
   }

   if (head_id != eosio::checksum256{} && (!result.prev_block || result.prev_block->block_id != head_id))
      throw std::runtime_error("prev_block does not match");

   if (result.this_block->block_num <= result.last_irreversible.block_num) {
      undo_stack->commit(std::min(result.last_irreversible.block_num, head));
      undo_stack->set_revision(result.this_block->block_num, false);
   } else {
      end_write(false);
      undo_stack->commit(std::min(result.last_irreversible.block_num, head));
      undo_stack->push(false);
   }
   writing_block = result.this_block->block_num;
}

void rodeos_db_snapshot::end_block(const get_blocks_result_v0& result, bool force_write) {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   if (!result.this_block)
      throw std::runtime_error("get_blocks_result this_block is empty");
   if (!writing_block || result.this_block->block_num != *writing_block)
      throw std::runtime_error("call start_block first");

   bool near       = result.this_block->block_num + 4 >= result.last_irreversible.block_num;
   bool write_now  = !(result.this_block->block_num % 200) || near || force_write;
   head            = result.this_block->block_num;
   head_id         = result.this_block->block_id;
   irreversible    = result.last_irreversible.block_num;
   irreversible_id = result.last_irreversible.block_id;
   if (!first || head < first)
      first = head;
   if (write_now)
      end_write(write_now);
   if (near)
      db->flush(false, false);
}

void rodeos_db_snapshot::check_write(const ship_protocol::get_blocks_result_v0& result) {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   if (!result.this_block)
      throw std::runtime_error("get_blocks_result this_block is empty");
   if (!writing_block || result.this_block->block_num != *writing_block)
      throw std::runtime_error("call start_block first");
}

void rodeos_db_snapshot::write_block_info(const ship_protocol::get_blocks_result_v0& result) {
   check_write(result);
   if (!result.block)
      return;

   uint32_t            block_num = result.this_block->block_num;
   eosio::input_stream bin       = *result.block;
   signed_block        block;
   from_bin(block, bin);

   db_view_state view_state{ state_account, *db, *write_session, partition->contract_kv_prefix };
   view_state.kv_state.enable_write = true;

   block_info_v0 info;
   info.num                = block_num;
   info.id                 = result.this_block->block_id;
   info.timestamp          = block.timestamp;
   info.producer           = block.producer;
   info.confirmed          = block.confirmed;
   info.previous           = block.previous;
   info.transaction_mroot  = block.transaction_mroot;
   info.action_mroot       = block.action_mroot;
   info.schedule_version   = block.schedule_version;
   info.new_producers      = block.new_producers;
   info.producer_signature = block.producer_signature;

   block_info_kv table{ kv_environment{ view_state } };
   table.put(info);
}

void rodeos_db_snapshot::write_deltas(const ship_protocol::get_blocks_result_v0& result,
                                      std::function<bool()>                      shutdown) {
   check_write(result);
   if (!result.deltas)
      return;

   uint32_t            block_num = result.this_block->block_num;
   eosio::input_stream bin       = *result.deltas;

   db_view_state view_state{ state_account, *db, *write_session, partition->contract_kv_prefix };
   view_state.kv_ram.enable_write           = true;
   view_state.kv_ram.bypass_receiver_check  = true;
   view_state.kv_disk.enable_write          = true;
   view_state.kv_disk.bypass_receiver_check = true;
   view_state.kv_state.enable_write         = true;
   uint32_t num;
   eosio::varuint32_from_bin(num, bin);
   for (uint32_t i = 0; i < num; ++i) {
      ship_protocol::table_delta delta;
      from_bin(delta, bin);
      auto&  delta_v0      = std::get<0>(delta);
      size_t num_processed = 0;
      store_delta({ view_state }, delta_v0, head == 0, [&]() {
         if (delta_v0.rows.size() > 10000 && !(num_processed % 10000)) {
            if (shutdown())
               throw std::runtime_error("shutting down");
            ilog("block ${b} ${t} ${n} of ${r}",
                 ("b", block_num)("t", delta_v0.name)("n", num_processed)("r", delta_v0.rows.size()));
            if (head == 0) {
               end_write(false);
               view_state.reset();
            }
         }
         ++num_processed;
      });
   }
}

std::once_flag registered_filter_callbacks;

rodeos_filter::rodeos_filter(eosio::name name, const std::string& wasm_filename) : name{ name } {
   std::call_once(registered_filter_callbacks, filter::register_callbacks);

   std::ifstream wasm_file(wasm_filename, std::ios::binary);
   if (!wasm_file.is_open())
      throw std::runtime_error("can not open " + wasm_filename);
   ilog("compiling ${f}", ("f", wasm_filename));
   wasm_file.seekg(0, std::ios::end);
   int len = wasm_file.tellg();
   if (len < 0)
      throw std::runtime_error("wasm file length is -1");
   std::vector<uint8_t> code(len);
   wasm_file.seekg(0, std::ios::beg);
   wasm_file.read((char*)code.data(), code.size());
   wasm_file.close();
   backend      = std::make_unique<filter::backend_t>(code, nullptr);
   filter_state = std::make_unique<filter::filter_state>();
   filter::rhf_t::resolve(backend->get_module());
}

void rodeos_filter::process(rodeos_db_snapshot& snapshot, const ship_protocol::get_blocks_result_v0& result,
                            eosio::input_stream                                         bin,
                            const std::function<void(const char* data, uint64_t size)>& push_data) {
   // todo: timeout
   snapshot.check_write(result);
   chaindb_state chaindb_state;
   db_view_state view_state{ name, *snapshot.db, *snapshot.write_session, snapshot.partition->contract_kv_prefix };
   view_state.kv_disk.enable_write = true;
   view_state.kv_ram.enable_write  = true;
   filter::callbacks cb{ *filter_state, chaindb_state, view_state };
   filter_state->max_console_size = 10000;
   filter_state->console.clear();
   filter_state->input_data = bin;
   filter_state->push_data  = push_data;
   backend->set_wasm_allocator(&filter_state->wa);
   backend->initialize(&cb);
   try {
      (*backend)(cb, "env", "apply", uint64_t(0), uint64_t(0), uint64_t(0));
   } catch (...) {
      if (!filter_state->console.empty())
         ilog("filter ${n} console output before exception: <<<\n${c}>>>",
              ("n", name.to_string())("c", filter_state->console));
      throw;
   }
   if (!filter_state->console.empty())
      ilog("filter ${n} console output: <<<\n${c}>>>", ("n", name.to_string())("c", filter_state->console));
}

rodeos_query_handler::rodeos_query_handler(std::shared_ptr<rodeos_db_partition>         partition,
                                           std::shared_ptr<const wasm_ql::shared_state> shared_state)
    : partition{ partition }, shared_state{ std::move(shared_state) }, state_cache{ this->shared_state } {}

} // namespace b1::rodeos
<commit_msg>Report wasm filter exceptions<commit_after>#include <b1/rodeos/rodeos.hpp>

#include <b1/rodeos/callbacks/kv.hpp>
#include <b1/rodeos/rodeos_tables.hpp>

namespace b1::rodeos {

namespace ship_protocol = eosio::ship_protocol;

using ship_protocol::get_blocks_result_v0;
using ship_protocol::signed_block;

rodeos_db_snapshot::rodeos_db_snapshot(std::shared_ptr<rodeos_db_partition> partition, bool persistent)
    : partition{ std::move(partition) }, db{ this->partition->db } {
   if (persistent) {
      undo_stack.emplace(*db, this->partition->undo_prefix);
      write_session.emplace(*db);
   } else {
      snap.emplace(db->rdb.get());
      write_session.emplace(*db, snap->snapshot());
   }

   db_view_state    view_state{ state_account, *db, *write_session, this->partition->contract_kv_prefix };
   fill_status_sing sing{ state_account, view_state, false };
   if (sing.exists()) {
      auto status     = std::get<0>(sing.get());
      chain_id        = status.chain_id;
      head            = status.head;
      head_id         = status.head_id;
      irreversible    = status.irreversible;
      irreversible_id = status.irreversible_id;
      first           = status.first;
   }
}

void rodeos_db_snapshot::refresh() {
   if (undo_stack)
      throw std::runtime_error("can not refresh a persistent snapshot");
   snap.emplace(db->rdb.get());
   write_session->snapshot = snap->snapshot();
   write_session->wipe_cache();
}

void rodeos_db_snapshot::write_fill_status() {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   fill_status status;
   if (irreversible < head)
      status = fill_status_v0{ .chain_id        = chain_id,
                               .head            = head,
                               .head_id         = head_id,
                               .irreversible    = irreversible,
                               .irreversible_id = irreversible_id,
                               .first           = first };
   else
      status = fill_status_v0{ .chain_id        = chain_id,
                               .head            = head,
                               .head_id         = head_id,
                               .irreversible    = head,
                               .irreversible_id = head_id,
                               .first           = first };

   db_view_state view_state{ state_account, *db, *write_session, partition->contract_kv_prefix };
   view_state.kv_state.enable_write = true;
   fill_status_sing sing{ state_account, view_state, false };
   sing.set(status);
   sing.store();
}

void rodeos_db_snapshot::end_write(bool write_fill) {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   if (write_fill)
      write_fill_status();
   write_session->write_changes(*undo_stack);
}

void rodeos_db_snapshot::start_block(const get_blocks_result_v0& result) {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   if (!result.this_block)
      throw std::runtime_error("get_blocks_result this_block is empty");

   if (result.this_block->block_num <= head) {
      ilog("switch forks at block ${b}; database contains revisions ${f} - ${h}",
           ("b", result.this_block->block_num)("f", undo_stack->first_revision())("h", undo_stack->revision()));
      if (undo_stack->first_revision() >= result.this_block->block_num)
         throw std::runtime_error("can't switch forks since database doesn't contain revision " +
                                  std::to_string(result.this_block->block_num - 1));
      write_session->wipe_cache();
      while (undo_stack->revision() >= result.this_block->block_num) //
         undo_stack->undo(true);
   }

   if (head_id != eosio::checksum256{} && (!result.prev_block || result.prev_block->block_id != head_id))
      throw std::runtime_error("prev_block does not match");

   if (result.this_block->block_num <= result.last_irreversible.block_num) {
      undo_stack->commit(std::min(result.last_irreversible.block_num, head));
      undo_stack->set_revision(result.this_block->block_num, false);
   } else {
      end_write(false);
      undo_stack->commit(std::min(result.last_irreversible.block_num, head));
      undo_stack->push(false);
   }
   writing_block = result.this_block->block_num;
}

void rodeos_db_snapshot::end_block(const get_blocks_result_v0& result, bool force_write) {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   if (!result.this_block)
      throw std::runtime_error("get_blocks_result this_block is empty");
   if (!writing_block || result.this_block->block_num != *writing_block)
      throw std::runtime_error("call start_block first");

   bool near       = result.this_block->block_num + 4 >= result.last_irreversible.block_num;
   bool write_now  = !(result.this_block->block_num % 200) || near || force_write;
   head            = result.this_block->block_num;
   head_id         = result.this_block->block_id;
   irreversible    = result.last_irreversible.block_num;
   irreversible_id = result.last_irreversible.block_id;
   if (!first || head < first)
      first = head;
   if (write_now)
      end_write(write_now);
   if (near)
      db->flush(false, false);
}

void rodeos_db_snapshot::check_write(const ship_protocol::get_blocks_result_v0& result) {
   if (!undo_stack)
      throw std::runtime_error("Can only write to persistent snapshots");
   if (!result.this_block)
      throw std::runtime_error("get_blocks_result this_block is empty");
   if (!writing_block || result.this_block->block_num != *writing_block)
      throw std::runtime_error("call start_block first");
}

void rodeos_db_snapshot::write_block_info(const ship_protocol::get_blocks_result_v0& result) {
   check_write(result);
   if (!result.block)
      return;

   uint32_t            block_num = result.this_block->block_num;
   eosio::input_stream bin       = *result.block;
   signed_block        block;
   from_bin(block, bin);

   db_view_state view_state{ state_account, *db, *write_session, partition->contract_kv_prefix };
   view_state.kv_state.enable_write = true;

   block_info_v0 info;
   info.num                = block_num;
   info.id                 = result.this_block->block_id;
   info.timestamp          = block.timestamp;
   info.producer           = block.producer;
   info.confirmed          = block.confirmed;
   info.previous           = block.previous;
   info.transaction_mroot  = block.transaction_mroot;
   info.action_mroot       = block.action_mroot;
   info.schedule_version   = block.schedule_version;
   info.new_producers      = block.new_producers;
   info.producer_signature = block.producer_signature;

   block_info_kv table{ kv_environment{ view_state } };
   table.put(info);
}

void rodeos_db_snapshot::write_deltas(const ship_protocol::get_blocks_result_v0& result,
                                      std::function<bool()>                      shutdown) {
   check_write(result);
   if (!result.deltas)
      return;

   uint32_t            block_num = result.this_block->block_num;
   eosio::input_stream bin       = *result.deltas;

   db_view_state view_state{ state_account, *db, *write_session, partition->contract_kv_prefix };
   view_state.kv_ram.enable_write           = true;
   view_state.kv_ram.bypass_receiver_check  = true;
   view_state.kv_disk.enable_write          = true;
   view_state.kv_disk.bypass_receiver_check = true;
   view_state.kv_state.enable_write         = true;
   uint32_t num;
   eosio::varuint32_from_bin(num, bin);
   for (uint32_t i = 0; i < num; ++i) {
      ship_protocol::table_delta delta;
      from_bin(delta, bin);
      auto&  delta_v0      = std::get<0>(delta);
      size_t num_processed = 0;
      store_delta({ view_state }, delta_v0, head == 0, [&]() {
         if (delta_v0.rows.size() > 10000 && !(num_processed % 10000)) {
            if (shutdown())
               throw std::runtime_error("shutting down");
            ilog("block ${b} ${t} ${n} of ${r}",
                 ("b", block_num)("t", delta_v0.name)("n", num_processed)("r", delta_v0.rows.size()));
            if (head == 0) {
               end_write(false);
               view_state.reset();
            }
         }
         ++num_processed;
      });
   }
}

std::once_flag registered_filter_callbacks;

rodeos_filter::rodeos_filter(eosio::name name, const std::string& wasm_filename) : name{ name } {
   std::call_once(registered_filter_callbacks, filter::register_callbacks);

   std::ifstream wasm_file(wasm_filename, std::ios::binary);
   if (!wasm_file.is_open())
      throw std::runtime_error("can not open " + wasm_filename);
   ilog("compiling ${f}", ("f", wasm_filename));
   wasm_file.seekg(0, std::ios::end);
   int len = wasm_file.tellg();
   if (len < 0)
      throw std::runtime_error("wasm file length is -1");
   std::vector<uint8_t> code(len);
   wasm_file.seekg(0, std::ios::beg);
   wasm_file.read((char*)code.data(), code.size());
   wasm_file.close();
   backend      = std::make_unique<filter::backend_t>(code, nullptr);
   filter_state = std::make_unique<filter::filter_state>();
   filter::rhf_t::resolve(backend->get_module());
}

void rodeos_filter::process(rodeos_db_snapshot& snapshot, const ship_protocol::get_blocks_result_v0& result,
                            eosio::input_stream                                         bin,
                            const std::function<void(const char* data, uint64_t size)>& push_data) {
   // todo: timeout
   snapshot.check_write(result);
   chaindb_state chaindb_state;
   db_view_state view_state{ name, *snapshot.db, *snapshot.write_session, snapshot.partition->contract_kv_prefix };
   view_state.kv_disk.enable_write = true;
   view_state.kv_ram.enable_write  = true;
   filter::callbacks cb{ *filter_state, chaindb_state, view_state };
   filter_state->max_console_size = 10000;
   filter_state->console.clear();
   filter_state->input_data = bin;
   filter_state->push_data  = push_data;
   backend->set_wasm_allocator(&filter_state->wa);
   backend->initialize(&cb);
   try {
      (*backend)(cb, "env", "apply", uint64_t(0), uint64_t(0), uint64_t(0));

      if (!filter_state->console.empty())
         ilog("filter ${n} console output: <<<\n${c}>>>", ("n", name.to_string())("c", filter_state->console));
   } catch (...) {
      try {
         throw;
      } catch( const std::exception& e ) {
         elog( "std::exception processing filter wasm: ${e}", ("e", e.what()) );
      } catch( const fc::exception& e ) {
         elog( "fc::exception processing filter wasm: ${e}", ("e", e.to_detail_string()) );
      } catch( ... ) {
         elog( "unknown exception processing filter wasm" );
      }
      if (!filter_state->console.empty())
         ilog("filter ${n} console output before exception: <<<\n${c}>>>",
              ("n", name.to_string())("c", filter_state->console));
      throw;
   }
}

rodeos_query_handler::rodeos_query_handler(std::shared_ptr<rodeos_db_partition>         partition,
                                           std::shared_ptr<const wasm_ql::shared_state> shared_state)
    : partition{ partition }, shared_state{ std::move(shared_state) }, state_cache{ this->shared_state } {}

} // namespace b1::rodeos
<|endoftext|>


<commit_before>#include "common.h"

#include <iolib/file_stream.h>
#include <iolib/stream.h>
#include <windows_error.h>

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

using namespace std;
using namespace iolib;
using namespace windows;

struct section_header_t
{
	char name[8];
	uint32_t virtual_size;
	uint32_t virtual_address;
	uint32_t raw_data_size;
	uint32_t raw_data_offset;
	uint32_t relocations_offset;
	uint32_t line_numbers_offset;
	uint16_t relocation_count;
	uint16_t line_number_count;
	uint32_t characteristics;
};

struct import_entry_t
{
	uint32_t lookup_virtual_address;
	uint32_t timestamp;
	uint32_t forwarder_chain;
	uint32_t dllname_virtual_address;
	uint32_t import_table_virtual_address;
};

static const import_entry_t import_entry_null = { };

static const char PESignature[] = { 'P', 'E', '\0', '\0' };
static const uint16_t OptionalHeader_PE32Signature = 0x10B;
static const uint16_t OptionalHeader_PE32PlusSignature = 0x20B;

int wmain(int argc, wchar_t* argv[])
{
#if _DEBUG
	at_scope_exit([&]{ system("pause"); });
#endif

	if (argc != 3)
	{
		wcout << L"Usage:\n\t" << argv[0] << L" <input_path> <output_path>" << endl;
		return EXIT_FAILURE;
	}

	try
	{
		// Read the input file into an in-memory buffer.
		vector<uint8_t> file_buffer;
		{
			file input_file(argv[1], file::mode::open | file::mode::read);
			input_file.seek(0, file::seek_from::end);
			size_t size = size_t(input_file.position());
			file_buffer.resize(size);
			input_file.seek(0, file::seek_from::beginning);
			input_file.read(file_buffer.data(), file_buffer.size());
		}

		// iolib streams are very good for reading heterogeneous data.
		memory_stream file_data(file_buffer.data(), file_buffer.size());

		// Read offset of PE header
		file_data.seek(0x3C);
		uint32_t offset;
		file_data.read(offset);

		// Read PE signature
		file_data.seek(offset, stream::seek_from::beginning);
		char signature[4];
		file_data.read(signature, sizeof(signature));
		if (!equal(begin(signature), end(signature), begin(PESignature)))
		{
			wcerr << L"Error: Input file is not a valid executable." << endl;
			return EXIT_FAILURE;
		}

		// Read number of sections
		file_data.seek(2);
		uint16_t section_count;
		file_data.read(section_count);

		// Skip to optional header
		file_data.seek(12);
		uint16_t header_size;
		file_data.read(header_size);

		file_data.seek(2);
		uint16_t pe_type_signature;
		file_data.read(pe_type_signature);
		if (pe_type_signature != OptionalHeader_PE32Signature && pe_type_signature != OptionalHeader_PE32PlusSignature)
		{
			wcerr << L"Error: Input file is not a valid executable." << endl;
			return EXIT_FAILURE;
		}

		// Skip to the section tables.
		file_data.seek(header_size - 2);

		for (unsigned section_header_index = 0; section_header_index < section_count; ++section_header_index)
		{
			section_header_t section_header;
			file_data.read(section_header);
			if (strcmp(section_header.name, ".idata") != 0)
				continue;

			// Save current position.
			auto position = file_data.position();

			// Skip to the import tables.
			file_data.seek(section_header.raw_data_offset, file::seek_from::beginning);

			// The import tables specify RVAs for import entries, so we'll need the base
			// address of the section in order to locate the imports in the input file.
			uint32_t idata_base_rva = section_header.virtual_address;

			// Skip past the directory tables.
			while (true)
			{
				import_entry_t import_entry;
				file_data.read(import_entry);
				if (memcmp(&import_entry, &import_entry_null, sizeof(import_entry_t)) == 0)
					break;

				auto import_entry_position = file_data.position();
				file_data.seek(section_header.raw_data_offset + import_entry.dllname_virtual_address - idata_base_rva, file::seek_from::beginning);
				string dll_name;
				char ch;
				while ((file_data.read(ch), ch) != '\0')
					dll_name += ch;
				if (_stricmp(dll_name.c_str(), "ddraw.dll") == 0)
				{
					file_data.seek(section_header.raw_data_offset + import_entry.lookup_virtual_address - idata_base_rva, file::seek_from::beginning);
					if (pe_type_signature == OptionalHeader_PE32Signature)
					{
						uint32_t lookup;
						while ((file_data.read(lookup), lookup) != 0)
						{
							if ((lookup & 0x80000000) == 0)
							{
								file_data.seek(section_header.raw_data_offset + lookup - idata_base_rva + 2, file::seek_from::beginning);
								string name;
								while ((file_data.read(ch), ch) != '\0')
									name += ch;
							}
						}
					}
					else
					{
						uint64_t lookup;
						while ((file_data.read(lookup), lookup) != 0)
						{
							if ((lookup & 0x8000000000000000) == 0)
							{
								file_data.seek(section_header.raw_data_offset + uint32_t(lookup) - idata_base_rva + 2, file::seek_from::beginning);
								string name;
								while ((file_data.read(ch), ch) != '\0')
									name += ch;
							}
						}
					}
				}

				file_data.set_position(import_entry_position);
			}
		}

		return EXIT_SUCCESS;
	}
	catch (...)
	{
	}

	return EXIT_FAILURE;
}
<commit_msg>Patcher replaces ddraw import information with wcdx.<commit_after>#include "common.h"

#include <iolib/file_stream.h>
#include <iolib/stream.h>
#include <windows_error.h>

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

using namespace std;
using namespace iolib;
using namespace windows;

struct section_header_t
{
	char name[8];
	uint32_t virtual_size;
	uint32_t virtual_address;
	uint32_t raw_data_size;
	uint32_t raw_data_offset;
	uint32_t relocations_offset;
	uint32_t line_numbers_offset;
	uint16_t relocation_count;
	uint16_t line_number_count;
	uint32_t characteristics;
};

struct import_entry_t
{
	uint32_t lookup_virtual_address;
	uint32_t timestamp;
	uint32_t forwarder_chain;
	uint32_t dllname_virtual_address;
	uint32_t import_table_virtual_address;
};

static const import_entry_t import_entry_null = { };

static const char PESignature[] = { 'P', 'E', '\0', '\0' };
static const uint16_t OptionalHeader_PE32Signature = 0x10B;
static const uint16_t OptionalHeader_PE32PlusSignature = 0x20B;

int wmain(int argc, wchar_t* argv[])
{
#if _DEBUG
	at_scope_exit([&]{ system("pause"); });
#endif

	if (argc != 3)
	{
		wcout << L"Usage:\n\t" << argv[0] << L" <input_path> <output_path>" << endl;
		return EXIT_FAILURE;
	}

	try
	{
		// Read the input file into an in-memory buffer.
		vector<uint8_t> file_buffer;
		{
			file input_file(argv[1], file::mode::open | file::mode::read);
			input_file.seek(0, file::seek_from::end);
			size_t size = size_t(input_file.position());
			file_buffer.resize(size);
			input_file.seek(0, file::seek_from::beginning);
			input_file.read(file_buffer.data(), file_buffer.size());
		}

		// iolib streams are very good for reading heterogeneous data.
		memory_stream file_data(file_buffer.data(), file_buffer.size());

		// Read offset of PE header
		file_data.seek(0x3C);
		uint32_t offset;
		file_data.read(offset);

		// Read PE signature
		file_data.seek(offset, stream::seek_from::beginning);
		char signature[4];
		file_data.read(signature, sizeof(signature));
		if (!equal(begin(signature), end(signature), begin(PESignature)))
		{
			wcerr << L"Error: Input file is not a valid executable." << endl;
			return EXIT_FAILURE;
		}

		// Read number of sections
		file_data.seek(2);
		uint16_t section_count;
		file_data.read(section_count);

		// Skip to optional header
		file_data.seek(12);
		uint16_t header_size;
		file_data.read(header_size);

		file_data.seek(2);
		uint16_t pe_type_signature;
		file_data.read(pe_type_signature);
		if (pe_type_signature != OptionalHeader_PE32Signature && pe_type_signature != OptionalHeader_PE32PlusSignature)
		{
			wcerr << L"Error: Input file is not a valid executable." << endl;
			return EXIT_FAILURE;
		}

		// Skip to the section tables.
		file_data.seek(header_size - 2);

		section_header_t section_header;
		for (unsigned section_header_index = 0; section_header_index < section_count; ++section_header_index)
		{
			file_data.read(section_header);
			if (strcmp(section_header.name, ".idata") == 0)
				break;
		}

		// Save current position.
		auto position = file_data.position();

		// Skip to the import tables.
		file_data.seek(section_header.raw_data_offset, file::seek_from::beginning);

		// The import tables specify RVAs for import entries, so we'll need the base
		// address of the section in order to locate the imports in the input file.
		uint32_t idata_base_rva = section_header.virtual_address;

		// Skip past the directory tables.
		import_entry_t import_entry;
		while (true)
		{
			file_data.read(import_entry);
			if (memcmp(&import_entry, &import_entry_null, sizeof(import_entry_t)) == 0)
				return EXIT_FAILURE;

			auto import_entry_position = file_data.position();
			file_data.seek(section_header.raw_data_offset + import_entry.dllname_virtual_address - idata_base_rva, file::seek_from::beginning);
			string dll_name;
			char ch;
			while ((file_data.read(ch), ch) != '\0')
				dll_name += ch;
			if (_stricmp(dll_name.c_str(), "ddraw.dll") == 0)
				break;

			file_data.set_position(import_entry_position);
		}

		file_data.seek(section_header.raw_data_offset + import_entry.lookup_virtual_address - idata_base_rva, file::seek_from::beginning);
		if (pe_type_signature != OptionalHeader_PE32Signature)
			return EXIT_FAILURE;

		uint32_t lookup;
		memory_stream::position_type lookup_position;
		while (true)
		{
			if (!file_data.read(lookup) || lookup == 0)
				return EXIT_FAILURE;

			if ((lookup & 0x80000000) == 0)
			{
				lookup_position = file_data.position();
				file_data.seek(section_header.raw_data_offset + lookup - idata_base_rva + 2, file::seek_from::beginning);
				auto name_position = file_data.position();

				string name;
				char ch;
				while ((file_data.read(ch), ch) != '\0')
					name += ch;
				if (name == "DirectDrawCreate")
				{
					file_data.set_position(name_position);
					break;
				}
				file_data.set_position(lookup_position);
			}
		}

		string_view function_name = "WcdxCreate";
		file_data.write(function_name.data(), function_name.length() * sizeof(char));
		file_data.write('\0');

		file_data.set_position(lookup_position);
		file_data.write(0);
		return EXIT_SUCCESS;
	}
	catch (...)
	{
	}

	return EXIT_FAILURE;
}
<|endoftext|>


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

#ifndef ROCRAND_RNG_SOBOL32_H_
#define ROCRAND_RNG_SOBOL32_H_

#include <algorithm>
#include <hip/hip_runtime.h>

#include <rocrand.h>
#include <rocrand_sobol_precomputed.h>

#include "generator_type.hpp"
#include "device_engines.hpp"
#include "distributions.hpp"

namespace rocrand_host {
namespace detail {

    typedef ::rocrand_device::sobol32_engine<true> sobol32_device_engine;

    template<class Type, class Distribution>
    __global__
    void generate_kernel(Type * data, const size_t n,
                         const unsigned int * direction_vectors,
                         const unsigned int offset,
                         Distribution distribution)
    {
        const unsigned int dimension = hipBlockIdx_y;
        const unsigned int engine_id = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
        const unsigned int stride = hipGridDim_x * hipBlockDim_x;

        // Each thread of the current block use the same direction vectors
        // (the dimension is determined by hipBlockIdx_y)
        __shared__ unsigned int vectors[32];
        if (hipThreadIdx_x < 32)
        {
            vectors[hipThreadIdx_x] = direction_vectors[dimension * 32 + hipThreadIdx_x];
        }
        __syncthreads();

        sobol32_device_engine engine(vectors, offset + engine_id);

        const unsigned int start = dimension * n;
        unsigned int index = engine_id;
        while(index < n)
        {
            data[start + index] = distribution(engine.current());
            engine.discard_stride(stride);
            index += stride;
        }
    }

} // end namespace detail
} // end namespace rocrand_host

class rocrand_sobol32 : public rocrand_generator_type<ROCRAND_RNG_QUASI_SOBOL32>
{
public:
    using base_type = rocrand_generator_type<ROCRAND_RNG_QUASI_SOBOL32>;
    using engine_type = ::rocrand_host::detail::sobol32_device_engine;

    rocrand_sobol32(unsigned long long offset = 0,
                    hipStream_t stream = 0)
        : base_type(0, offset, stream),
          m_initialized(false),
          m_dimensions(1)
    {
        // Allocate direction vectors
        hipError_t error;
        error = hipMalloc(&m_direction_vectors, sizeof(unsigned int) * SOBOL_N);
        if(error != hipSuccess)
        {
            throw ROCRAND_STATUS_ALLOCATION_FAILED;
        }
        error = hipMemcpy(m_direction_vectors, h_sobol32_direction_vectors, sizeof(unsigned int) * SOBOL_N, hipMemcpyHostToDevice);
        if(error != hipSuccess)
        {
            throw ROCRAND_STATUS_INTERNAL_ERROR;
        }
    }

    ~rocrand_sobol32()
    {
        hipFree(m_direction_vectors);
    }

    void reset()
    {
        m_initialized = false;
    }

    void set_offset(unsigned long long offset)
    {
        m_offset = offset;
        m_initialized = false;
    }

    void set_dimensions(unsigned int dimensions)
    {
        m_dimensions = dimensions;
        m_initialized = false;
    }

    rocrand_status init()
    {
        if (m_initialized)
            return ROCRAND_STATUS_SUCCESS;

        m_current_offset = static_cast<unsigned int>(m_offset);
        m_initialized = true;

        return ROCRAND_STATUS_SUCCESS;
    }

    template<class T, class Distribution = uniform_distribution<T> >
    rocrand_status generate(T * data, size_t data_size,
                            const Distribution& distribution = Distribution())
    {
        if (data_size % m_dimensions != 0)
            return ROCRAND_STATUS_LENGTH_NOT_MULTIPLE;

        rocrand_status status = init();
        if (status != ROCRAND_STATUS_SUCCESS)
            return status;

        #ifdef __HIP_PLATFORM_NVCC__
        const uint32_t threads = 64;
        const uint32_t max_blocks = 4096;
        #else
        const uint32_t threads = 256;
        const uint32_t max_blocks = 4096;
        #endif

        const size_t size = data_size / m_dimensions;
        const uint32_t blocks = std::min(max_blocks, static_cast<uint32_t>((size + threads - 1) / threads));

        // blocks_x must be power of 2 because strided discard (leap frog)
        // supports only power of 2 jumps
        const uint32_t blocks_x = next_power2((blocks + m_dimensions - 1) / m_dimensions);
        const uint32_t blocks_y = m_dimensions;
        hipLaunchKernelGGL(
            HIP_KERNEL_NAME(rocrand_host::detail::generate_kernel),
            dim3(blocks_x, blocks_y), dim3(threads), 0, m_stream,
            data, size,
            m_direction_vectors, m_current_offset,
            distribution
        );
        // Check kernel status
        if(hipPeekAtLastError() != hipSuccess)
            return ROCRAND_STATUS_LAUNCH_FAILURE;

        m_current_offset += size;

        return ROCRAND_STATUS_SUCCESS;
    }

    template<class T>
    rocrand_status generate_uniform(T * data, size_t data_size)
    {
        uniform_distribution<T> distribution;
        return generate(data, data_size, distribution);
    }

    template<class T>
    rocrand_status generate_normal(T * data, size_t data_size, T mean, T stddev)
    {
        normal_distribution<T> distribution(mean, stddev);
        return generate(data, data_size, distribution);
    }

    template<class T>
    rocrand_status generate_log_normal(T * data, size_t data_size, T mean, T stddev)
    {
        log_normal_distribution<T> distribution(mean, stddev);
        return generate(data, data_size, distribution);
    }

    rocrand_status generate_poisson(unsigned int * data, size_t data_size, double lambda)
    {
        try
        {
            m_poisson.set_lambda(lambda);
        }
        catch(rocrand_status status)
        {
            return status;
        }
        return generate(data, data_size, m_poisson.dis);
    }

private:
    bool m_initialized;
    unsigned int m_dimensions;
    unsigned int m_current_offset;
    unsigned int * m_direction_vectors;

    // For caching of Poisson for consecutive generations with the same lambda
    poisson_distribution_manager<ROCRAND_DISCRETE_METHOD_CDF> m_poisson;

    // m_offset from base_type

    size_t next_power2(size_t x)
    {
        size_t power = 1;
        while (power < x)
        {
            power *= 2;
        }
        return power;
    }
};

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

#ifndef ROCRAND_RNG_SOBOL32_H_
#define ROCRAND_RNG_SOBOL32_H_

#include <algorithm>
#include <hip/hip_runtime.h>

#include <rocrand.h>
#include <rocrand_sobol_precomputed.h>

#include "generator_type.hpp"
#include "device_engines.hpp"
#include "distributions.hpp"

namespace rocrand_host {
namespace detail {

    typedef ::rocrand_device::sobol32_engine<true> sobol32_device_engine;

    template<class Type, class Distribution>
    __global__
    void generate_kernel(Type * data, const size_t n,
                         const unsigned int * direction_vectors,
                         const unsigned int offset,
                         Distribution distribution)
    {
        const unsigned int dimension = hipBlockIdx_y;
        const unsigned int engine_id = hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x;
        const unsigned int stride = hipGridDim_x * hipBlockDim_x;

        // Each thread of the current block use the same direction vectors
        // (the dimension is determined by hipBlockIdx_y)
        __shared__ unsigned int vectors[32];
        if (hipThreadIdx_x < 32)
        {
            vectors[hipThreadIdx_x] = direction_vectors[dimension * 32 + hipThreadIdx_x];
        }
        __syncthreads();

        sobol32_device_engine engine(vectors, offset + engine_id);

        const unsigned int start = dimension * n;
        unsigned int index = engine_id;
        while(index < n)
        {
            data[start + index] = distribution(engine.current());
            engine.discard_stride(stride);
            index += stride;
        }
    }

} // end namespace detail
} // end namespace rocrand_host

class rocrand_sobol32 : public rocrand_generator_type<ROCRAND_RNG_QUASI_SOBOL32>
{
public:
    using base_type = rocrand_generator_type<ROCRAND_RNG_QUASI_SOBOL32>;
    using engine_type = ::rocrand_host::detail::sobol32_device_engine;

    rocrand_sobol32(unsigned long long offset = 0,
                    hipStream_t stream = 0)
        : base_type(0, offset, stream),
          m_initialized(false),
          m_dimensions(1)
    {
        // Allocate direction vectors
        hipError_t error;
        error = hipMalloc(&m_direction_vectors, sizeof(unsigned int) * SOBOL_N);
        if(error != hipSuccess)
        {
            throw ROCRAND_STATUS_ALLOCATION_FAILED;
        }
        error = hipMemcpy(m_direction_vectors, h_sobol32_direction_vectors, sizeof(unsigned int) * SOBOL_N, hipMemcpyHostToDevice);
        if(error != hipSuccess)
        {
            throw ROCRAND_STATUS_INTERNAL_ERROR;
        }
    }

    ~rocrand_sobol32()
    {
        hipFree(m_direction_vectors);
    }

    void reset()
    {
        m_initialized = false;
    }

    void set_offset(unsigned long long offset)
    {
        m_offset = offset;
        m_initialized = false;
    }

    void set_dimensions(unsigned int dimensions)
    {
        m_dimensions = dimensions;
        m_initialized = false;
    }

    rocrand_status init()
    {
        if (m_initialized)
            return ROCRAND_STATUS_SUCCESS;

        m_current_offset = static_cast<unsigned int>(m_offset);
        m_initialized = true;

        return ROCRAND_STATUS_SUCCESS;
    }

    template<class T, class Distribution = uniform_distribution<T> >
    rocrand_status generate(T * data, size_t data_size,
                            const Distribution& distribution = Distribution())
    {
        if (data_size % m_dimensions != 0)
            return ROCRAND_STATUS_LENGTH_NOT_MULTIPLE;

        rocrand_status status = init();
        if (status != ROCRAND_STATUS_SUCCESS)
            return status;

        #ifdef __HIP_PLATFORM_NVCC__
        const uint32_t threads = 64;
        const uint32_t max_blocks = 4096;
        #else
        const uint32_t threads = 256;
        const uint32_t max_blocks = 4096;
        #endif

        const size_t size = data_size / m_dimensions;
        const uint32_t blocks = std::min(max_blocks, static_cast<uint32_t>((size + threads - 1) / threads));

        // blocks_x must be power of 2 because strided discard (leap frog)
        // supports only power of 2 jumps
        const uint32_t blocks_x = next_power2((blocks + m_dimensions - 1) / m_dimensions);
        const uint32_t blocks_y = m_dimensions;
        hipLaunchKernelGGL(
            HIP_KERNEL_NAME(rocrand_host::detail::generate_kernel),
            dim3(blocks_x, blocks_y), dim3(threads), 0, m_stream,
            data, size,
            static_cast<const unsigned int*>(m_direction_vectors), m_current_offset,
            distribution
        );
        // Check kernel status
        if(hipPeekAtLastError() != hipSuccess)
            return ROCRAND_STATUS_LAUNCH_FAILURE;

        m_current_offset += size;

        return ROCRAND_STATUS_SUCCESS;
    }

    template<class T>
    rocrand_status generate_uniform(T * data, size_t data_size)
    {
        uniform_distribution<T> distribution;
        return generate(data, data_size, distribution);
    }

    template<class T>
    rocrand_status generate_normal(T * data, size_t data_size, T mean, T stddev)
    {
        normal_distribution<T> distribution(mean, stddev);
        return generate(data, data_size, distribution);
    }

    template<class T>
    rocrand_status generate_log_normal(T * data, size_t data_size, T mean, T stddev)
    {
        log_normal_distribution<T> distribution(mean, stddev);
        return generate(data, data_size, distribution);
    }

    rocrand_status generate_poisson(unsigned int * data, size_t data_size, double lambda)
    {
        try
        {
            m_poisson.set_lambda(lambda);
        }
        catch(rocrand_status status)
        {
            return status;
        }
        return generate(data, data_size, m_poisson.dis);
    }

private:
    bool m_initialized;
    unsigned int m_dimensions;
    unsigned int m_current_offset;
    unsigned int * m_direction_vectors;

    // For caching of Poisson for consecutive generations with the same lambda
    poisson_distribution_manager<ROCRAND_DISCRETE_METHOD_CDF> m_poisson;

    // m_offset from base_type

    size_t next_power2(size_t x)
    {
        size_t power = 1;
        while (power < x)
        {
            power *= 2;
        }
        return power;
    }
};

#endif // ROCRAND_RNG_SOBOL32_H_
<|endoftext|>


<commit_before>/**
 * @file   Path.cpp
 * @brief  Path class implementation.
 * @author zer0
 * @date   2016-10-14
 */

#include <libtbag/filesystem/Path.hpp>
#include <libtbag/filesystem/details/FsCanonical.hpp>
#include <libtbag/filesystem/details/FsNode.hpp>
#include <libtbag/filesystem/details/FsProhibited.hpp>
#include <libtbag/filesystem/details/FsCommon.hpp>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace filesystem {

char const * getLibraryPrefix()
{
#if defined(TBAG_PLATFORM_WINDOWS) && !defined(TBAG_PLATFORM_MINGW)
    return details::WINDOWS_SHARED_LIBRARY_PREFIX;
#else
    return details::ELF_SHARED_LIBRARY_PREFIX;
#endif
}

char const * getLibrarySuffix()
{
#if defined(TBAG_PLATFORM_WINDOWS)
# if defined(TBAG_PLATFORM_MINGW)
    return details::MINGW_SHARED_LIBRARY_SUFFIX;
# else  // if defined(TBAG_PLATFORM_MINGW)
    return details::WINDOWS_SHARED_LIBRARY_SUFFIX;
# endif // if defined(TBAG_PLATFORM_MINGW)
#elif defined(TBAG_PLATFORM_MACOS)
    return details::MACHO_SHARED_LIBRARY_SUFFIX;
#else
    return details::ELF_SHARED_LIBRARY_SUFFIX;
#endif
}

char const * getModuleSuffix()
{
#if defined(TBAG_PLATFORM_WINDOWS)
# if defined(TBAG_PLATFORM_MINGW)
    return details::MINGW_SHARED_LIBRARY_SUFFIX;
# else  // if defined(TBAG_PLATFORM_MINGW)
    return details::WINDOWS_SHARED_LIBRARY_SUFFIX;
# endif // if defined(TBAG_PLATFORM_MINGW)
#else
    return details::ELF_SHARED_LIBRARY_SUFFIX;
#endif
}

std::string getLibraryName(std::string const & name)
{
    return std::string(getLibraryPrefix()) + name + getLibrarySuffix();
}

std::string getModuleName(std::string const & name)
{
    return std::string(getLibraryPrefix()) + name + getModuleSuffix();
}

std::string getExecutablePrefix()
{
    return details::ELF_EXECUTABLE_PREFIX;
}

std::string getExecutableSuffix()
{
#if defined(TBAG_PLATFORM_WINDOWS)
    return details::WINDOWS_EXECUTABLE_SUFFIX;
#else
    return details::ELF_EXECUTABLE_SUFFIX;
#endif
}

std::string getExecutableName(std::string const & name)
{
    return getExecutablePrefix() + name + getExecutableSuffix();
}

// --------------------
// Path implementation.
// --------------------

Path::Path() TBAG_NOEXCEPT_SPECIFIER(std::is_nothrow_default_constructible<std::string>::value) : _path()
{
    // EMPTY.
}

Path::Path(std::string const & path) : _path(path)
{
    // EMPTY.
}

Path::Path(char const * path) : Path(std::string(path))
{
    // EMPTY.
}

Path::Path(char const * path, update_generic const & UNUSED_PARAM(v)) : Path(std::string(path))
{
    updateGeneric();
}

Path::Path(std::string const & path, update_generic const & UNUSED_PARAM(v)) : Path(path)
{
    updateGeneric();
}

Path::Path(char const * path, update_canonical const & UNUSED_PARAM(v)) : Path(std::string(path))
{
    updateCanonical();
}

Path::Path(std::string const & path, update_canonical const & UNUSED_PARAM(v)) : Path(path)
{
    updateCanonical();
}

Path::Path(std::vector<std::string> const & nodes) : Path()
{
    append(nodes);
}

Path::Path(std::initializer_list<std::string> list) : Path()
{
    for (auto & cursor : list) {
        append(cursor);
    }
}

Path::Path(Path const & obj) : Path()
{
    copy(obj);
}

Path::Path(Path && obj) : Path()
{
    swap(obj);
}

Path::~Path()
{
    // EMPTY.
}

Path & Path::operator =(char const * path)
{
    _path.assign(path);
    return *this;
}

Path & Path::operator =(std::string const & path)
{
    if (&(_path) != &path) {
        _path = path;
    }
    return *this;
}

Path & Path::operator =(std::string && path)
{
    if (&(_path) != &path) {
        _path.swap(path);
    }
    return *this;
}

Path & Path::operator =(Path const & obj)
{
    return copy(obj);
}

Path & Path::operator =(Path && obj)
{
    swap(obj);
    return *this;
}

bool Path::operator ==(Path const & path) const
{
    return getCanonicalString() == path.getCanonicalString();
}

bool Path::operator !=(Path const & path) const
{
    return !((*this) == path);
}

bool Path::operator ==(std::string const & path) const
{
    return getCanonicalString() == Path(path).getCanonicalString();
}

bool Path::operator !=(std::string const & path) const
{
    return !((*this) == path);
}

Path & Path::copy(Path const & obj)
{
    if (this != &obj) {
        _path = obj._path;
    }
    return *this;
}

void Path::swap(Path && obj)
{
    if (this != &obj) {
        _path.swap(obj._path);
    }
}

void Path::swap(Path & obj)
{
    if (this != &obj) {
        _path.swap(obj._path);
    }
}

std::string Path::getGenericString() const
{
    return details::getGeneric(_path);
}

Path Path::getGeneric() const
{
    return Path(getGenericString());
}

std::string Path::getNativeString() const
{
    return details::getNative(_path);
}

Path Path::getNative() const
{
    return Path(getNativeString());
}

Path Path::getCanonical() const
{
    return Path(splitNodesWithCanonical());
}

std::string Path::getCanonicalString() const
{
    return getCanonical().getString();
}

Path & Path::updateGeneric()
{
    setString(getGenericString());
    return *this;
}

Path & Path::updateNative()
{
    setString(getNativeString());
    return *this;
}

Path & Path::updateCanonical()
{
    setString(getCanonicalString());
    return *this;
}

std::string Path::getRootDirString() const
{
    return details::getRootDir(_path);
}

Path Path::getRootDir() const
{
    return Path(getRootDirString());
}

bool Path::isRootDir() const
{
    return Path(_path) == getRootDir();
}

bool Path::isAbsolute() const
{
    return details::isAbsolute(_path);
}

bool Path::isRelative() const
{
    return details::isRelative(_path);
}

std::string Path::append(std::string const & parent, std::string const & child)
{
    std::string result = parent;
    // [ko] "문지열이 공백일 경우 경로 분리자를 삽입하면 루트(Root)가 되는 현상을 방지한다." [ko]
    if (!parent.empty() && parent.back() != details::PATH_SEPARATOR) {
        result += details::PATH_SEPARATOR;
    }
    result += child;
    return result;
}

Path & Path::append(std::string const & child)
{
    _path = append(this->_path, child);
    return *this;
}

Path & Path::append(std::vector<std::string> const & nodes)
{
    for (auto & cursor : nodes) {
        append(cursor);
    }
    return *this;
}

Path & Path::operator /=(std::string const & child)
{
    return append(child);
}

/* FRIEND */ Path operator /(Path const & path, std::string const & child)
{
    Path result = path;
    result.append(child);
    return result;
}

/* FRIEND */ Path operator /(Path && path, std::string const & child)
{
    path.append(child);
    return path;
}

std::string Path::getParentString() const
{
    return details::getParent(_path);
}

Path Path::getParent() const
{
    return Path(getParentString());
}

std::vector<std::string> Path::splitNodes() const
{
    return details::splitNodes(_path);
}

std::vector<std::string> Path::splitNodesWithCanonical() const
{
    return details::splitNodesWithCanonical(_path);
}

std::string Path::getName() const
{
    auto nodes = splitNodes();
    if (nodes.rbegin() == nodes.rend()) {
        return std::string();
    }
    return *nodes.rbegin();
}

std::string Path::getNameWithoutExtension() const
{
    std::string name = getName();
    std::size_t pos = name.find(details::FILE_EXTENSION_DELIMITER);
    return name.substr(0, pos);
}

std::string Path::getExtensionName() const
{
    std::string name = getName();
    std::size_t pos = name.find(details::FILE_EXTENSION_DELIMITER);
    if (pos != std::string::npos) {
        return name.substr(pos);
    }
    return std::string();
}

Path::FileState Path::getState(bool * result) const
{
    FileState state = { 0, };
    bool const code = details::getState(_path, &state);
    if (result != nullptr) {
        *result = code;
    }
    return state;
}

bool Path::exists() const
{
    return details::exists(_path);
}

bool Path::isExecutable() const
{
    return details::isExecutable(_path);
}

bool Path::isWritable() const
{
    return details::isWritable(_path);
}

bool Path::isReadable() const
{
    return details::isReadable(_path);
}

bool Path::isRegularFile() const
{
    return details::isRegularFile(_path);
}

bool Path::isDirectory() const
{
    return details::isDirectory(_path);
}

bool Path::createDir(int mode) const
{
    if (details::createDirectoryEx(_path, mode)) {
        return true;
    }

    if (isRootDir()) {
        return false;
    }

    if (getParent().createDir(mode)) {
        return details::createDirectoryEx(_path, mode);
    }
    return false;
}

bool Path::remove() const
{
    if (isDirectory()) {
        return details::removeDirectory(_path);
    } else if (isRegularFile()) {
        return details::removeFile(_path);
    }
    return false;
}

bool Path::removeAll() const
{
    return details::removeAll(_path);
}

std::vector<std::string> Path::scanNameOnly(DirentType type) const
{
    return details::scanDir(_path, type);
}

std::vector<std::string> Path::scanRecurrentNameOnly(DirentType type) const
{
    std::vector<std::string> result;
    scanRecurrentNameOnly(type, Path(_path), Path(), result);
    return result;
}

std::vector<Path> Path::scanDir(DirentType type) const
{
    std::vector<Path> result;
    for (auto & cursor : scanNameOnly(type)) {
        result.push_back(Path(_path) / cursor);
    }
    return result;
}

std::vector<Path> Path::scanRecurrentDir(DirentType type) const
{
    auto const PARENT_DIR = Path(_path);
    std::vector<Path> result;
    for (auto & cursor : scanRecurrentNameOnly(type)) {
        result.push_back(PARENT_DIR / cursor);
    }
    return result;
}

void Path::scanRecurrentNameOnly(DirentType type,
                                 Path const & parent_dir,
                                 Path const & node,
                                 std::vector<std::string> & result)
{
    for (auto & dir_name : details::scanDir(parent_dir, Path::DIRENT_DIR)) {
        scanRecurrentNameOnly(type, parent_dir / dir_name, node / dir_name, result);
    }
    for (auto & cursor : details::scanDir(parent_dir, type)) {
        result.push_back(node / cursor);
    }
}

Path Path::getWorkDir()
{
    return Path(details::getWorkDir());
}

Path Path::getHomeDir()
{
    return Path(details::getHomeDir());
}

Path Path::getExePath()
{
    return Path(details::getExePath());
}

Path Path::getExeDir()
{
    return Path(details::removeLastNode(details::getExePath()));
}

// ----------
// Utilities.
// ----------

Err checkPrepareFiles(std::string const & source_path, std::string const & destination_path, bool check_dir)
{
    return checkPrepareFiles(Path(source_path), Path(destination_path));
}

Err checkPrepareFiles(Path const & source_path, Path const & destination_path, bool check_dir)
{
    if (!source_path.exists()) {
        // Not exists source file.
        return E_ENOENT;
    }

    if (!source_path.isReadable()) {
        // You do not have read permission.
        return E_EACCES;
    }

    if (destination_path.exists()) {
        // File already exists.
        return E_EEXIST;
    }

    Path const DESTINATION_DIR = destination_path.getParent();
    if (check_dir) {
        if (!DESTINATION_DIR.exists()) {
            // Not exists destination directory.
            return E_ENOENT;
        }

        if (!DESTINATION_DIR.isDirectory()) {
            // Not a directory.
            return E_ENOENT;
        }

        if (!DESTINATION_DIR.isWritable()) {
            // You do not have write permission.
            return E_EACCES;
        }
    }

    return E_SUCCESS;
}

} // namespace filesystem

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

<commit_msg>Changed internal behavior of Path.operator==() method from CanonicalPath to GenericPath.<commit_after>/**
 * @file   Path.cpp
 * @brief  Path class implementation.
 * @author zer0
 * @date   2016-10-14
 */

#include <libtbag/filesystem/Path.hpp>
#include <libtbag/filesystem/details/FsCanonical.hpp>
#include <libtbag/filesystem/details/FsNode.hpp>
#include <libtbag/filesystem/details/FsProhibited.hpp>
#include <libtbag/filesystem/details/FsCommon.hpp>

// -------------------
NAMESPACE_LIBTBAG_OPEN
// -------------------

namespace filesystem {

char const * getLibraryPrefix()
{
#if defined(TBAG_PLATFORM_WINDOWS) && !defined(TBAG_PLATFORM_MINGW)
    return details::WINDOWS_SHARED_LIBRARY_PREFIX;
#else
    return details::ELF_SHARED_LIBRARY_PREFIX;
#endif
}

char const * getLibrarySuffix()
{
#if defined(TBAG_PLATFORM_WINDOWS)
# if defined(TBAG_PLATFORM_MINGW)
    return details::MINGW_SHARED_LIBRARY_SUFFIX;
# else  // if defined(TBAG_PLATFORM_MINGW)
    return details::WINDOWS_SHARED_LIBRARY_SUFFIX;
# endif // if defined(TBAG_PLATFORM_MINGW)
#elif defined(TBAG_PLATFORM_MACOS)
    return details::MACHO_SHARED_LIBRARY_SUFFIX;
#else
    return details::ELF_SHARED_LIBRARY_SUFFIX;
#endif
}

char const * getModuleSuffix()
{
#if defined(TBAG_PLATFORM_WINDOWS)
# if defined(TBAG_PLATFORM_MINGW)
    return details::MINGW_SHARED_LIBRARY_SUFFIX;
# else  // if defined(TBAG_PLATFORM_MINGW)
    return details::WINDOWS_SHARED_LIBRARY_SUFFIX;
# endif // if defined(TBAG_PLATFORM_MINGW)
#else
    return details::ELF_SHARED_LIBRARY_SUFFIX;
#endif
}

std::string getLibraryName(std::string const & name)
{
    return std::string(getLibraryPrefix()) + name + getLibrarySuffix();
}

std::string getModuleName(std::string const & name)
{
    return std::string(getLibraryPrefix()) + name + getModuleSuffix();
}

std::string getExecutablePrefix()
{
    return details::ELF_EXECUTABLE_PREFIX;
}

std::string getExecutableSuffix()
{
#if defined(TBAG_PLATFORM_WINDOWS)
    return details::WINDOWS_EXECUTABLE_SUFFIX;
#else
    return details::ELF_EXECUTABLE_SUFFIX;
#endif
}

std::string getExecutableName(std::string const & name)
{
    return getExecutablePrefix() + name + getExecutableSuffix();
}

// --------------------
// Path implementation.
// --------------------

Path::Path() TBAG_NOEXCEPT_SPECIFIER(std::is_nothrow_default_constructible<std::string>::value) : _path()
{
    // EMPTY.
}

Path::Path(std::string const & path) : _path(path)
{
    // EMPTY.
}

Path::Path(char const * path) : Path(std::string(path))
{
    // EMPTY.
}

Path::Path(char const * path, update_generic const & UNUSED_PARAM(v)) : Path(std::string(path))
{
    updateGeneric();
}

Path::Path(std::string const & path, update_generic const & UNUSED_PARAM(v)) : Path(path)
{
    updateGeneric();
}

Path::Path(char const * path, update_canonical const & UNUSED_PARAM(v)) : Path(std::string(path))
{
    updateCanonical();
}

Path::Path(std::string const & path, update_canonical const & UNUSED_PARAM(v)) : Path(path)
{
    updateCanonical();
}

Path::Path(std::vector<std::string> const & nodes) : Path()
{
    append(nodes);
}

Path::Path(std::initializer_list<std::string> list) : Path()
{
    for (auto & cursor : list) {
        append(cursor);
    }
}

Path::Path(Path const & obj) : Path()
{
    copy(obj);
}

Path::Path(Path && obj) : Path()
{
    swap(obj);
}

Path::~Path()
{
    // EMPTY.
}

Path & Path::operator =(char const * path)
{
    _path.assign(path);
    return *this;
}

Path & Path::operator =(std::string const & path)
{
    if (&(_path) != &path) {
        _path = path;
    }
    return *this;
}

Path & Path::operator =(std::string && path)
{
    if (&(_path) != &path) {
        _path.swap(path);
    }
    return *this;
}

Path & Path::operator =(Path const & obj)
{
    return copy(obj);
}

Path & Path::operator =(Path && obj)
{
    swap(obj);
    return *this;
}

bool Path::operator ==(Path const & path) const
{
    return getGenericString() == path.getGenericString();
}

bool Path::operator !=(Path const & path) const
{
    return !((*this) == path);
}

bool Path::operator ==(std::string const & path) const
{
    return getGenericString() == Path(path).getGenericString();
}

bool Path::operator !=(std::string const & path) const
{
    return !((*this) == path);
}

Path & Path::copy(Path const & obj)
{
    if (this != &obj) {
        _path = obj._path;
    }
    return *this;
}

void Path::swap(Path && obj)
{
    if (this != &obj) {
        _path.swap(obj._path);
    }
}

void Path::swap(Path & obj)
{
    if (this != &obj) {
        _path.swap(obj._path);
    }
}

std::string Path::getGenericString() const
{
    return details::getGeneric(_path);
}

Path Path::getGeneric() const
{
    return Path(getGenericString());
}

std::string Path::getNativeString() const
{
    return details::getNative(_path);
}

Path Path::getNative() const
{
    return Path(getNativeString());
}

Path Path::getCanonical() const
{
    return Path(splitNodesWithCanonical());
}

std::string Path::getCanonicalString() const
{
    return getCanonical().getString();
}

Path & Path::updateGeneric()
{
    setString(getGenericString());
    return *this;
}

Path & Path::updateNative()
{
    setString(getNativeString());
    return *this;
}

Path & Path::updateCanonical()
{
    setString(getCanonicalString());
    return *this;
}

std::string Path::getRootDirString() const
{
    return details::getRootDir(_path);
}

Path Path::getRootDir() const
{
    return Path(getRootDirString());
}

bool Path::isRootDir() const
{
    return Path(_path) == getRootDir();
}

bool Path::isAbsolute() const
{
    return details::isAbsolute(_path);
}

bool Path::isRelative() const
{
    return details::isRelative(_path);
}

std::string Path::append(std::string const & parent, std::string const & child)
{
    std::string result = parent;
    // [ko] "문지열이 공백일 경우 경로 분리자를 삽입하면 루트(Root)가 되는 현상을 방지한다." [ko]
    if (!parent.empty() && parent.back() != details::PATH_SEPARATOR) {
        result += details::PATH_SEPARATOR;
    }
    result += child;
    return result;
}

Path & Path::append(std::string const & child)
{
    _path = append(this->_path, child);
    return *this;
}

Path & Path::append(std::vector<std::string> const & nodes)
{
    for (auto & cursor : nodes) {
        append(cursor);
    }
    return *this;
}

Path & Path::operator /=(std::string const & child)
{
    return append(child);
}

/* FRIEND */ Path operator /(Path const & path, std::string const & child)
{
    Path result = path;
    result.append(child);
    return result;
}

/* FRIEND */ Path operator /(Path && path, std::string const & child)
{
    path.append(child);
    return path;
}

std::string Path::getParentString() const
{
    return details::getParent(_path);
}

Path Path::getParent() const
{
    return Path(getParentString());
}

std::vector<std::string> Path::splitNodes() const
{
    return details::splitNodes(_path);
}

std::vector<std::string> Path::splitNodesWithCanonical() const
{
    return details::splitNodesWithCanonical(_path);
}

std::string Path::getName() const
{
    auto nodes = splitNodes();
    if (nodes.rbegin() == nodes.rend()) {
        return std::string();
    }
    return *nodes.rbegin();
}

std::string Path::getNameWithoutExtension() const
{
    std::string name = getName();
    std::size_t pos = name.find(details::FILE_EXTENSION_DELIMITER);
    return name.substr(0, pos);
}

std::string Path::getExtensionName() const
{
    std::string name = getName();
    std::size_t pos = name.find(details::FILE_EXTENSION_DELIMITER);
    if (pos != std::string::npos) {
        return name.substr(pos);
    }
    return std::string();
}

Path::FileState Path::getState(bool * result) const
{
    FileState state = { 0, };
    bool const code = details::getState(_path, &state);
    if (result != nullptr) {
        *result = code;
    }
    return state;
}

bool Path::exists() const
{
    return details::exists(_path);
}

bool Path::isExecutable() const
{
    return details::isExecutable(_path);
}

bool Path::isWritable() const
{
    return details::isWritable(_path);
}

bool Path::isReadable() const
{
    return details::isReadable(_path);
}

bool Path::isRegularFile() const
{
    return details::isRegularFile(_path);
}

bool Path::isDirectory() const
{
    return details::isDirectory(_path);
}

bool Path::createDir(int mode) const
{
    if (details::createDirectoryEx(_path, mode)) {
        return true;
    }

    if (isRootDir()) {
        return false;
    }

    if (getParent().createDir(mode)) {
        return details::createDirectoryEx(_path, mode);
    }
    return false;
}

bool Path::remove() const
{
    if (isDirectory()) {
        return details::removeDirectory(_path);
    } else if (isRegularFile()) {
        return details::removeFile(_path);
    }
    return false;
}

bool Path::removeAll() const
{
    return details::removeAll(_path);
}

std::vector<std::string> Path::scanNameOnly(DirentType type) const
{
    return details::scanDir(_path, type);
}

std::vector<std::string> Path::scanRecurrentNameOnly(DirentType type) const
{
    std::vector<std::string> result;
    scanRecurrentNameOnly(type, Path(_path), Path(), result);
    return result;
}

std::vector<Path> Path::scanDir(DirentType type) const
{
    std::vector<Path> result;
    for (auto & cursor : scanNameOnly(type)) {
        result.push_back(Path(_path) / cursor);
    }
    return result;
}

std::vector<Path> Path::scanRecurrentDir(DirentType type) const
{
    auto const PARENT_DIR = Path(_path);
    std::vector<Path> result;
    for (auto & cursor : scanRecurrentNameOnly(type)) {
        result.push_back(PARENT_DIR / cursor);
    }
    return result;
}

void Path::scanRecurrentNameOnly(DirentType type,
                                 Path const & parent_dir,
                                 Path const & node,
                                 std::vector<std::string> & result)
{
    for (auto & dir_name : details::scanDir(parent_dir, Path::DIRENT_DIR)) {
        scanRecurrentNameOnly(type, parent_dir / dir_name, node / dir_name, result);
    }
    for (auto & cursor : details::scanDir(parent_dir, type)) {
        result.push_back(node / cursor);
    }
}

Path Path::getWorkDir()
{
    return Path(details::getWorkDir());
}

Path Path::getHomeDir()
{
    return Path(details::getHomeDir());
}

Path Path::getExePath()
{
    return Path(details::getExePath());
}

Path Path::getExeDir()
{
    return Path(details::removeLastNode(details::getExePath()));
}

// ----------
// Utilities.
// ----------

Err checkPrepareFiles(std::string const & source_path, std::string const & destination_path, bool check_dir)
{
    return checkPrepareFiles(Path(source_path), Path(destination_path));
}

Err checkPrepareFiles(Path const & source_path, Path const & destination_path, bool check_dir)
{
    if (!source_path.exists()) {
        // Not exists source file.
        return E_ENOENT;
    }

    if (!source_path.isReadable()) {
        // You do not have read permission.
        return E_EACCES;
    }

    if (destination_path.exists()) {
        // File already exists.
        return E_EEXIST;
    }

    Path const DESTINATION_DIR = destination_path.getParent();
    if (check_dir) {
        if (!DESTINATION_DIR.exists()) {
            // Not exists destination directory.
            return E_ENOENT;
        }

        if (!DESTINATION_DIR.isDirectory()) {
            // Not a directory.
            return E_ENOENT;
        }

        if (!DESTINATION_DIR.isWritable()) {
            // You do not have write permission.
            return E_EACCES;
        }
    }

    return E_SUCCESS;
}

} // namespace filesystem

// --------------------
NAMESPACE_LIBTBAG_CLOSE
// --------------------

<|endoftext|>


<commit_before>/**
 * @file    PollerMgr.cpp
 * @author  Longwei Lai<lailongwei@126.com>
 * @date    2014/11/14
 * @version 1.0
 *
 * @brief
 */

#include "llbc/common/Export.h"
#include "llbc/common/BeforeIncl.h"

#include "llbc/comm/Packet.h"
#include "llbc/comm/Socket.h"
#include "llbc/comm/PollerType.h"
#include "llbc/comm/PollerEvent.h"
#include "llbc/comm/BasePoller.h"
#include "llbc/comm/PollerMgr.h"

namespace
{
    typedef LLBC_NS LLBC_PollerMgr This;
}

__LLBC_INTERNAL_NS_BEGIN

static LLBC_NS LLBC_Socket *__CreateSocket(int type)
{
    LLBC_NS LLBC_SocketHandle handle = LLBC_INVALID_SOCKET_HANDLE;
#if LLBC_TARGET_PLATFORM_WIN32
    if (type == LLBC_NS LLBC_PollerType::IocpPoller)
        if (UNLIKELY((handle = LLBC_NS LLBC_CreateTcpSocketEx()) == LLBC_INVALID_SOCKET_HANDLE))
            return NULL;
#endif

    LLBC_NS LLBC_Socket *sock =
        LLBC_New1(LLBC_NS LLBC_Socket, handle);
    sock->SetPollerType(type);

    return sock;
}

__LLBC_INTERNAL_NS_END

__LLBC_NS_BEGIN

LLBC_PollerMgr::LLBC_PollerMgr()
: _type(LLBC_PollerType::End)
, _svc(NULL)

, _pollerCount(0)
, _pollers(NULL)
, _pollerLock()

, _maxSessionId(1)

, _pendingAddSocks()
, _pendingAsyncConns()
{
}

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

void LLBC_PollerMgr::SetPollerType(int type)
{
    _type = type;
}

void LLBC_PollerMgr::SetService(LLBC_IService *svc)
{
    _svc = svc;
}

int LLBC_PollerMgr::Start(int count)
{
    if (count <= 0)
    {
        LLBC_SetLastError(LLBC_ERROR_INVALID);
        return LLBC_FAILED;
    }
    else if (_pollers)
    {
        LLBC_SetLastError(LLBC_ERROR_REENTRY);
        return LLBC_FAILED;
    }

    _pollerCount = count;
    _pollers = LLBC_Malloc(LLBC_BasePoller *, sizeof(LLBC_BasePoller *) * count);
    ::memset(_pollers, 0, sizeof(LLBC_BasePoller *) * count);

    // Create pollers.
    for (int i = 0; i < count; i++)
    {
        _pollers[i] = LLBC_BasePoller::Create(_type);
        _pollers[i]->SetPollerId(i);
        _pollers[i]->SetService(_svc);
        _pollers[i]->SetPollerMgr(this);
        _pollers[i]->SetBrothersCount(count);
    }

    // Startup all pollers.
    for (int i = 0; i < count; i++)
        _pollers[i]->Start();

    // Process pending sockets.
    for (_PendingAddSocks::iterator it = _pendingAddSocks.begin();
         it != _pendingAddSocks.end();
         it++)
         _pollers[it->first % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAddSockEv(it->first, it->second));
    _pendingAddSocks.clear();

    // Process Async-connections.
    for (_PendingAsyncConns::iterator it = _pendingAsyncConns.begin();
         it != _pendingAsyncConns.end();
         it++)
        _pollers[it->first % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAsyncConnEv(it->first, it->second));
    _pendingAsyncConns.clear();

    return LLBC_OK;
}

void LLBC_PollerMgr::Stop()
{
    // Always cleanup pending add-sock container.
    LLBC_STLHelper::DeleteContainer(_pendingAddSocks);
    // Always cleanup pending async-conn container.
    _pendingAsyncConns.clear();

    if (_pollers)
    {
        for (int i = 0; i < _pollerCount; i++)
            LLBC_Delete(_pollers[i]);
        LLBC_XFree(_pollers);
        _pollerCount = 0;
    }

    _maxSessionId = 1;
}

int LLBC_PollerMgr::Listen(const char *ip, uint16 port)
{
    LLBC_SockAddr_IN local;
    if (This::GetAddr(ip, port, local) != LLBC_OK)
        return 0;

    LLBC_Socket *sock;
    if (!(sock = LLBC_INL_NS __CreateSocket(_type)))
    {
        return 0;
    }
    else if (sock->SetNonBlocking() != LLBC_OK ||
            sock->EnableAddressReusable() != LLBC_OK ||
            sock->BindTo(local) != LLBC_OK ||
            sock->Listen() != LLBC_OK)
    {
        LLBC_Delete(sock);
        return 0;
    }

    const int sessionId = AllocSessionId();
    if (LIKELY(_pollers))
        _pollers[sessionId % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAddSockEv(sessionId, sock));
    else
        _pendingAddSocks.insert(std::make_pair(sessionId, sock));

    return sessionId;
}

int LLBC_PollerMgr::Connect(const char *ip, uint16 port)
{
    LLBC_SockAddr_IN peer;
    if (This::GetAddr(ip, port, peer) != LLBC_OK)
        return 0;

    LLBC_Socket *sock;
    if (!(sock = LLBC_INL_NS __CreateSocket(_type)))
    {
        return 0;
    }
    else if (sock->Connect(peer) != LLBC_OK)
    {
        LLBC_Delete(sock);
        return 0;
    }

    sock->SetNonBlocking();

    const int sessionId = AllocSessionId();

    if (LIKELY(_pollers))
        _pollers[sessionId % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAddSockEv(sessionId, sock));
    else
        _pendingAddSocks.insert(std::make_pair(sessionId, sock));

    return sessionId;
}

int LLBC_PollerMgr::AsyncConn(const char *ip, uint16 port)
{
    LLBC_SockAddr_IN peer;
    if (This::GetAddr(ip, port, peer) != LLBC_OK)
        return LLBC_FAILED;

    const int sessionId = AllocSessionId();
    if (LIKELY(_pollers))
        _pollers[sessionId % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAsyncConnEv(sessionId, peer));
    else
        _pendingAsyncConns.insert(std::make_pair(sessionId, peer));

    return LLBC_OK;
}

int LLBC_PollerMgr::Send(LLBC_Packet *packet)
{
    _pollers[packet->GetSessionId() %
        _pollerCount]->Push(LLBC_PollerEvUtil::BuildSendEv(packet));
    return LLBC_OK;
}

void LLBC_PollerMgr::Close(int sessionId, const char *reason)
{
    _pollers[sessionId % _pollerCount]->Push(LLBC_PollerEvUtil::BuildCloseEv(sessionId, reason));
}

int LLBC_PollerMgr::AllocSessionId()
{
    return LLBC_AtomicFetchAndAdd(&_maxSessionId, 1);
}

int LLBC_PollerMgr::PushMsgToPoller(int id, LLBC_MessageBlock *block)
{
    LLBC_Guard guard(_pollerLock);
    LLBC_BasePoller *poller = _pollers[id];
    if (LIKELY(poller))
    {
        poller->Push(block);
        return LLBC_OK;
    }

    return LLBC_FAILED;
}

void LLBC_PollerMgr::OnPollerStop(int id)
{
    _pollerLock.Lock();
    _pollers[id] = NULL;

    _pollerLock.Unlock();
}

int LLBC_PollerMgr::GetAddr(const char *ip, uint16 port, LLBC_SockAddr_IN &addr)
{
    if (LLBC_IsIPv4Addr(ip))
    {
        addr.SetIp(ip);
        addr.SetPort(port);

        return LLBC_OK;
    }

    // Use LLBC_GetAddrInfo to fetch sockaddr.
    struct addrinfo hints;
    hints.ai_flags = 0;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_addrlen = 0;
    hints.ai_addr = NULL;
    hints.ai_canonname = NULL;
    hints.ai_next = NULL;

    struct addrinfo *ai;
    if (LLBC_GetAddrInfo(ip,                        // servname
                         LLBC_Num2Str(port).c_str(),// nodename
                         &hints,                    // hints
                         &ai) != LLBC_OK)       // result
        return LLBC_FAILED;

    addr.FromOSDataType(reinterpret_cast<
            struct sockaddr_in *>(ai->ai_addr));
    LLBC_FreeAddrInfo(ai);

    return LLBC_OK;
}

__LLBC_NS_END

#include "llbc/common/AfterIncl.h"
<commit_msg>Adjust the code alignment<commit_after>/**
 * @file    PollerMgr.cpp
 * @author  Longwei Lai<lailongwei@126.com>
 * @date    2014/11/14
 * @version 1.0
 *
 * @brief
 */

#include "llbc/common/Export.h"
#include "llbc/common/BeforeIncl.h"

#include "llbc/comm/Packet.h"
#include "llbc/comm/Socket.h"
#include "llbc/comm/PollerType.h"
#include "llbc/comm/PollerEvent.h"
#include "llbc/comm/BasePoller.h"
#include "llbc/comm/PollerMgr.h"

namespace
{
    typedef LLBC_NS LLBC_PollerMgr This;
}

__LLBC_INTERNAL_NS_BEGIN

static LLBC_NS LLBC_Socket *__CreateSocket(int type)
{
    LLBC_NS LLBC_SocketHandle handle = LLBC_INVALID_SOCKET_HANDLE;
#if LLBC_TARGET_PLATFORM_WIN32
    if (type == LLBC_NS LLBC_PollerType::IocpPoller)
        if (UNLIKELY((handle = LLBC_NS LLBC_CreateTcpSocketEx()) == LLBC_INVALID_SOCKET_HANDLE))
            return NULL;
#endif

    LLBC_NS LLBC_Socket *sock =
        LLBC_New1(LLBC_NS LLBC_Socket, handle);
    sock->SetPollerType(type);

    return sock;
}

__LLBC_INTERNAL_NS_END

__LLBC_NS_BEGIN

LLBC_PollerMgr::LLBC_PollerMgr()
: _type(LLBC_PollerType::End)
, _svc(NULL)

, _pollerCount(0)
, _pollers(NULL)
, _pollerLock()

, _maxSessionId(1)

, _pendingAddSocks()
, _pendingAsyncConns()
{
}

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

void LLBC_PollerMgr::SetPollerType(int type)
{
    _type = type;
}

void LLBC_PollerMgr::SetService(LLBC_IService *svc)
{
    _svc = svc;
}

int LLBC_PollerMgr::Start(int count)
{
    if (count <= 0)
    {
        LLBC_SetLastError(LLBC_ERROR_INVALID);
        return LLBC_FAILED;
    }
    else if (_pollers)
    {
        LLBC_SetLastError(LLBC_ERROR_REENTRY);
        return LLBC_FAILED;
    }

    _pollerCount = count;
    _pollers = LLBC_Malloc(LLBC_BasePoller *, sizeof(LLBC_BasePoller *) * count);
    ::memset(_pollers, 0, sizeof(LLBC_BasePoller *) * count);

    // Create pollers.
    for (int i = 0; i < count; i++)
    {
        _pollers[i] = LLBC_BasePoller::Create(_type);
        _pollers[i]->SetPollerId(i);
        _pollers[i]->SetService(_svc);
        _pollers[i]->SetPollerMgr(this);
        _pollers[i]->SetBrothersCount(count);
    }

    // Startup all pollers.
    for (int i = 0; i < count; i++)
        _pollers[i]->Start();

    // Process pending sockets.
    for (_PendingAddSocks::iterator it = _pendingAddSocks.begin();
         it != _pendingAddSocks.end();
         it++)
         _pollers[it->first % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAddSockEv(it->first, it->second));
    _pendingAddSocks.clear();

    // Process Async-connections.
    for (_PendingAsyncConns::iterator it = _pendingAsyncConns.begin();
         it != _pendingAsyncConns.end();
         it++)
        _pollers[it->first % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAsyncConnEv(it->first, it->second));
    _pendingAsyncConns.clear();

    return LLBC_OK;
}

void LLBC_PollerMgr::Stop()
{
    // Always cleanup pending add-sock container.
    LLBC_STLHelper::DeleteContainer(_pendingAddSocks);
    // Always cleanup pending async-conn container.
    _pendingAsyncConns.clear();

    if (_pollers)
    {
        for (int i = 0; i < _pollerCount; i++)
            LLBC_Delete(_pollers[i]);
        LLBC_XFree(_pollers);
        _pollerCount = 0;
    }

    _maxSessionId = 1;
}

int LLBC_PollerMgr::Listen(const char *ip, uint16 port)
{
    LLBC_SockAddr_IN local;
    if (This::GetAddr(ip, port, local) != LLBC_OK)
        return 0;

    LLBC_Socket *sock;
    if (!(sock = LLBC_INL_NS __CreateSocket(_type)))
    {
        return 0;
    }
    else if (sock->SetNonBlocking() != LLBC_OK ||
            sock->EnableAddressReusable() != LLBC_OK ||
            sock->BindTo(local) != LLBC_OK ||
            sock->Listen() != LLBC_OK)
    {
        LLBC_Delete(sock);
        return 0;
    }

    const int sessionId = AllocSessionId();
    if (LIKELY(_pollers))
        _pollers[sessionId % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAddSockEv(sessionId, sock));
    else
        _pendingAddSocks.insert(std::make_pair(sessionId, sock));

    return sessionId;
}

int LLBC_PollerMgr::Connect(const char *ip, uint16 port)
{
    LLBC_SockAddr_IN peer;
    if (This::GetAddr(ip, port, peer) != LLBC_OK)
        return 0;

    LLBC_Socket *sock;
    if (!(sock = LLBC_INL_NS __CreateSocket(_type)))
    {
        return 0;
    }
    else if (sock->Connect(peer) != LLBC_OK)
    {
        LLBC_Delete(sock);
        return 0;
    }

    sock->SetNonBlocking();

    const int sessionId = AllocSessionId();

    if (LIKELY(_pollers))
        _pollers[sessionId % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAddSockEv(sessionId, sock));
    else
        _pendingAddSocks.insert(std::make_pair(sessionId, sock));

    return sessionId;
}

int LLBC_PollerMgr::AsyncConn(const char *ip, uint16 port)
{
    LLBC_SockAddr_IN peer;
    if (This::GetAddr(ip, port, peer) != LLBC_OK)
        return LLBC_FAILED;

    const int sessionId = AllocSessionId();
    if (LIKELY(_pollers))
        _pollers[sessionId % _pollerCount]->Push(
                LLBC_PollerEvUtil::BuildAsyncConnEv(sessionId, peer));
    else
        _pendingAsyncConns.insert(std::make_pair(sessionId, peer));

    return LLBC_OK;
}

int LLBC_PollerMgr::Send(LLBC_Packet *packet)
{
    _pollers[packet->GetSessionId() %
        _pollerCount]->Push(LLBC_PollerEvUtil::BuildSendEv(packet));
    return LLBC_OK;
}

void LLBC_PollerMgr::Close(int sessionId, const char *reason)
{
    _pollers[sessionId % _pollerCount]->Push(LLBC_PollerEvUtil::BuildCloseEv(sessionId, reason));
}

int LLBC_PollerMgr::AllocSessionId()
{
    return LLBC_AtomicFetchAndAdd(&_maxSessionId, 1);
}

int LLBC_PollerMgr::PushMsgToPoller(int id, LLBC_MessageBlock *block)
{
    LLBC_Guard guard(_pollerLock);
    LLBC_BasePoller *poller = _pollers[id];
    if (LIKELY(poller))
    {
        poller->Push(block);
        return LLBC_OK;
    }

    return LLBC_FAILED;
}

void LLBC_PollerMgr::OnPollerStop(int id)
{
    _pollerLock.Lock();
    _pollers[id] = NULL;

    _pollerLock.Unlock();
}

int LLBC_PollerMgr::GetAddr(const char *ip, uint16 port, LLBC_SockAddr_IN &addr)
{
    if (LLBC_IsIPv4Addr(ip))
    {
        addr.SetIp(ip);
        addr.SetPort(port);

        return LLBC_OK;
    }

    // Use LLBC_GetAddrInfo to fetch sockaddr.
    struct addrinfo hints;
    hints.ai_flags = 0;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_addrlen = 0;
    hints.ai_addr = NULL;
    hints.ai_canonname = NULL;
    hints.ai_next = NULL;

    struct addrinfo *ai;
    if (LLBC_GetAddrInfo(ip,                         // servname
                         LLBC_Num2Str(port).c_str(), // nodename
                         &hints,                     // hints
                         &ai) != LLBC_OK)            // result
        return LLBC_FAILED;

    addr.FromOSDataType(reinterpret_cast<
            struct sockaddr_in *>(ai->ai_addr));
    LLBC_FreeAddrInfo(ai);

    return LLBC_OK;
}

__LLBC_NS_END

#include "llbc/common/AfterIncl.h"
<|endoftext|>