<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// oa_hash_table_test.cpp
//
// Identification: test/codegen/oa_hash_table_test.cpp
//
// Copyright (c) 2015-2018, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <unordered_map>

#include "common/harness.h"

#include "murmur3/MurmurHash3.h"
#include "libcuckoo/cuckoohash_map.hh"

#include "codegen/util/oa_hash_table.h"
#include "common/timer.h"

namespace peloton {
namespace test {

class OAHashTableTest : public PelotonTest {
 public:
  // The key and value object we store in the hash table
  struct Key {
    uint32_t k1, k2;

    Key(uint32_t _k1, uint32_t _k2) : k1(_k1), k2(_k2) {}

    bool operator==(const Key &rhs) const {
      return k1 == rhs.k1 && k2 == rhs.k2;
    }
    bool operator!=(const Key &rhs) const { return !(rhs == *this); }
  };

  struct Value {
    uint32_t v1, v2, v3, v4;
    bool operator==(const Value &rhs) const {
      return v1 == rhs.v1 && v2 == rhs.v2 && v3 == rhs.v3 && v4 == rhs.v4;
    }
    bool operator!=(const Value &rhs) const { return !(rhs == *this); }
  };

  OAHashTableTest() : ht_(sizeof(Key), sizeof(Value)) {}

  static uint32_t Hash(const Key &k) {
    static constexpr uint32_t seed = 12345;
    auto h1 = MurmurHash3_x86_32(&k.k1, sizeof(uint32_t), seed);
    auto h2 = MurmurHash3_x86_32(&k.k2, sizeof(uint32_t), seed);
    return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
  }

  void Insert(Key k, Value v) { GetHashTable().Insert(Hash(k), k, v); }

  codegen::util::OAHashTable &GetHashTable() { return ht_; }

 private:
  // The open-addressing hash-table instance
  codegen::util::OAHashTable ht_;
};

TEST_F(OAHashTableTest, CanInsertKeyValuePairs) {
  Value v = {3, 4, 5, 6};

  uint32_t to_insert = 50000;

  // Insert a bunch of unique keys
  for (uint32_t i = 0; i < to_insert; i++) {
    Insert({1, i}, v);
  }

  // Check validity
  EXPECT_EQ(to_insert, GetHashTable().NumEntries());
  EXPECT_EQ(to_insert, GetHashTable().NumOccupiedBuckets());

  // Insert a duplicate key-value pair
  Insert({1, 0}, v);

  // Duplicate keys don't occupy additional buckets
  EXPECT_EQ(to_insert + 1, GetHashTable().NumEntries());
  EXPECT_EQ(to_insert, GetHashTable().NumOccupiedBuckets());
}

TEST_F(OAHashTableTest, CanIterate) {
  Value v = {3, 4, 5, 6};

  uint32_t to_insert = 50000;

  // Insert a bunch of unique keys
  for (uint32_t i = 0; i < to_insert; i++) {
    Insert({1, i}, v);
  }

  auto &hashtable = GetHashTable();

  // Check that we find them all
  uint32_t i = 0;
  for (auto iter = hashtable.begin(), end = hashtable.end(); iter != end;
       ++iter) {
    i++;
  }

  EXPECT_EQ(to_insert, i);

  // Insert two duplicate keys to make sure iteration catches it
  Key key_dup{1, 0};
  Value vdup1 = {6, 5, 4, 3}, vdup2{4, 4, 4, 4};

  Insert(key_dup, vdup1);
  Insert(key_dup, vdup2);

  i = 0;
  uint32_t dup_count = 0;
  for (auto iter = hashtable.begin(), end = hashtable.end(); iter != end;
       ++iter) {
    const auto *iter_key = reinterpret_cast<const Key *>(iter.Key());
    if (*iter_key == key_dup) {
      dup_count++;
      const auto *iter_val = reinterpret_cast<const Value *>(iter.Value());
      EXPECT_TRUE(*iter_val == v || *iter_val == vdup1 || *iter_val == vdup2);
    }
    i++;
  }

  EXPECT_EQ(to_insert + 2, i);
  EXPECT_EQ(3, dup_count);
}

TEST_F(OAHashTableTest, MicroBenchmark) {
  uint32_t num_runs = 10;

  std::vector<Key> keys;
  Value v = {6, 5, 4, 3};

  std::random_device r;
  std::default_random_engine e(r());
  std::uniform_int_distribution<uint32_t> gen;

  // Create all keys
  uint32_t num_keys = 100000;
  for (uint32_t i = 0; i < num_keys; i++) {
    keys.emplace_back(gen(e), gen(e));
  }

  double avg_oaht_insert = 0.0, avg_oaht_probe = 0.0;
  double avg_map_insert = 0.0, avg_map_probe = 0.0;
  double avg_cuckoo_insert = 0.0, avg_cuckoo_probe = 0.0;

  // First, bench ours ...
  {
    for (uint32_t b = 0; b < num_runs; b++) {
      codegen::util::OAHashTable ht(
          sizeof(Key), sizeof(Value),
          codegen::util::OAHashTable::kDefaultInitialSize);

      Timer<std::ratio<1, 1000>> timer;
      timer.Start();

      // Start Insert
      for (uint32_t i = 0; i < num_keys; i++) {
        ht.Insert(Hash(keys[i]), keys[i], v);
      }
      // End Insert

      timer.Stop();
      avg_oaht_insert += timer.GetDuration();

      timer.Reset();
      timer.Start();

      // Start Probe
      std::vector<Key> shuffled = keys;
      std::random_shuffle(shuffled.begin(), shuffled.end());
      for (uint32_t i = 0; i < num_keys; i++) {
        Value probe_val;
        EXPECT_TRUE(ht.Probe(Hash(shuffled[i]), shuffled[i], probe_val));
      }
      // End Probe

      timer.Stop();
      avg_oaht_probe += timer.GetDuration();
    }
  }

  // Next, unordered_map ...
  {
    struct Hasher {
      size_t operator()(const Key &k) const { return Hash(k); }
    };

    for (uint32_t b = 0; b < num_runs; b++) {
      std::unordered_map<Key, Value, Hasher> ht(
          codegen::util::OAHashTable::kDefaultInitialSize);

      Timer<std::ratio<1, 1000>> timer;
      timer.Start();

      for (uint32_t i = 0; i < num_keys; i++) {
        ht.insert(std::make_pair(keys[i], v));
      }

      timer.Stop();
      avg_map_insert += timer.GetDuration();

      timer.Reset();
      timer.Start();

      // Start Probe
      std::vector<Key> shuffled = keys;
      std::random_shuffle(shuffled.begin(), shuffled.end());
      for (uint32_t i = 0; i < num_keys; i++) {
        EXPECT_NE(ht.find(shuffled[i]), ht.end());
      }
      // End Probe

      timer.Stop();
      avg_map_probe += timer.GetDuration();
    }
  }

  // Next, cuckoo map
  {
    struct Hasher {
      size_t operator()(const Key &k) const { return Hash(k); }
    };

    for (uint32_t b = 0; b < num_runs; b++) {
      cuckoohash_map<Key, Value, Hasher> map(
          codegen::util::OAHashTable::kDefaultInitialSize);

      Timer<std::ratio<1, 1000>> timer;
      timer.Start();

      for (uint32_t i = 0; i < num_keys; i++) {
        map.insert(keys[i], v);
      }

      timer.Stop();
      avg_cuckoo_insert += timer.GetDuration();

      timer.Reset();
      timer.Start();

      // Start Probe
      std::vector<Key> shuffled = keys;
      std::random_shuffle(shuffled.begin(), shuffled.end());
      for (uint32_t i = 0; i < num_keys; i++) {
        Value probe_val;
        EXPECT_TRUE(map.find(shuffled[i], probe_val));
      }
      // End Probe

      timer.Stop();
      avg_cuckoo_probe += timer.GetDuration();
    }
  }

  LOG_INFO("OA_HT insert: %.2lf, probe: %.2lf",
           avg_oaht_insert / (double)num_runs,
           avg_oaht_probe / (double)num_runs);
  LOG_INFO("std::unordered_map insert: %.2lf, probe: %.2lf",
           avg_map_insert / (double)num_runs, avg_map_probe / (double)num_runs);
  LOG_INFO("Cuckoo insert: %.2lf, probe: %.2lf",
           avg_cuckoo_insert / (double)num_runs,
           avg_cuckoo_probe / (double)num_runs);
}

}  // namespace test
}  // namespace peloton
<commit_msg>Modify test<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// oa_hash_table_test.cpp
//
// Identification: test/codegen/oa_hash_table_test.cpp
//
// Copyright (c) 2015-2018, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <unordered_map>

#include "common/harness.h"

#include "murmur3/MurmurHash3.h"
#include "libcuckoo/cuckoohash_map.hh"

#include "codegen/util/oa_hash_table.h"
#include "codegen/util/hash_table.h"
#include "common/timer.h"
#include "type/ephemeral_pool.h"

namespace peloton {
namespace test {

class OAHashTableTest : public PelotonTest {
 public:
  // The key and value object we store in the hash table
  struct Key {
    uint32_t k1, k2;

    Key(uint32_t _k1, uint32_t _k2) : k1(_k1), k2(_k2) {}

    bool operator==(const Key &rhs) const {
      return k1 == rhs.k1 && k2 == rhs.k2;
    }
    bool operator!=(const Key &rhs) const { return !(rhs == *this); }
  };

  struct Value {
    uint32_t v1, v2, v3, v4;
    bool operator==(const Value &rhs) const {
      return v1 == rhs.v1 && v2 == rhs.v2 && v3 == rhs.v3 && v4 == rhs.v4;
    }
    bool operator!=(const Value &rhs) const { return !(rhs == *this); }
  };

  OAHashTableTest() : ht_(sizeof(Key), sizeof(Value)) {}

  static uint64_t Hash(const Key &k) {
    static constexpr uint32_t seed = 12345;
    uint64_t h1 = MurmurHash3_x86_32(&k.k1, sizeof(uint32_t), seed);
    uint64_t h2 = MurmurHash3_x86_32(&k.k2, sizeof(uint32_t), seed);
    return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
  }

  void Insert(Key k, Value v) { GetHashTable().Insert(Hash(k), k, v); }

  codegen::util::OAHashTable &GetHashTable() { return ht_; }

 private:
  // The open-addressing hash-table instance
  codegen::util::OAHashTable ht_;
};

TEST_F(OAHashTableTest, CanInsertKeyValuePairs) {
  Value v = {3, 4, 5, 6};

  uint32_t to_insert = 50000;

  // Insert a bunch of unique keys
  for (uint32_t i = 0; i < to_insert; i++) {
    Insert({1, i}, v);
  }

  // Check validity
  EXPECT_EQ(to_insert, GetHashTable().NumEntries());
  EXPECT_EQ(to_insert, GetHashTable().NumOccupiedBuckets());

  // Insert a duplicate key-value pair
  Insert({1, 0}, v);

  // Duplicate keys don't occupy additional buckets
  EXPECT_EQ(to_insert + 1, GetHashTable().NumEntries());
  EXPECT_EQ(to_insert, GetHashTable().NumOccupiedBuckets());
}

TEST_F(OAHashTableTest, CanIterate) {
  Value v = {3, 4, 5, 6};

  uint32_t to_insert = 50000;

  // Insert a bunch of unique keys
  for (uint32_t i = 0; i < to_insert; i++) {
    Insert({1, i}, v);
  }

  auto &hashtable = GetHashTable();

  // Check that we find them all
  uint32_t i = 0;
  for (auto iter = hashtable.begin(), end = hashtable.end(); iter != end;
       ++iter) {
    i++;
  }

  EXPECT_EQ(to_insert, i);

  // Insert two duplicate keys to make sure iteration catches it
  Key key_dup{1, 0};
  Value vdup1 = {6, 5, 4, 3}, vdup2{4, 4, 4, 4};

  Insert(key_dup, vdup1);
  Insert(key_dup, vdup2);

  i = 0;
  uint32_t dup_count = 0;
  for (auto iter = hashtable.begin(), end = hashtable.end(); iter != end;
       ++iter) {
    const auto *iter_key = reinterpret_cast<const Key *>(iter.Key());
    if (*iter_key == key_dup) {
      dup_count++;
      const auto *iter_val = reinterpret_cast<const Value *>(iter.Value());
      EXPECT_TRUE(*iter_val == v || *iter_val == vdup1 || *iter_val == vdup2);
    }
    i++;
  }

  EXPECT_EQ(to_insert + 2, i);
  EXPECT_EQ(3, dup_count);
}

TEST_F(OAHashTableTest, MicroBenchmark) {
  uint32_t num_runs = 10;

  std::vector<Key> keys;
  Value v = {6, 5, 4, 3};

  std::random_device r;
  std::default_random_engine e(r());
  std::uniform_int_distribution<uint32_t> gen;

  // Create all keys
  uint32_t num_keys = 100000;
  for (uint32_t i = 0; i < num_keys; i++) {
    keys.emplace_back(gen(e), gen(e));
  }

  double avg_oaht_insert = 0.0, avg_oaht_probe = 0.0;
  double avg_lazyht_insert = 0.0, avg_lazyht_probe = 0.0;
  double avg_map_insert = 0.0, avg_map_probe = 0.0;
  double avg_cuckoo_insert = 0.0, avg_cuckoo_probe = 0.0;

  // First, bench ours ...
  {
    for (uint32_t b = 0; b < num_runs; b++) {
      codegen::util::OAHashTable ht(
          sizeof(Key), sizeof(Value),
          codegen::util::OAHashTable::kDefaultInitialSize);

      Timer<std::ratio<1, 1000>> timer;
      timer.Start();

      // Start Insert
      for (uint32_t i = 0; i < num_keys; i++) {
        ht.Insert(Hash(keys[i]), keys[i], v);
      }
      // End Insert

      timer.Stop();
      avg_oaht_insert += timer.GetDuration();

      timer.Reset();
      timer.Start();

      // Start Probe
      std::vector<Key> shuffled = keys;
      std::random_shuffle(shuffled.begin(), shuffled.end());
      for (uint32_t i = 0; i < num_keys; i++) {
        Value probe_val;
        EXPECT_TRUE(ht.Probe(Hash(shuffled[i]), shuffled[i], probe_val));
      }
      // End Probe

      timer.Stop();
      avg_oaht_probe += timer.GetDuration();
    }
  }

  // First, bench ours ...
  {
    for (uint32_t b = 0; b < num_runs; b++) {
      ::peloton::type::EphemeralPool pool;
      codegen::util::HashTable ht(pool, sizeof(Key), sizeof(Value));

      Timer<std::ratio<1, 1000>> timer;
      timer.Start();

      // Start Insert
      for (uint32_t i = 0; i < num_keys; i++) {
        ht.TypedInsertLazy(Hash(keys[i]), keys[i], v);
      }
      ht.BuildLazy();
      // End Insert

      timer.Stop();
      avg_lazyht_insert += timer.GetDuration();

      timer.Reset();
      timer.Start();

      // Start Probe
      std::vector<Key> shuffled = keys;
      std::random_shuffle(shuffled.begin(), shuffled.end());
      for (uint32_t i = 0; i < num_keys; i++) {
        Value probe_val;
        EXPECT_TRUE(ht.TypedProbe(Hash(shuffled[i]), shuffled[i], probe_val));
      }
      // End Probe

      timer.Stop();
      avg_lazyht_probe += timer.GetDuration();
    }
  }

  // Next, unordered_map ...
  {
    struct Hasher {
      size_t operator()(const Key &k) const { return Hash(k); }
    };

    for (uint32_t b = 0; b < num_runs; b++) {
      std::unordered_map<Key, Value, Hasher> ht(
          codegen::util::OAHashTable::kDefaultInitialSize);

      Timer<std::ratio<1, 1000>> timer;
      timer.Start();

      for (uint32_t i = 0; i < num_keys; i++) {
        ht.insert(std::make_pair(keys[i], v));
      }

      timer.Stop();
      avg_map_insert += timer.GetDuration();

      timer.Reset();
      timer.Start();

      // Start Probe
      std::vector<Key> shuffled = keys;
      std::random_shuffle(shuffled.begin(), shuffled.end());
      for (uint32_t i = 0; i < num_keys; i++) {
        EXPECT_NE(ht.find(shuffled[i]), ht.end());
      }
      // End Probe

      timer.Stop();
      avg_map_probe += timer.GetDuration();
    }
  }

  // Next, cuckoo map
  {
    struct Hasher {
      size_t operator()(const Key &k) const { return Hash(k); }
    };

    for (uint32_t b = 0; b < num_runs; b++) {
      cuckoohash_map<Key, Value, Hasher> map(
          codegen::util::OAHashTable::kDefaultInitialSize);

      Timer<std::ratio<1, 1000>> timer;
      timer.Start();

      for (uint32_t i = 0; i < num_keys; i++) {
        map.insert(keys[i], v);
      }

      timer.Stop();
      avg_cuckoo_insert += timer.GetDuration();

      timer.Reset();
      timer.Start();

      // Start Probe
      std::vector<Key> shuffled = keys;
      std::random_shuffle(shuffled.begin(), shuffled.end());
      for (uint32_t i = 0; i < num_keys; i++) {
        Value probe_val;
        EXPECT_TRUE(map.find(shuffled[i], probe_val));
      }
      // End Probe

      timer.Stop();
      avg_cuckoo_probe += timer.GetDuration();
    }
  }

  LOG_INFO("OA_HT insert: %.2lf, probe: %.2lf",
           avg_oaht_insert / (double)num_runs,
           avg_oaht_probe / (double)num_runs);
  LOG_INFO("Lazy HT insert: %.2lf, probe: %.2lf",
           avg_lazyht_insert / (double)num_runs,
           avg_lazyht_probe / (double)num_runs);
  LOG_INFO("std::unordered_map insert: %.2lf, probe: %.2lf",
           avg_map_insert / (double)num_runs, avg_map_probe / (double)num_runs);
  LOG_INFO("Cuckoo insert: %.2lf, probe: %.2lf",
           avg_cuckoo_insert / (double)num_runs,
           avg_cuckoo_probe / (double)num_runs);
}

}  // namespace test
}  // namespace peloton
<|endoftext|>


<commit_before>/*
 * This File is part of Davix, The IO library for HTTP based protocols
 * Copyright (C) CERN 2019
 * Author: Georgios Bitzes <georgios.bitzes@cern.ch>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
*/

#ifndef DAVIX_TEST_ASSISTED_THREAD_HPP
#define DAVIX_TEST_ASSISTED_THREAD_HPP

#include "Synchronized.hpp"

#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <vector>

//------------------------------------------------------------------------------
// C++ threads offer no easy way to stop a thread once it's started. Signalling
// "stop" to a (potentially sleeping) background thread involves a subtle dance
// involving a mutex, condition variable, and possibly an atomic.
//
// Doing this correctly for every thread is a huge pain, which this class
// tries to alleviate.
//
// How to create a thread: Just like std::thread, ie
// AssistedThread(&SomeClass::SomeFunction, this, some_int_value)
//
// The function will receive a thread assistant object as *one extra*
// parameter *at the end*, for example:
//
// void SomeClass::SomeFunction(int some_int_value, ThreadAssistant &assistant)
//
// The assistant object can then be used to check if thread termination has been
// requested, or sleep for a specified amount of time but wake up immediatelly
// the moment termination is requested.
//
// A common pattern for background threads is then:
// while(!assistant.terminationRequested()) {
//   doStuff();
//   assistant.sleep_for(std::chrono::seconds(1));
// }
//------------------------------------------------------------------------------
class AssistedThread;

//------------------------------------------------------------------------------
//! Class ThreadAssistant
//------------------------------------------------------------------------------
class ThreadAssistant {
public:
  void reset() {
    stopFlag.set(false);
    terminationCallbacks.clear();
  }

  void requestTermination() {
    std::lock_guard<std::mutex> lock(mtx);
    if(!stopFlag.get()) {
      stopFlag.set(true);
      notifier.notify_all();

      for(size_t i = 0; i < terminationCallbacks.size(); i++) {
        terminationCallbacks[i]();
      }
    }
  }

  void registerCallback(std::function<void()> callable) {
    std::lock_guard<std::mutex> lock(mtx);
    terminationCallbacks.emplace_back(std::move(callable));

    if(stopFlag.get()) {
      //------------------------------------------------------------------------
      // Careful here.. This is a race condition where thread termination has
      // already been requested, even though we're not done yet registering
      // callbacks, apparently.
      //
      // Let's simply call the callback ourselves.
      //------------------------------------------------------------------------
      (terminationCallbacks.back())();
    }
  }

  void dropCallbacks() {
    std::lock_guard<std::mutex> lock(mtx);
    terminationCallbacks.clear();
  }

  bool terminationRequested() {
    return stopFlag.get();
  }

  template<typename T>
  void wait_for(T duration) {
    std::unique_lock<std::mutex> lock(mtx);

    if(stopFlag.get()) return;
    notifier.wait_for(lock, duration);
  }

  template<typename T>
  void wait_until(T duration) {
    std::unique_lock<std::mutex> lock(mtx);

    if(stopFlag.get()) return;
    notifier.wait_until(lock, duration);
  }

  //----------------------------------------------------------------------------
  // Ok, this is a bit weird: Consider an AssistedThread which "owns" or
  // coordinates a bunch of other threads:
  //
  // void Coordinator(ThreadAssistant &assistant) {
  //   AssistedThread worker1( ... );
  //   AssistedThread worker2( ... );
  //   AssistedThread worker3( ... );
  //
  //   worker1.blockUntilThreadJoins();
  //   worker2.blockUntilThreadJoins();
  //   worker3.blockUntilThreadJoins();
  // }
  //
  // We would like that any requests to shut down Coordinator propagate to all
  // workers. Otherwise, since Coordinator blocks waiting for the workers to
  // terminate, its own early termination signal would get ignored.
  //
  // propagateTerminationSignal does just this. In the above example, call:
  // assistant.propagateTerminationSignal(worker1);
  // assistant.propagateTerminationSignal(worker2);
  // assistant.propagateTerminationSignal(worker3);
  //
  // And the moment Coordinator is asked to terminate, all registered threads
  // will, too.
  //
  // NOTE: assistant object must belong to a different thread!
  //----------------------------------------------------------------------------
  void propagateTerminationSignal(AssistedThread &thread);

private:
  // Private constructor - only AssistedThread can create such an object.
  ThreadAssistant(bool flag) {
    stopFlag.set(flag);
  }

  friend class AssistedThread;

  Synchronized<bool> stopFlag;
  std::mutex mtx;
  std::condition_variable notifier;

  std::vector<std::function<void()>> terminationCallbacks;
};

class AssistedThread {
public:
  //----------------------------------------------------------------------------
  //! null constructor, no underlying thread
  //----------------------------------------------------------------------------
  AssistedThread() : assistant(new ThreadAssistant(true)), joined(true) { }

  //----------------------------------------------------------------------------
  // universal references, perfect forwarding, variadic template
  // (C++ is intensifying)
  //----------------------------------------------------------------------------
  template<typename... Args>
  AssistedThread(Args&&... args) : assistant(new ThreadAssistant(false)), joined(false), th(std::forward<Args>(args)..., std::ref(*assistant)) {
  }

  // No assignment, no copying
  AssistedThread& operator=(const AssistedThread&) = delete;

  // Moving is allowed.
  AssistedThread(AssistedThread&& other) {
    assistant = std::move(other.assistant);
    joined = other.joined;
    th = std::move(other.th);
    other.joined = true;
  }

  template<typename... Args>
  void reset(Args&&... args) {
    join();

    assistant.get()->reset();
    joined = false;
    th = std::thread(std::forward<Args>(args)..., std::ref(*assistant));
  }

  virtual ~AssistedThread() {
    join();
  }

  void stop() {
    if(joined) return;
    assistant->requestTermination();
  }

  void join() {
    if(joined) return;
    stop();

    blockUntilThreadJoins();
  }

  // Different meaning than join, which explicitly asks the thread to
  // terminate. Here, we simply wait until the thread exits on its own.
  void blockUntilThreadJoins() {
    if(joined) return;

    th.join();
    joined = true;
  }

  void registerCallback(std::function<void()> callable) {
    assistant->registerCallback(std::move(callable));
  }

  void dropCallbacks() {
    assistant->dropCallbacks();
  }

  //----------------------------------------------------------------------------
  //! Set thread name. Useful to have in GDB traces, for example.
  //----------------------------------------------------------------------------
  void setName(const std::string &threadName) {
    pthread_setname_np(th.native_handle(), threadName.c_str());
  }

private:
  std::unique_ptr<ThreadAssistant> assistant;
  bool joined;
  std::thread th;
};

inline void ThreadAssistant::propagateTerminationSignal(AssistedThread &thread) {
  registerCallback(std::bind(&AssistedThread::stop, &thread));
}

#endif
<commit_msg>Drop AssistedThread::setName, as it is not compatible on MacOS<commit_after>/*
 * This File is part of Davix, The IO library for HTTP based protocols
 * Copyright (C) CERN 2019
 * Author: Georgios Bitzes <georgios.bitzes@cern.ch>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
*/

#ifndef DAVIX_TEST_ASSISTED_THREAD_HPP
#define DAVIX_TEST_ASSISTED_THREAD_HPP

#include "Synchronized.hpp"

#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <vector>

//------------------------------------------------------------------------------
// C++ threads offer no easy way to stop a thread once it's started. Signalling
// "stop" to a (potentially sleeping) background thread involves a subtle dance
// involving a mutex, condition variable, and possibly an atomic.
//
// Doing this correctly for every thread is a huge pain, which this class
// tries to alleviate.
//
// How to create a thread: Just like std::thread, ie
// AssistedThread(&SomeClass::SomeFunction, this, some_int_value)
//
// The function will receive a thread assistant object as *one extra*
// parameter *at the end*, for example:
//
// void SomeClass::SomeFunction(int some_int_value, ThreadAssistant &assistant)
//
// The assistant object can then be used to check if thread termination has been
// requested, or sleep for a specified amount of time but wake up immediatelly
// the moment termination is requested.
//
// A common pattern for background threads is then:
// while(!assistant.terminationRequested()) {
//   doStuff();
//   assistant.sleep_for(std::chrono::seconds(1));
// }
//------------------------------------------------------------------------------
class AssistedThread;

//------------------------------------------------------------------------------
//! Class ThreadAssistant
//------------------------------------------------------------------------------
class ThreadAssistant {
public:
  void reset() {
    stopFlag.set(false);
    terminationCallbacks.clear();
  }

  void requestTermination() {
    std::lock_guard<std::mutex> lock(mtx);
    if(!stopFlag.get()) {
      stopFlag.set(true);
      notifier.notify_all();

      for(size_t i = 0; i < terminationCallbacks.size(); i++) {
        terminationCallbacks[i]();
      }
    }
  }

  void registerCallback(std::function<void()> callable) {
    std::lock_guard<std::mutex> lock(mtx);
    terminationCallbacks.emplace_back(std::move(callable));

    if(stopFlag.get()) {
      //------------------------------------------------------------------------
      // Careful here.. This is a race condition where thread termination has
      // already been requested, even though we're not done yet registering
      // callbacks, apparently.
      //
      // Let's simply call the callback ourselves.
      //------------------------------------------------------------------------
      (terminationCallbacks.back())();
    }
  }

  void dropCallbacks() {
    std::lock_guard<std::mutex> lock(mtx);
    terminationCallbacks.clear();
  }

  bool terminationRequested() {
    return stopFlag.get();
  }

  template<typename T>
  void wait_for(T duration) {
    std::unique_lock<std::mutex> lock(mtx);

    if(stopFlag.get()) return;
    notifier.wait_for(lock, duration);
  }

  template<typename T>
  void wait_until(T duration) {
    std::unique_lock<std::mutex> lock(mtx);

    if(stopFlag.get()) return;
    notifier.wait_until(lock, duration);
  }

  //----------------------------------------------------------------------------
  // Ok, this is a bit weird: Consider an AssistedThread which "owns" or
  // coordinates a bunch of other threads:
  //
  // void Coordinator(ThreadAssistant &assistant) {
  //   AssistedThread worker1( ... );
  //   AssistedThread worker2( ... );
  //   AssistedThread worker3( ... );
  //
  //   worker1.blockUntilThreadJoins();
  //   worker2.blockUntilThreadJoins();
  //   worker3.blockUntilThreadJoins();
  // }
  //
  // We would like that any requests to shut down Coordinator propagate to all
  // workers. Otherwise, since Coordinator blocks waiting for the workers to
  // terminate, its own early termination signal would get ignored.
  //
  // propagateTerminationSignal does just this. In the above example, call:
  // assistant.propagateTerminationSignal(worker1);
  // assistant.propagateTerminationSignal(worker2);
  // assistant.propagateTerminationSignal(worker3);
  //
  // And the moment Coordinator is asked to terminate, all registered threads
  // will, too.
  //
  // NOTE: assistant object must belong to a different thread!
  //----------------------------------------------------------------------------
  void propagateTerminationSignal(AssistedThread &thread);

private:
  // Private constructor - only AssistedThread can create such an object.
  ThreadAssistant(bool flag) {
    stopFlag.set(flag);
  }

  friend class AssistedThread;

  Synchronized<bool> stopFlag;
  std::mutex mtx;
  std::condition_variable notifier;

  std::vector<std::function<void()>> terminationCallbacks;
};

class AssistedThread {
public:
  //----------------------------------------------------------------------------
  //! null constructor, no underlying thread
  //----------------------------------------------------------------------------
  AssistedThread() : assistant(new ThreadAssistant(true)), joined(true) { }

  //----------------------------------------------------------------------------
  // universal references, perfect forwarding, variadic template
  // (C++ is intensifying)
  //----------------------------------------------------------------------------
  template<typename... Args>
  AssistedThread(Args&&... args) : assistant(new ThreadAssistant(false)), joined(false), th(std::forward<Args>(args)..., std::ref(*assistant)) {
  }

  // No assignment, no copying
  AssistedThread& operator=(const AssistedThread&) = delete;

  // Moving is allowed.
  AssistedThread(AssistedThread&& other) {
    assistant = std::move(other.assistant);
    joined = other.joined;
    th = std::move(other.th);
    other.joined = true;
  }

  template<typename... Args>
  void reset(Args&&... args) {
    join();

    assistant.get()->reset();
    joined = false;
    th = std::thread(std::forward<Args>(args)..., std::ref(*assistant));
  }

  virtual ~AssistedThread() {
    join();
  }

  void stop() {
    if(joined) return;
    assistant->requestTermination();
  }

  void join() {
    if(joined) return;
    stop();

    blockUntilThreadJoins();
  }

  // Different meaning than join, which explicitly asks the thread to
  // terminate. Here, we simply wait until the thread exits on its own.
  void blockUntilThreadJoins() {
    if(joined) return;

    th.join();
    joined = true;
  }

  void registerCallback(std::function<void()> callable) {
    assistant->registerCallback(std::move(callable));
  }

  void dropCallbacks() {
    assistant->dropCallbacks();
  }

private:
  std::unique_ptr<ThreadAssistant> assistant;
  bool joined;
  std::thread th;
};

inline void ThreadAssistant::propagateTerminationSignal(AssistedThread &thread) {
  registerCallback(std::bind(&AssistedThread::stop, &thread));
}

#endif
<|endoftext|>


<commit_before>/**
 * studentCollection_class.cpp
 *
 * Author: Patrick Rummage <patrickbrummage@gmail.com>
 *
 * Objective:
 *
 */
#include <iostream>
using std::cin;
using std::cout;

struct studentRecord {
    int studentID;
    int grade;
    char* name;
};

class studentCollection {
    private:
        struct studentNode {
            studentRecord studentData;
            studentNode* next;
        };

    public:
        studentCollection();
        ~studentCollection();
        void addRecord(studentRecord newStudent);
        studentRecord recordWithNumber(int idNum);
        void removeRecord(int idNum);
        studentNode* copiedList(const studentNode* original);
        studentCollection& operator=(const studentCollection& rhs);

    private:
        studentNode* _listHead;
        void deleteList(studentNode* &listPtr);
};

studentCollection::studentCollection() {
    _listHead = NULL;
}

void studentCollection::addRecord(studentRecord newStudent) {
    studentNode* newNode = new studentNode;
    newNode->studentData = newStudent;
    newNode->next = _listHead; // previous first item
    _listHead = newNode;
}

studentRecord studentCollection::recordWithNumber(int idNum) {
    studentNode* loopPtr = _listHead;
    while (loopPtr != NULL && loopPtr->studentData.studentID != idNum) {
        loopPtr = loopPtr->next;
    }
    if (loopPtr == NULL) {
        studentRecord dummyRecord{-1,-1,"VOID"};
        return dummyRecord;
    } else {
        return loopPtr->studentData;
    }
}

void studentCollection::removeRecord(int idNum) {
    studentNode* loopPtr = _listHead;
    studentNode* previous = NULL;
    while (loopPtr != NULL && loopPtr->studentData.studentID != idNum) {
        previous = loopPtr;
        loopPtr = loopPtr->next;
    }
    if (loopPtr == NULL) { // Not found
        return;
    }
    if (previous == NULL) { // Removing first node
        _listHead = _listHead->next;
    } else { // Join nodes before and after one to be deleted
        previous->next = loopPtr->next;
    }
    delete loopPtr;
}

void studentCollection::deleteList(studentNode* &listPtr) {
    while (listPtr != NULL) {
        studentNode* temp = listPtr;
        listPtr = listPtr->next;
        delete temp;
    }
}

studentCollection::studentNode*
studentCollection::copiedList(const studentNode* original) {
    if (original == NULL) {
        return NULL;
    }
    studentNode* newList = new studentNode;
    newList->studentData = original->studentData;
    studentNode* oldLoopPtr = original->next;
    studentNode* newLoopPtr = newList;
    while(oldLoopPtr != NULL) {
        newLoopPtr->next = new studentNode;
        newLoopPtr = newLoopPtr->next;
        newLoopPtr->studentData = oldLoopPtr->studentData;
        oldLoopPtr = oldLoopPtr->next;
    }
    newLoopPtr->next = NULL;
    return newList;
}

studentCollection::~studentCollection() {
    deleteList(_listHead);
}

studentCollection& studentCollection::operator=(const studentCollection& rhs) {
    if (this != &rhs) {
        deleteList(_listHead);
        _listHead = copiedList(rhs._listHead);
    }
    return *this;
}

int main (int argc, char* argv[]) {

    return 0;
}
<commit_msg>added records within range method<commit_after>/**
 * studentCollection_class.cpp
 *
 * Author: Patrick Rummage <patrickbrummage@gmail.com>
 *
 * Objective:
 *
 */
#include <iostream>
using std::cin;
using std::cout;

struct studentRecord {
    int studentID;
    int grade;
    char* name;
};

class studentCollection {
    private:
        struct studentNode {
            studentRecord studentData;
            studentNode* next;
        };

    public:
        studentCollection();
        ~studentCollection();
        void addRecord(studentRecord newStudent);
        studentRecord recordWithNumber(int idNum);
        studentCollection recordsWithinRange(int low, int high);
        void removeRecord(int idNum);
        studentNode* copiedList(const studentNode* original);
        studentCollection& operator=(const studentCollection& rhs);

    private:
        studentNode* _listHead;
        void deleteList(studentNode* &listPtr);
};

studentCollection::studentCollection() {
    _listHead = NULL;
}

void studentCollection::addRecord(studentRecord newStudent) {
    studentNode* newNode = new studentNode;
    newNode->studentData = newStudent;
    newNode->next = _listHead; // previous first item
    _listHead = newNode;
}

studentRecord studentCollection::recordWithNumber(int idNum) {
    studentNode* loopPtr = _listHead;
    while (loopPtr != NULL && loopPtr->studentData.studentID != idNum) {
        loopPtr = loopPtr->next;
    }
    if (loopPtr == NULL) {
        studentRecord dummyRecord{-1,-1,"VOID"};
        return dummyRecord;
    } else {
        return loopPtr->studentData;
    }
}

void studentCollection::removeRecord(int idNum) {
    studentNode* loopPtr = _listHead;
    studentNode* previous = NULL;
    while (loopPtr != NULL && loopPtr->studentData.studentID != idNum) {
        previous = loopPtr;
        loopPtr = loopPtr->next;
    }
    if (loopPtr == NULL) { // Not found
        return;
    }
    if (previous == NULL) { // Removing first node
        _listHead = _listHead->next;
    } else { // Join nodes before and after one to be deleted
        previous->next = loopPtr->next;
    }
    delete loopPtr;
}

void studentCollection::deleteList(studentNode* &listPtr) {
    while (listPtr != NULL) {
        studentNode* temp = listPtr;
        listPtr = listPtr->next;
        delete temp;
    }
}

studentCollection studentCollection::recordsWithinRange(int low, int high) {
    studentCollection newCollection;
    studentNode* listPtr = _listHead;
    int studentGrade;
    while (listPtr != NULL) {
        studentGrade = listPtr->studentData.grade;
        if (studentGrade >= low && studentGrade <= high) {
           newCollection.addRecord(listPtr->studentData);
        }
        listPtr = listPtr->next;
    }
    return newCollection;
}

studentCollection::studentNode*
studentCollection::copiedList(const studentNode* original) {
    if (original == NULL) {
        return NULL;
    }
    studentNode* newList = new studentNode;
    newList->studentData = original->studentData;
    studentNode* oldLoopPtr = original->next;
    studentNode* newLoopPtr = newList;
    while(oldLoopPtr != NULL) {
        newLoopPtr->next = new studentNode;
        newLoopPtr = newLoopPtr->next;
        newLoopPtr->studentData = oldLoopPtr->studentData;
        oldLoopPtr = oldLoopPtr->next;
    }
    newLoopPtr->next = NULL;
    return newList;
}

studentCollection::~studentCollection() {
    deleteList(_listHead);
}

studentCollection& studentCollection::operator=(const studentCollection& rhs) {
    if (this != &rhs) {
        deleteList(_listHead);
        _listHead = copiedList(rhs._listHead);
    }
    return *this;
}

int main (int argc, char* argv[]) {

    return 0;
}
<|endoftext|>


<commit_before>// trace.cc
// code for trace.h

#include "trace.h"     // this module
#include "objlist.h"   // List
#include "str.h"       // string
#include "strtokp.h"   // StrtokParse
#include "nonport.h"   // getMilliseconds()

#include <fstream.h>   // ofstream

// auto-init
static bool inited = false;

// list of active tracers, initially empty
static ObjList<string> tracers;

// this will probably work; I just need a sink
ostream devNullObj;

// stream connected to /dev/null
static ostream *devNull = &devNullObj;

// initialize
static void init()
{
  if (inited) {
    return;
  }

  // there's a more efficient way to do this, but I don't care to dig
  // around and find out how
  // this leaks, and now that I'm checking for them, it's a little
  // annoying...
  //devNull = new ofstream("/dev/null");

  inited = true;
}

void traceAddSys(char const *sysName)
{
  init();

  tracers.prepend(new string(sysName));
}

void traceRemoveSys(char const *sysName)
{
  init();

  MUTATE_EACH_OBJLIST(string, tracers, mut) {
    if (mut.data()->compareTo(sysName) == 0) {
      mut.deleteIt();
      return;
    }
  }
  xfailure("traceRemoveSys: tried to remove system that isn't there");
}

bool tracingSys(char const *sysName)
{
  init();

  FOREACH_OBJLIST(string, tracers, iter) {
    if (iter.data()->compareTo(sysName) == 0) {
      return true;
    }
  }
  return false;
}

ostream &trace(char const *sysName)
{
  init();

  if (tracingSys(sysName)) {
    cout << "%%% " << sysName << ": ";
    return cout;
  }
  else {
    return *devNull;
  }
}

void trstr(char const *sysName, char const *traceString)
{
  trace(sysName) << traceString << endl;
}

ostream &traceProgress(int level)
{
  // for now, just suppress anything more than 1
  if (level == 1) {
    static long progStart = getMilliseconds();

    return trace("progress") << (getMilliseconds() - progStart) << "ms: ";
  }
  else {
    return *devNull;
  }
}

void traceAddMultiSys(char const *systemNames)
{
  StrtokParse tok(systemNames, ",");
  loopi(tok) {
    if (tok[i][0] == '-') {
      // treat a leading '-' as a signal to *remove*
      // a tracing flag, e.g. from some defaults specified
      // statically
      char const *name = tok[i]+1;
      if (tracingSys(name)) {      // be forgiving here
        traceRemoveSys(name);
      }
      else {
        cout << "Currently, `" << name << "' is not being traced.\n";
      }
    }

    else {
      // normal behavior: add things to the trace list
      traceAddSys(tok[i]);
    }
  }
}

bool traceProcessArg(int &argc, char **&argv)
{
  if (argc >= 3  &&  0==strcmp(argv[1], "-tr")) {
    traceAddMultiSys(argv[2]);
    argc -= 2;
    argv += 2;
    return true;
  }
  else {
    return false;
  }
}
<commit_msg>fixed..<commit_after>// trace.cc
// code for trace.h

#include "trace.h"     // this module
#include "objlist.h"   // List
#include "str.h"       // string
#include "strtokp.h"   // StrtokParse
#include "nonport.h"   // getMilliseconds()

#include <fstream.h>   // ofstream

// auto-init
static bool inited = false;

// list of active tracers, initially empty
static ObjList<string> tracers;

// stream connected to /dev/null
ofstream devNullObj("/dev/null");
static ostream *devNull = &devNullObj;

// initialize
static void init()
{
  if (inited) {
    return;
  }

  // there's a more efficient way to do this, but I don't care to dig
  // around and find out how
  // this leaks, and now that I'm checking for them, it's a little
  // annoying...
  //devNull = new ofstream("/dev/null");

  inited = true;
}

void traceAddSys(char const *sysName)
{
  init();

  tracers.prepend(new string(sysName));
}

void traceRemoveSys(char const *sysName)
{
  init();

  MUTATE_EACH_OBJLIST(string, tracers, mut) {
    if (mut.data()->compareTo(sysName) == 0) {
      mut.deleteIt();
      return;
    }
  }
  xfailure("traceRemoveSys: tried to remove system that isn't there");
}

bool tracingSys(char const *sysName)
{
  init();

  FOREACH_OBJLIST(string, tracers, iter) {
    if (iter.data()->compareTo(sysName) == 0) {
      return true;
    }
  }
  return false;
}

ostream &trace(char const *sysName)
{
  init();

  if (tracingSys(sysName)) {
    cout << "%%% " << sysName << ": ";
    return cout;
  }
  else {
    return *devNull;
  }
}

void trstr(char const *sysName, char const *traceString)
{
  trace(sysName) << traceString << endl;
}

ostream &traceProgress(int level)
{
  // for now, just suppress anything more than 1
  if (level == 1) {
    static long progStart = getMilliseconds();

    return trace("progress") << (getMilliseconds() - progStart) << "ms: ";
  }
  else {
    return *devNull;
  }
}

void traceAddMultiSys(char const *systemNames)
{
  StrtokParse tok(systemNames, ",");
  loopi(tok) {
    if (tok[i][0] == '-') {
      // treat a leading '-' as a signal to *remove*
      // a tracing flag, e.g. from some defaults specified
      // statically
      char const *name = tok[i]+1;
      if (tracingSys(name)) {      // be forgiving here
        traceRemoveSys(name);
      }
      else {
        cout << "Currently, `" << name << "' is not being traced.\n";
      }
    }

    else {
      // normal behavior: add things to the trace list
      traceAddSys(tok[i]);
    }
  }
}

bool traceProcessArg(int &argc, char **&argv)
{
  if (argc >= 3  &&  0==strcmp(argv[1], "-tr")) {
    traceAddMultiSys(argv[2]);
    argc -= 2;
    argv += 2;
    return true;
  }
  else {
    return false;
  }
}
<|endoftext|>


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

#include "chrome/renderer/net/net_error_helper.h"

#include <string>

#include "base/command_line.h"
#include "base/i18n/rtl.h"
#include "base/json/json_writer.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/localized_error.h"
#include "chrome/common/render_messages.h"
#include "chrome/grit/renderer_resources.h"
#include "chrome/renderer/net/net_error_page_controller.h"
#include "components/error_page/common/error_page_params.h"
#include "components/error_page/common/net_error_info.h"
#include "content/public/common/content_client.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/resource_fetcher.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/jstemplate_builder.h"
#include "url/gurl.h"

using base::JSONWriter;
using chrome_common_net::DnsProbeStatus;
using chrome_common_net::DnsProbeStatusToString;
using content::DocumentState;
using content::RenderFrame;
using content::RenderFrameObserver;
using content::RenderThread;
using content::kUnreachableWebDataURL;
using error_page::ErrorPageParams;
using error_page::NetErrorHelperCore;

namespace {

// Number of seconds to wait for the navigation correction service to return
// suggestions.  If it takes too long, just use the local error page.
static const int kNavigationCorrectionFetchTimeoutSec = 3;

NetErrorHelperCore::PageType GetLoadingPageType(const blink::WebFrame* frame) {
  GURL url = frame->provisionalDataSource()->request().url();
  if (!url.is_valid() || url.spec() != kUnreachableWebDataURL)
    return NetErrorHelperCore::NON_ERROR_PAGE;
  return NetErrorHelperCore::ERROR_PAGE;
}

NetErrorHelperCore::FrameType GetFrameType(const blink::WebFrame* frame) {
  if (!frame->parent())
    return NetErrorHelperCore::MAIN_FRAME;
  return NetErrorHelperCore::SUB_FRAME;
}

}  // namespace

NetErrorHelper::NetErrorHelper(RenderFrame* render_frame)
    : RenderFrameObserver(render_frame),
      content::RenderFrameObserverTracker<NetErrorHelper>(render_frame) {
  RenderThread::Get()->AddObserver(this);
  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  bool auto_reload_enabled =
      command_line->HasSwitch(switches::kEnableOfflineAutoReload);
  bool auto_reload_visible_only =
      command_line->HasSwitch(switches::kEnableOfflineAutoReloadVisibleOnly);
  core_.reset(new NetErrorHelperCore(this,
                                     auto_reload_enabled,
                                     auto_reload_visible_only,
                                     !render_frame->IsHidden()));
}

NetErrorHelper::~NetErrorHelper() {
  RenderThread::Get()->RemoveObserver(this);
}

void NetErrorHelper::ReloadButtonPressed() {
  core_->ExecuteButtonPress(NetErrorHelperCore::RELOAD_BUTTON);
}

void NetErrorHelper::ShowSavedCopyButtonPressed() {
  core_->ExecuteButtonPress(NetErrorHelperCore::SHOW_SAVED_COPY_BUTTON);
}

void NetErrorHelper::MoreButtonPressed() {
  core_->ExecuteButtonPress(NetErrorHelperCore::MORE_BUTTON);
}

void NetErrorHelper::TrackActivatedEasterEgg() {
  core_->ExecuteButtonPress(NetErrorHelperCore::EASTER_EGG);
}

void NetErrorHelper::DidStartProvisionalLoad() {
  blink::WebFrame* frame = render_frame()->GetWebFrame();
  core_->OnStartLoad(GetFrameType(frame), GetLoadingPageType(frame));
}

void NetErrorHelper::DidCommitProvisionalLoad(bool is_new_navigation,
                                              bool is_same_page_navigation) {
  blink::WebFrame* frame = render_frame()->GetWebFrame();
  core_->OnCommitLoad(GetFrameType(frame), frame->document().url());
}

void NetErrorHelper::DidFinishLoad() {
  blink::WebFrame* frame = render_frame()->GetWebFrame();
  core_->OnFinishLoad(GetFrameType(frame));
}

void NetErrorHelper::OnStop() {
  core_->OnStop();
}

void NetErrorHelper::WasShown() {
  core_->OnWasShown();
}

void NetErrorHelper::WasHidden() {
  core_->OnWasHidden();
}

bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;

  IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetNavigationCorrectionInfo,
                        OnSetNavigationCorrectionInfo);
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

void NetErrorHelper::NetworkStateChanged(bool enabled) {
  core_->NetworkStateChanged(enabled);
}

void NetErrorHelper::GetErrorHTML(
    blink::WebFrame* frame,
    const blink::WebURLError& error,
    bool is_failed_post,
    std::string* error_html) {
  core_->GetErrorHTML(GetFrameType(frame), error, is_failed_post, error_html);
}

bool NetErrorHelper::ShouldSuppressErrorPage(blink::WebFrame* frame,
                                             const GURL& url) {
  return core_->ShouldSuppressErrorPage(GetFrameType(frame), url);
}

void NetErrorHelper::TrackClick(int tracking_id) {
  core_->TrackClick(tracking_id);
}

void NetErrorHelper::GenerateLocalizedErrorPage(
    const blink::WebURLError& error,
    bool is_failed_post,
    scoped_ptr<ErrorPageParams> params,
    bool* reload_button_shown,
    bool* show_saved_copy_button_shown,
    std::string* error_html) const {
  error_html->clear();

  int resource_id = IDR_NET_ERROR_HTML;
  const base::StringPiece template_html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id));
  if (template_html.empty()) {
    NOTREACHED() << "unable to load template.";
  } else {
    base::DictionaryValue error_strings;
    LocalizedError::GetStrings(error.reason, error.domain.utf8(),
                               error.unreachableURL, is_failed_post,
                               error.staleCopyInCache,
                               RenderThread::Get()->GetLocale(),
                               render_frame()->GetRenderView()->
                                   GetAcceptLanguages(),
                               params.Pass(), &error_strings);
    *reload_button_shown = error_strings.Get("reloadButton", NULL);
    *show_saved_copy_button_shown =
        error_strings.Get("showSavedCopyButton", NULL);

    // "t" is the id of the template's root node.
    *error_html = webui::GetTemplatesHtml(template_html, &error_strings, "t");
  }
}

void NetErrorHelper::LoadErrorPageInMainFrame(const std::string& html,
                                              const GURL& failed_url) {
  blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
  if (!web_view)
    return;
  blink::WebFrame* frame = web_view->mainFrame();
  frame->loadHTMLString(html, GURL(kUnreachableWebDataURL), failed_url, true);
}

void NetErrorHelper::EnablePageHelperFunctions() {
  NetErrorPageController::Install(render_frame());
}

void NetErrorHelper::UpdateErrorPage(const blink::WebURLError& error,
                                     bool is_failed_post) {
  base::DictionaryValue error_strings;
  LocalizedError::GetStrings(error.reason,
                             error.domain.utf8(),
                             error.unreachableURL,
                             is_failed_post,
                             error.staleCopyInCache,
                             RenderThread::Get()->GetLocale(),
                             render_frame()->GetRenderView()->
                                 GetAcceptLanguages(),
                             scoped_ptr<ErrorPageParams>(),
                             &error_strings);

  std::string json;
  JSONWriter::Write(error_strings, &json);

  std::string js = "if (window.updateForDnsProbe) "
                   "updateForDnsProbe(" + json + ");";
  base::string16 js16;
  if (!base::UTF8ToUTF16(js.c_str(), js.length(), &js16)) {
    NOTREACHED();
    return;
  }

  render_frame()->ExecuteJavaScript(js16);
}

void NetErrorHelper::FetchNavigationCorrections(
    const GURL& navigation_correction_url,
    const std::string& navigation_correction_request_body) {
  DCHECK(!correction_fetcher_.get());

  blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
  if (!web_view)
    return;
  blink::WebFrame* frame = web_view->mainFrame();

  correction_fetcher_.reset(
      content::ResourceFetcher::Create(navigation_correction_url));
  correction_fetcher_->SetMethod("POST");
  correction_fetcher_->SetBody(navigation_correction_request_body);
  correction_fetcher_->SetHeader("Content-Type", "application/json");

  correction_fetcher_->Start(
      frame,
      blink::WebURLRequest::RequestContextInternal,
      blink::WebURLRequest::FrameTypeTopLevel,
      content::ResourceFetcher::PLATFORM_LOADER,
      base::Bind(&NetErrorHelper::OnNavigationCorrectionsFetched,
                 base::Unretained(this)));

  correction_fetcher_->SetTimeout(
      base::TimeDelta::FromSeconds(kNavigationCorrectionFetchTimeoutSec));
}

void NetErrorHelper::CancelFetchNavigationCorrections() {
  correction_fetcher_.reset();
}

void NetErrorHelper::SendTrackingRequest(
    const GURL& tracking_url,
    const std::string& tracking_request_body) {
  blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
  if (!web_view)
    return;
  blink::WebFrame* frame = web_view->mainFrame();

  // If there's already a pending tracking request, this will cancel it.
  tracking_fetcher_.reset(content::ResourceFetcher::Create(tracking_url));
  tracking_fetcher_->SetMethod("POST");
  tracking_fetcher_->SetBody(tracking_request_body);
  tracking_fetcher_->SetHeader("Content-Type", "application/json");

  tracking_fetcher_->Start(
      frame,
      blink::WebURLRequest::RequestContextInternal,
      blink::WebURLRequest::FrameTypeTopLevel,
      content::ResourceFetcher::PLATFORM_LOADER,
      base::Bind(&NetErrorHelper::OnTrackingRequestComplete,
                 base::Unretained(this)));
}

void NetErrorHelper::ReloadPage() {
  render_frame()->GetWebFrame()->reload(false);
}

void NetErrorHelper::LoadPageFromCache(const GURL& page_url) {
  blink::WebFrame* web_frame = render_frame()->GetWebFrame();
  DCHECK(!base::EqualsASCII(web_frame->dataSource()->request().httpMethod(),
                            "POST"));

  blink::WebURLRequest request(page_url);
  request.setCachePolicy(blink::WebURLRequest::ReturnCacheDataDontLoad);

  web_frame->loadRequest(request);
}

void NetErrorHelper::OnNetErrorInfo(int status_num) {
  DCHECK(status_num >= 0 && status_num < chrome_common_net::DNS_PROBE_MAX);

  DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num);

  core_->OnNetErrorInfo(static_cast<DnsProbeStatus>(status_num));
}

void NetErrorHelper::OnSetNavigationCorrectionInfo(
    const GURL& navigation_correction_url,
    const std::string& language,
    const std::string& country_code,
    const std::string& api_key,
    const GURL& search_url) {
  core_->OnSetNavigationCorrectionInfo(navigation_correction_url, language,
                                      country_code, api_key, search_url);
}

void NetErrorHelper::OnNavigationCorrectionsFetched(
    const blink::WebURLResponse& response,
    const std::string& data) {
  // The fetcher may only be deleted after |data| is passed to |core_|.  Move
  // it to a temporary to prevent any potential re-entrancy issues.
  scoped_ptr<content::ResourceFetcher> fetcher(
      correction_fetcher_.release());
  bool success = (!response.isNull() && response.httpStatusCode() == 200);
  core_->OnNavigationCorrectionsFetched(
      success ? data : "",
      render_frame()->GetRenderView()->GetAcceptLanguages(),
      base::i18n::IsRTL());
}

void NetErrorHelper::OnTrackingRequestComplete(
    const blink::WebURLResponse& response,
    const std::string& data) {
  tracking_fetcher_.reset();
}
<commit_msg>Change FetchNavigationCorrections FrameType to FrameTypeNone<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/renderer/net/net_error_helper.h"

#include <string>

#include "base/command_line.h"
#include "base/i18n/rtl.h"
#include "base/json/json_writer.h"
#include "base/metrics/histogram.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/localized_error.h"
#include "chrome/common/render_messages.h"
#include "chrome/grit/renderer_resources.h"
#include "chrome/renderer/net/net_error_page_controller.h"
#include "components/error_page/common/error_page_params.h"
#include "components/error_page/common/net_error_info.h"
#include "content/public/common/content_client.h"
#include "content/public/common/url_constants.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/resource_fetcher.h"
#include "ipc/ipc_message.h"
#include "ipc/ipc_message_macros.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/jstemplate_builder.h"
#include "url/gurl.h"

using base::JSONWriter;
using chrome_common_net::DnsProbeStatus;
using chrome_common_net::DnsProbeStatusToString;
using content::DocumentState;
using content::RenderFrame;
using content::RenderFrameObserver;
using content::RenderThread;
using content::kUnreachableWebDataURL;
using error_page::ErrorPageParams;
using error_page::NetErrorHelperCore;

namespace {

// Number of seconds to wait for the navigation correction service to return
// suggestions.  If it takes too long, just use the local error page.
static const int kNavigationCorrectionFetchTimeoutSec = 3;

NetErrorHelperCore::PageType GetLoadingPageType(const blink::WebFrame* frame) {
  GURL url = frame->provisionalDataSource()->request().url();
  if (!url.is_valid() || url.spec() != kUnreachableWebDataURL)
    return NetErrorHelperCore::NON_ERROR_PAGE;
  return NetErrorHelperCore::ERROR_PAGE;
}

NetErrorHelperCore::FrameType GetFrameType(const blink::WebFrame* frame) {
  if (!frame->parent())
    return NetErrorHelperCore::MAIN_FRAME;
  return NetErrorHelperCore::SUB_FRAME;
}

}  // namespace

NetErrorHelper::NetErrorHelper(RenderFrame* render_frame)
    : RenderFrameObserver(render_frame),
      content::RenderFrameObserverTracker<NetErrorHelper>(render_frame) {
  RenderThread::Get()->AddObserver(this);
  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  bool auto_reload_enabled =
      command_line->HasSwitch(switches::kEnableOfflineAutoReload);
  bool auto_reload_visible_only =
      command_line->HasSwitch(switches::kEnableOfflineAutoReloadVisibleOnly);
  core_.reset(new NetErrorHelperCore(this,
                                     auto_reload_enabled,
                                     auto_reload_visible_only,
                                     !render_frame->IsHidden()));
}

NetErrorHelper::~NetErrorHelper() {
  RenderThread::Get()->RemoveObserver(this);
}

void NetErrorHelper::ReloadButtonPressed() {
  core_->ExecuteButtonPress(NetErrorHelperCore::RELOAD_BUTTON);
}

void NetErrorHelper::ShowSavedCopyButtonPressed() {
  core_->ExecuteButtonPress(NetErrorHelperCore::SHOW_SAVED_COPY_BUTTON);
}

void NetErrorHelper::MoreButtonPressed() {
  core_->ExecuteButtonPress(NetErrorHelperCore::MORE_BUTTON);
}

void NetErrorHelper::TrackActivatedEasterEgg() {
  core_->ExecuteButtonPress(NetErrorHelperCore::EASTER_EGG);
}

void NetErrorHelper::DidStartProvisionalLoad() {
  blink::WebFrame* frame = render_frame()->GetWebFrame();
  core_->OnStartLoad(GetFrameType(frame), GetLoadingPageType(frame));
}

void NetErrorHelper::DidCommitProvisionalLoad(bool is_new_navigation,
                                              bool is_same_page_navigation) {
  blink::WebFrame* frame = render_frame()->GetWebFrame();
  core_->OnCommitLoad(GetFrameType(frame), frame->document().url());
}

void NetErrorHelper::DidFinishLoad() {
  blink::WebFrame* frame = render_frame()->GetWebFrame();
  core_->OnFinishLoad(GetFrameType(frame));
}

void NetErrorHelper::OnStop() {
  core_->OnStop();
}

void NetErrorHelper::WasShown() {
  core_->OnWasShown();
}

void NetErrorHelper::WasHidden() {
  core_->OnWasHidden();
}

bool NetErrorHelper::OnMessageReceived(const IPC::Message& message) {
  bool handled = true;

  IPC_BEGIN_MESSAGE_MAP(NetErrorHelper, message)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_NetErrorInfo, OnNetErrorInfo)
    IPC_MESSAGE_HANDLER(ChromeViewMsg_SetNavigationCorrectionInfo,
                        OnSetNavigationCorrectionInfo);
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()

  return handled;
}

void NetErrorHelper::NetworkStateChanged(bool enabled) {
  core_->NetworkStateChanged(enabled);
}

void NetErrorHelper::GetErrorHTML(
    blink::WebFrame* frame,
    const blink::WebURLError& error,
    bool is_failed_post,
    std::string* error_html) {
  core_->GetErrorHTML(GetFrameType(frame), error, is_failed_post, error_html);
}

bool NetErrorHelper::ShouldSuppressErrorPage(blink::WebFrame* frame,
                                             const GURL& url) {
  return core_->ShouldSuppressErrorPage(GetFrameType(frame), url);
}

void NetErrorHelper::TrackClick(int tracking_id) {
  core_->TrackClick(tracking_id);
}

void NetErrorHelper::GenerateLocalizedErrorPage(
    const blink::WebURLError& error,
    bool is_failed_post,
    scoped_ptr<ErrorPageParams> params,
    bool* reload_button_shown,
    bool* show_saved_copy_button_shown,
    std::string* error_html) const {
  error_html->clear();

  int resource_id = IDR_NET_ERROR_HTML;
  const base::StringPiece template_html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id));
  if (template_html.empty()) {
    NOTREACHED() << "unable to load template.";
  } else {
    base::DictionaryValue error_strings;
    LocalizedError::GetStrings(error.reason, error.domain.utf8(),
                               error.unreachableURL, is_failed_post,
                               error.staleCopyInCache,
                               RenderThread::Get()->GetLocale(),
                               render_frame()->GetRenderView()->
                                   GetAcceptLanguages(),
                               params.Pass(), &error_strings);
    *reload_button_shown = error_strings.Get("reloadButton", NULL);
    *show_saved_copy_button_shown =
        error_strings.Get("showSavedCopyButton", NULL);

    // "t" is the id of the template's root node.
    *error_html = webui::GetTemplatesHtml(template_html, &error_strings, "t");
  }
}

void NetErrorHelper::LoadErrorPageInMainFrame(const std::string& html,
                                              const GURL& failed_url) {
  blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
  if (!web_view)
    return;
  blink::WebFrame* frame = web_view->mainFrame();
  frame->loadHTMLString(html, GURL(kUnreachableWebDataURL), failed_url, true);
}

void NetErrorHelper::EnablePageHelperFunctions() {
  NetErrorPageController::Install(render_frame());
}

void NetErrorHelper::UpdateErrorPage(const blink::WebURLError& error,
                                     bool is_failed_post) {
  base::DictionaryValue error_strings;
  LocalizedError::GetStrings(error.reason,
                             error.domain.utf8(),
                             error.unreachableURL,
                             is_failed_post,
                             error.staleCopyInCache,
                             RenderThread::Get()->GetLocale(),
                             render_frame()->GetRenderView()->
                                 GetAcceptLanguages(),
                             scoped_ptr<ErrorPageParams>(),
                             &error_strings);

  std::string json;
  JSONWriter::Write(error_strings, &json);

  std::string js = "if (window.updateForDnsProbe) "
                   "updateForDnsProbe(" + json + ");";
  base::string16 js16;
  if (!base::UTF8ToUTF16(js.c_str(), js.length(), &js16)) {
    NOTREACHED();
    return;
  }

  render_frame()->ExecuteJavaScript(js16);
}

void NetErrorHelper::FetchNavigationCorrections(
    const GURL& navigation_correction_url,
    const std::string& navigation_correction_request_body) {
  DCHECK(!correction_fetcher_.get());

  blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
  if (!web_view)
    return;
  blink::WebFrame* frame = web_view->mainFrame();

  correction_fetcher_.reset(
      content::ResourceFetcher::Create(navigation_correction_url));
  correction_fetcher_->SetMethod("POST");
  correction_fetcher_->SetBody(navigation_correction_request_body);
  correction_fetcher_->SetHeader("Content-Type", "application/json");

  correction_fetcher_->Start(
      frame,
      blink::WebURLRequest::RequestContextInternal,
      blink::WebURLRequest::FrameTypeNone,
      content::ResourceFetcher::PLATFORM_LOADER,
      base::Bind(&NetErrorHelper::OnNavigationCorrectionsFetched,
                 base::Unretained(this)));

  correction_fetcher_->SetTimeout(
      base::TimeDelta::FromSeconds(kNavigationCorrectionFetchTimeoutSec));
}

void NetErrorHelper::CancelFetchNavigationCorrections() {
  correction_fetcher_.reset();
}

void NetErrorHelper::SendTrackingRequest(
    const GURL& tracking_url,
    const std::string& tracking_request_body) {
  blink::WebView* web_view = render_frame()->GetRenderView()->GetWebView();
  if (!web_view)
    return;
  blink::WebFrame* frame = web_view->mainFrame();

  // If there's already a pending tracking request, this will cancel it.
  tracking_fetcher_.reset(content::ResourceFetcher::Create(tracking_url));
  tracking_fetcher_->SetMethod("POST");
  tracking_fetcher_->SetBody(tracking_request_body);
  tracking_fetcher_->SetHeader("Content-Type", "application/json");

  tracking_fetcher_->Start(
      frame,
      blink::WebURLRequest::RequestContextInternal,
      blink::WebURLRequest::FrameTypeTopLevel,
      content::ResourceFetcher::PLATFORM_LOADER,
      base::Bind(&NetErrorHelper::OnTrackingRequestComplete,
                 base::Unretained(this)));
}

void NetErrorHelper::ReloadPage() {
  render_frame()->GetWebFrame()->reload(false);
}

void NetErrorHelper::LoadPageFromCache(const GURL& page_url) {
  blink::WebFrame* web_frame = render_frame()->GetWebFrame();
  DCHECK(!base::EqualsASCII(web_frame->dataSource()->request().httpMethod(),
                            "POST"));

  blink::WebURLRequest request(page_url);
  request.setCachePolicy(blink::WebURLRequest::ReturnCacheDataDontLoad);

  web_frame->loadRequest(request);
}

void NetErrorHelper::OnNetErrorInfo(int status_num) {
  DCHECK(status_num >= 0 && status_num < chrome_common_net::DNS_PROBE_MAX);

  DVLOG(1) << "Received status " << DnsProbeStatusToString(status_num);

  core_->OnNetErrorInfo(static_cast<DnsProbeStatus>(status_num));
}

void NetErrorHelper::OnSetNavigationCorrectionInfo(
    const GURL& navigation_correction_url,
    const std::string& language,
    const std::string& country_code,
    const std::string& api_key,
    const GURL& search_url) {
  core_->OnSetNavigationCorrectionInfo(navigation_correction_url, language,
                                      country_code, api_key, search_url);
}

void NetErrorHelper::OnNavigationCorrectionsFetched(
    const blink::WebURLResponse& response,
    const std::string& data) {
  // The fetcher may only be deleted after |data| is passed to |core_|.  Move
  // it to a temporary to prevent any potential re-entrancy issues.
  scoped_ptr<content::ResourceFetcher> fetcher(
      correction_fetcher_.release());
  bool success = (!response.isNull() && response.httpStatusCode() == 200);
  core_->OnNavigationCorrectionsFetched(
      success ? data : "",
      render_frame()->GetRenderView()->GetAcceptLanguages(),
      base::i18n::IsRTL());
}

void NetErrorHelper::OnTrackingRequestComplete(
    const blink::WebURLResponse& response,
    const std::string& data) {
  tracking_fetcher_.reset();
}
<|endoftext|>


<commit_before><commit_msg>Fixed 'singleton' behavior of filebrowser<commit_after><|endoftext|>


<commit_before>## Note that this file is not auto generated, it is what generates the
## elog-gen.hpp file
// This file was autogenerated.  Do not edit!
// See elog-gen.py for more details
#pragma once

#include <string>
#include <tuple>
#include <type_traits>
#include <sdbusplus/exception.hpp>
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog.hpp>

<% exceptions = [] %>\
% for name in errors:
<%
    if("example.xyz.openbmc_project" not in name):
        exception = name.replace(".", "::")
        exception = "sdbusplus::" + exception
        index = exception.rfind("::")
        exception = exception[:index] + "::Error::" + exception[index+2:]
        exceptions.append(exception)
%>\
% endfor
% for exception in set(exceptions):
<%
    ns = exception.split("::")
    exception_name = ns[-1]
    ns = ns[:-1]
%>\
    % for s in ns:
namespace ${s}
{
    % endfor
    struct ${exception_name};
    % for s in reversed(ns):
} // namespace ${s}
    % endfor

% endfor

namespace phosphor
{

namespace logging
{

    % for index, name in enumerate(errors):
<%
    ## Ex: name: xyz.openbmc_project.Error.Callout.Device
    namespaces = name.split('.')
    ## classname is the last name item (Device)
    classname = namespaces[-1]
    ## namespaces are all the name items except the last one
    namespaces = namespaces[:-1]
%>\
    % for s in namespaces:
namespace ${s}
{
    % endfor
namespace _${classname}
{
<%
    meta_list = []
    if(name in meta):
        meta_list = meta[name]
%>\

    % for b in meta_list:
struct ${b}
{
    /*
     * We can't use -fsanitize=undefined if we declare a
     * 'static constexpr auto str' member, so don't. Instead, open-code the
     * mako template lookups.
     */
    static constexpr auto str_short = "${meta_data[b]['str_short']}";
    using type = std::tuple<std::decay_t<decltype("${meta_data[b]['str']}")>,${meta_data[b]['type']}>;
    explicit constexpr ${b}(${meta_data[b]['type']} a) : _entry(entry("${meta_data[b]['str']}", a)) {};
    type _entry;
};
    % endfor

}  // namespace _${classname}
<%
    example_yaml = False
    if("example.xyz.openbmc_project" in name):
        example_yaml = True
%>\
<%
    meta_string = ""
    if(meta_list):
        meta_string = ', '.join(meta_list)
    parent_meta = []

    parent = parents[name]
    while parent:
        tmpparent = parent.split('.')
        ## Name is the last item
        parent_name = tmpparent[-1]
        ## namespaces are all the name items except the last one
        parent_namespace = '::'.join(tmpparent[:-1])
        parent_meta += [parent_namespace + "::" + parent_name + "::" +
                        p for p in meta[parent]]
        parent_meta_short = ', '.join(meta[parent])
        # The parent may have empty meta,
        # so only add parent meta when it exists
        if (parent_meta_short):
            if(meta_string):
                meta_string = meta_string + ", " + parent_meta_short
            else:
                meta_string = parent_meta_short
        parent = parents[parent]

    if example_yaml:
        error_type = classname + " : public sdbusplus::exception_t"
    else:
        error_type = classname
%>
struct ${error_type}
{
    % if example_yaml:
    static constexpr auto errName = "${name}";
    static constexpr auto errDesc = "${error_msg[name]}";
    % endif
    static constexpr auto L = level::${error_lvl[name]};
    % for b in meta_list:
    using ${b} = _${classname}::${b};
    % endfor
    % for b in parent_meta:
    using ${b.split("::").pop()} = ${b};
    % endfor
    using metadata_types = std::tuple<${meta_string}>;

    % if example_yaml:
    const char* name() const noexcept
    {
        return errName;
    }

    const char* description() const noexcept
    {
        return errDesc;
    }

    const char* what() const noexcept
    {
        return errName;
    }
    % endif
};

% for s in reversed(namespaces):
} // namespace ${s}
% endfor

<%
    sdbusplus_name = name
    if not example_yaml :
        sdbusplus_name = "sdbusplus." + sdbusplus_name
        pos = sdbusplus_name.rfind(".")
        sdbusplus_name = (sdbusplus_name[:pos] + ".Error." +
                          sdbusplus_name[pos+1:])
    sdbusplus_type = sdbusplus_name.replace(".", "::")
    phosphor_type = sdbusplus_type
    if not example_yaml :
        phosphor_type = sdbusplus_type.replace("sdbusplus::", "")
        phosphor_type = phosphor_type.replace("Error::", "")
%>\

% if sdbusplus_type != phosphor_type:
namespace details
{

template <>
struct map_exception_type<${sdbusplus_type}>
{
    using type = ${phosphor_type};
};

}
%endif

    % endfor

} // namespace logging

} // namespace phosphor
<commit_msg>exception: define get_errno for example types<commit_after>## Note that this file is not auto generated, it is what generates the
## elog-gen.hpp file
// This file was autogenerated.  Do not edit!
// See elog-gen.py for more details
#pragma once

#include <string>
#include <tuple>
#include <type_traits>
#include <sdbusplus/exception.hpp>
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog.hpp>

<% exceptions = [] %>\
% for name in errors:
<%
    if("example.xyz.openbmc_project" not in name):
        exception = name.replace(".", "::")
        exception = "sdbusplus::" + exception
        index = exception.rfind("::")
        exception = exception[:index] + "::Error::" + exception[index+2:]
        exceptions.append(exception)
%>\
% endfor
% for exception in set(exceptions):
<%
    ns = exception.split("::")
    exception_name = ns[-1]
    ns = ns[:-1]
%>\
    % for s in ns:
namespace ${s}
{
    % endfor
    struct ${exception_name};
    % for s in reversed(ns):
} // namespace ${s}
    % endfor

% endfor

namespace phosphor
{

namespace logging
{

    % for index, name in enumerate(errors):
<%
    ## Ex: name: xyz.openbmc_project.Error.Callout.Device
    namespaces = name.split('.')
    ## classname is the last name item (Device)
    classname = namespaces[-1]
    ## namespaces are all the name items except the last one
    namespaces = namespaces[:-1]
%>\
    % for s in namespaces:
namespace ${s}
{
    % endfor
namespace _${classname}
{
<%
    meta_list = []
    if(name in meta):
        meta_list = meta[name]
%>\

    % for b in meta_list:
struct ${b}
{
    /*
     * We can't use -fsanitize=undefined if we declare a
     * 'static constexpr auto str' member, so don't. Instead, open-code the
     * mako template lookups.
     */
    static constexpr auto str_short = "${meta_data[b]['str_short']}";
    using type = std::tuple<std::decay_t<decltype("${meta_data[b]['str']}")>,${meta_data[b]['type']}>;
    explicit constexpr ${b}(${meta_data[b]['type']} a) : _entry(entry("${meta_data[b]['str']}", a)) {};
    type _entry;
};
    % endfor

}  // namespace _${classname}
<%
    example_yaml = False
    if("example.xyz.openbmc_project" in name):
        example_yaml = True
%>\
<%
    meta_string = ""
    if(meta_list):
        meta_string = ', '.join(meta_list)
    parent_meta = []

    parent = parents[name]
    while parent:
        tmpparent = parent.split('.')
        ## Name is the last item
        parent_name = tmpparent[-1]
        ## namespaces are all the name items except the last one
        parent_namespace = '::'.join(tmpparent[:-1])
        parent_meta += [parent_namespace + "::" + parent_name + "::" +
                        p for p in meta[parent]]
        parent_meta_short = ', '.join(meta[parent])
        # The parent may have empty meta,
        # so only add parent meta when it exists
        if (parent_meta_short):
            if(meta_string):
                meta_string = meta_string + ", " + parent_meta_short
            else:
                meta_string = parent_meta_short
        parent = parents[parent]

    if example_yaml:
        error_type = classname + " : public sdbusplus::exception_t"
    else:
        error_type = classname
%>
struct ${error_type}
{
    % if example_yaml:
    static constexpr auto errName = "${name}";
    static constexpr auto errDesc = "${error_msg[name]}";
    % endif
    static constexpr auto L = level::${error_lvl[name]};
    % for b in meta_list:
    using ${b} = _${classname}::${b};
    % endfor
    % for b in parent_meta:
    using ${b.split("::").pop()} = ${b};
    % endfor
    using metadata_types = std::tuple<${meta_string}>;

    % if example_yaml:
    const char* name() const noexcept override
    {
        return errName;
    }

    const char* description() const noexcept override
    {
        return errDesc;
    }

    const char* what() const noexcept override
    {
        return errName;
    }

    int get_errno() const noexcept override
    {
        return EIO;
    }
    % endif
};

% for s in reversed(namespaces):
} // namespace ${s}
% endfor

<%
    sdbusplus_name = name
    if not example_yaml :
        sdbusplus_name = "sdbusplus." + sdbusplus_name
        pos = sdbusplus_name.rfind(".")
        sdbusplus_name = (sdbusplus_name[:pos] + ".Error." +
                          sdbusplus_name[pos+1:])
    sdbusplus_type = sdbusplus_name.replace(".", "::")
    phosphor_type = sdbusplus_type
    if not example_yaml :
        phosphor_type = sdbusplus_type.replace("sdbusplus::", "")
        phosphor_type = phosphor_type.replace("Error::", "")
%>\

% if sdbusplus_type != phosphor_type:
namespace details
{

template <>
struct map_exception_type<${sdbusplus_type}>
{
    using type = ${phosphor_type};
};

}
%endif

    % endfor

} // namespace logging

} // namespace phosphor
<|endoftext|>


<commit_before>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TRAVERSAL_ALGORITHM_050324_HPP
#define TRAVERSAL_ALGORITHM_050324_HPP

#include <vector>
#include <set>

#include <libtorrent/kademlia/node_id.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/logging.hpp>

#include <boost/noncopyable.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/pool/pool.hpp>

namespace libtorrent { struct dht_lookup; }
namespace libtorrent { namespace dht
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DECLARE_LOG(traversal);
#endif

class rpc_manager;
class node_impl;

// this class may not be instantiated as a stack object
class traversal_algorithm : boost::noncopyable
{
public:
	void traverse(node_id const& id, udp::endpoint addr);
	void finished(udp::endpoint const& ep);

	enum flags_t { prevent_request = 1, short_timeout = 2 };
	void failed(udp::endpoint const& ep, int flags = 0);
	virtual ~traversal_algorithm();
	boost::pool<>& allocator() const;
	void status(dht_lookup& l);

	virtual char const* name() const { return "traversal_algorithm"; }
	virtual void start();

	node_id const& target() const { return m_target; }

	void add_entry(node_id const& id, udp::endpoint addr, unsigned char flags);

	struct result
	{
		result(node_id const& id, udp::endpoint ep, unsigned char f = 0)
			: id(id), flags(f)
		{
			if (ep.address().is_v6())
			{
				flags |= ipv6_address;
				addr.v6 = ep.address().to_v6().to_bytes();
			}
			else
			{
				flags &= ~ipv6_address;
				addr.v4 = ep.address().to_v4().to_bytes();
			}
			port = ep.port();
		}

		udp::endpoint endpoint() const
		{
			if (flags & ipv6_address)
				return udp::endpoint(address_v6(addr.v6), port);
			else
				return udp::endpoint(address_v4(addr.v4), port);
		}

		node_id id;

		union addr_t
		{
			address_v4::bytes_type v4;
			address_v6::bytes_type v6;
		} addr;

		boost::uint16_t port;

		enum {
			queried = 1,
			initial = 2,
			no_id = 4,
			short_timeout = 8,
			failed = 16,
			ipv6_address = 32,
			alive = 64
		};
		unsigned char flags;
	};

	traversal_algorithm(
		node_impl& node
		, node_id target)
		: m_ref_count(0)
		, m_node(node)
		, m_target(target)
		, m_invoke_count(0)
		, m_branch_factor(3)
		, m_responses(0)
		, m_timeouts(0)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << "] new traversal process";
#endif
	}

protected:

	void add_requests();
	void add_router_entries();
	void init();

	virtual void done() {}
	virtual bool invoke(udp::endpoint addr) { return false; }

	friend void intrusive_ptr_add_ref(traversal_algorithm* p)
	{
		p->m_ref_count++;
	}

	friend void intrusive_ptr_release(traversal_algorithm* p)
	{
		if (--p->m_ref_count == 0)
			delete p;
	}

	int m_ref_count;

	node_impl& m_node;
	node_id m_target;
	std::vector<result> m_results;
	int m_invoke_count;
	int m_branch_factor;
	int m_responses;
	int m_timeouts;
};

} } // namespace libtorrent::dht

#endif // TRAVERSAL_ALGORITHM_050324_HPP

<commit_msg>fixed msvc warning<commit_after>/*

Copyright (c) 2006, Arvid Norberg & Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TRAVERSAL_ALGORITHM_050324_HPP
#define TRAVERSAL_ALGORITHM_050324_HPP

#include <vector>
#include <set>

#include <libtorrent/kademlia/node_id.hpp>
#include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/logging.hpp>

#include <boost/noncopyable.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/pool/pool.hpp>

namespace libtorrent { struct dht_lookup; }
namespace libtorrent { namespace dht
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DECLARE_LOG(traversal);
#endif

class rpc_manager;
class node_impl;

// this class may not be instantiated as a stack object
struct traversal_algorithm : boost::noncopyable
{
	void traverse(node_id const& id, udp::endpoint addr);
	void finished(udp::endpoint const& ep);

	enum flags_t { prevent_request = 1, short_timeout = 2 };
	void failed(udp::endpoint const& ep, int flags = 0);
	virtual ~traversal_algorithm();
	boost::pool<>& allocator() const;
	void status(dht_lookup& l);

	virtual char const* name() const { return "traversal_algorithm"; }
	virtual void start();

	node_id const& target() const { return m_target; }

	void add_entry(node_id const& id, udp::endpoint addr, unsigned char flags);

	struct result
	{
		result(node_id const& id, udp::endpoint ep, unsigned char f = 0)
			: id(id), flags(f)
		{
			if (ep.address().is_v6())
			{
				flags |= ipv6_address;
				addr.v6 = ep.address().to_v6().to_bytes();
			}
			else
			{
				flags &= ~ipv6_address;
				addr.v4 = ep.address().to_v4().to_bytes();
			}
			port = ep.port();
		}

		udp::endpoint endpoint() const
		{
			if (flags & ipv6_address)
				return udp::endpoint(address_v6(addr.v6), port);
			else
				return udp::endpoint(address_v4(addr.v4), port);
		}

		node_id id;

		union addr_t
		{
			address_v4::bytes_type v4;
			address_v6::bytes_type v6;
		} addr;

		boost::uint16_t port;

		enum {
			queried = 1,
			initial = 2,
			no_id = 4,
			short_timeout = 8,
			failed = 16,
			ipv6_address = 32,
			alive = 64
		};
		unsigned char flags;
	};

	traversal_algorithm(
		node_impl& node
		, node_id target)
		: m_ref_count(0)
		, m_node(node)
		, m_target(target)
		, m_invoke_count(0)
		, m_branch_factor(3)
		, m_responses(0)
		, m_timeouts(0)
	{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
		TORRENT_LOG(traversal) << " [" << this << "] new traversal process";
#endif
	}

protected:

	void add_requests();
	void add_router_entries();
	void init();

	virtual void done() {}
	virtual bool invoke(udp::endpoint addr) { return false; }

	friend void intrusive_ptr_add_ref(traversal_algorithm* p)
	{
		p->m_ref_count++;
	}

	friend void intrusive_ptr_release(traversal_algorithm* p)
	{
		if (--p->m_ref_count == 0)
			delete p;
	}

	int m_ref_count;

	node_impl& m_node;
	node_id m_target;
	std::vector<result> m_results;
	int m_invoke_count;
	int m_branch_factor;
	int m_responses;
	int m_timeouts;
};

} } // namespace libtorrent::dht

#endif // TRAVERSAL_ALGORITHM_050324_HPP

<|endoftext|>