<commit_before>/*
 * Copyright (C) 2008-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <iostream>

#include <boost/thread/tss.hpp>

#include <libport/cassert>
#include <libport/containers.hh>
#include <libport/cstdio>
#include <libport/debug.hh>
#include <libport/escape.hh>
#include <libport/fnmatch.h>
#include <libport/foreach.hh>
#include <libport/format.hh>
#include <libport/ip-semaphore.hh>
#include <libport/lockable.hh>
#include <libport/pthread.h>
#include <libport/thread-data.hh>
#include <libport/tokenizer.hh>
#include <libport/unistd.h>
#include <libport/utime.hh>
#include <libport/windows.hh>
#include <sched/coroutine-data.hh>

#ifndef WIN32
# include <syslog.h>
#endif

#ifndef LIBPORT_DEBUG_DISABLE

GD_CATEGORY(Libport.Debug);

namespace libport
{
  LIBPORT_API boost::function0<local_data&> debugger_data;
  LIBPORT_API Debug* debugger = 0;
  LIBPORT_API Debug::levels::Level Debug::filter_(levels::log);

  local_data&
  debugger_data_thread_local()
  {
    static boost::thread_specific_ptr<local_data> storage;
    if (!storage.get())
      storage.reset(new local_data);
    return *storage;
  }

  local_data::local_data()
    : indent(0)
  {}

  namespace debug
  {
    // Wether categories are enabled by default.
    static bool default_category_state = true;

    LIBPORT_API void
    uninitialized_msg(const std::string& msg)
    {
      static bool warned = false;
      if (!warned)
      {
        std::cerr << "[Libport.Debug] Uninitialized debug, fallback to stderr." << std::endl;
        warned = true;
      }
      std::cerr << "[Libport.Debug] " << msg << std::endl;
    }

    // Categories added so far.
    categories_type&
    categories()
    {
      static categories_type categories;
      return categories;
    }

    static unsigned
    current_pattern()
    {
      static unsigned current = 0;
      return current++;
    }

    // Patterns added so far.
    patterns_type&
    patterns()
    {
      static patterns_type patterns;
      return patterns;
    }

    // Maximum category width.
    size_t&
    categories_largest()
    {
      static size_t res = 0;
      return res;
    }

    // Add a new category, look if it matches a pattern.
    Symbol
    add_category(Symbol name)
    {
      int order = -1;
      bool value = default_category_state;
      foreach (patterns_type::value_type& s, patterns())
      {
        if (fnmatch(s.first.name_get(), name.name_get()) == 0)
        {
          if (int(s.second.second) > order)
          {
            value = s.second.first;
            order = s.second.second;
          }
        }
      }

      categories()[name] = value;

      size_t size = name.name_get().size();
      if (categories_largest() < size)
        categories_largest() = size;

      return name;
    }

    // Add a new category pattern.
    int
    enable_category(Symbol pattern)
    {
      patterns()[pattern] = std::make_pair(true, current_pattern());
      foreach (categories_type::value_type& s, categories())
      {
        if (fnmatch(pattern.name_get(), s.first.name_get()) == 0)
          s.second = true;
      }

      return 42;
    }

    // Disable a new category pattern.
    int
    disable_category(Symbol pattern)
    {
      patterns()[pattern] = std::make_pair(false, current_pattern());
      foreach (categories_type::value_type& s, categories())
      {
        if (fnmatch(pattern.name_get(), s.first.name_get()) == 0)
          s.second = false;
      }

      return 42;
    }

    // Enable/Disable a new category pattern with modifier.
    int
    auto_category(Symbol pattern)
    {
      std::string p = pattern.name_get();
      char modifier = p[0];
      if (modifier == '+' || modifier == '-')
        p = p.substr(1);
      else
        modifier = '+';
      bool value = modifier == '+';

      patterns()[Symbol(p)] = std::make_pair(value, current_pattern());
      foreach (categories_type::value_type& s, categories())
      {
        if (fnmatch(p, s.first.name_get()) == 0)
          s.second = value;
      }

      return 42;
    }

    bool test_category(Symbol name)
    {
      return categories()[name];
    }

    typedef enum
    {
      ENABLE,
      DISABLE,
      AUTO,
    } category_modifier_type;

    static void set_category_state(const char* list,
                                   const category_modifier_type state)
    {
      if (state == ENABLE)
        debug::default_category_state = false;
      else
        debug::default_category_state = true;

      // Also set existing to default_category_state.
      foreach(categories_type::value_type& v, categories())
        v.second = debug::default_category_state;

      std::string s(list); // Do not pass temporary to make_tokenizer.
      tokenizer_type t = make_tokenizer(s, ",");
      foreach(const std::string& elem, t)
      {
        Symbol pattern(elem);
        switch(state)
        {
          case ENABLE:
            enable_category(pattern);
            break;
          case DISABLE:
            disable_category(pattern);
            break;
          case AUTO:
            auto_category(pattern);
            break;
        }
      }
    }
  }

  Debug::Debug()
    : locations_(getenv("GD_LOC"))
    , timestamps_(getenv("GD_TIME") || getenv("GD_TIMESTAMP_US"))
  {
    // Process enabled/disabled/auto categories in environment.
    if (const char* autolist = getenv("GD_CATEGORY"))
      debug::set_category_state(autolist, debug::AUTO);
    else
    {
      if (const char* enablelist = getenv("GD_ENABLE_CATEGORY"))
        debug::set_category_state(enablelist, debug::ENABLE);
      if (const char* disablelist = getenv("GD_DISABLE_CATEGORY"))
        debug::set_category_state(disablelist, debug::DISABLE);
    }

    if (const char* lvl_c = getenv("GD_LEVEL"))
      filter(lvl_c);
  }

  Debug::~Debug()
  {}

  void
  Debug::filter(levels::Level lvl)
  {
    filter_ = lvl;
  }

  void
  Debug::filter(const std::string& lvl)
  {
    if (lvl == "NONE" || lvl == "0")
      filter(Debug::levels::none);
    else if (lvl == "LOG" || lvl == "1")
      filter(Debug::levels::log);
    else if (lvl == "TRACE" || lvl == "2")
      filter(Debug::levels::trace);
    else if (lvl == "DEBUG" || lvl == "3")
      filter(Debug::levels::debug);
    else if (lvl == "DUMP" || lvl == "4")
      filter(Debug::levels::dump);
    else
      // Don't use GD_ABORT here, we can be in the debugger constructor!
      pabort("invalid debug level (NONE, LOG, TRACE, DEBUG, DUMP or [0-4])");
  }

  unsigned
  Debug::indentation() const
  {
    return debugger_data().indent;
  }

  Debug::levels::Level
  Debug::level()
  {
    return filter_;
  }

# ifdef LIBPORT_HAVE_IP_SEMAPHORE
  static IPSemaphore& sem()
  {
    static IPSemaphore res(1);
    return res;
  }
# endif

  void
  Debug::debug(const std::string& msg,
               types::Type type,
               debug::category_type category,
               const std::string& fun,
               const std::string& file,
               unsigned line)
  {
# ifdef LIBPORT_HAVE_IP_SEMAPHORE
    static bool useLock = getenv("GD_USE_LOCK") || getenv("GD_PID");
    libport::Finally f;
    if (useLock)
    {
      --sem();
      f << boost::bind(&IPSemaphore::operator++, boost::ref(sem()));
    }
# endif
    message(category, msg, type, fun, file, line);
  }

  Debug*
  Debug::push(debug::category_type category,
              const std::string& msg,
              const std::string& fun,
              const std::string& file,
              unsigned line)
  {
    message_push(category, msg, fun, file, line);
    return this;
  }

  std::string
  Debug::category_format(debug::category_type cat) const
  {
    std::string res = cat;
    size_t size = res.size();
    size_t largest = debug::categories_largest();
    if (size < largest)
    {
      size_t diff = largest - size;
      res = std::string(diff / 2, ' ')
        + res
        + std::string(diff / 2 + diff % 2, ' ');
    }

    return res;
  }

  namespace opts
  {

    void cb_debug_fun(const std::string& lvl)
    {
      GD_DEBUGGER->filter(lvl);
    }

    OptionValued::callback_type cb_debug(cb_debug_fun);

    OptionValue
    debug("set the debug level in NONE, LOG (default), TRACE, DEBUG, DUMP",
          "debug", 'd', "LEVEL", cb_debug);

  }

  ConsoleDebug::ConsoleDebug()
  {}

  namespace
  {
    inline
    std::string
    time()
    {
      static bool us = getenv("GD_TIMESTAMP_US");
      if (us)
        return string_cast(utime());
      time_t now = std::time(0);
      struct tm* ts = std::localtime(&now);
      char buf[80];
      strftime(buf, sizeof buf, "%a %Y-%m-%d %H:%M:%S %Z", ts);
      return buf;
    }

    inline
    std::string
    color(int color, bool bold = true)
    {
      static bool tty = isatty(STDERR_FILENO);
      static bool force = getenv("GD_COLOR");
      static bool force_disable = getenv("GD_NO_COLOR");
      return (((tty || force) && !force_disable)
              ? format("[33;0%s;%sm", bold ? 1 : 0, color)
              : "");
    }
  }

  static Debug::colors::Color
  msg_color(Debug::types::Type type)
  {
    switch (type)
    {
      case Debug::types::info:
        return Debug::colors::white;
      case Debug::types::warn:
        return Debug::colors::yellow;
      case Debug::types::error:
        return Debug::colors::red;
    };
    GD_UNREACHABLE();
  }

  void
  ConsoleDebug::message(debug::category_type category,
                        const std::string& msg,
                        types::Type type,
                        const std::string& fun,
                        const std::string& file,
                        unsigned line)
  {
    std::ostringstream ostr;
    Debug::colors::Color c = msg_color(type);
    if (timestamps())
      ostr << color(c) << time() << "    ";
    ostr << color(colors::purple)
         << "[" << category_format(category) << "] ";
    {
      static bool pid = getenv("GD_PID");
      if (pid)
        ostr << "[" << getpid() << "] ";
    }
#ifndef WIN32
    {
      static bool thread = getenv("GD_THREAD");
      if (thread)
        ostr << "[" << pthread_self() << "] ";
    }
#endif
    ostr << color(c);
    for (unsigned i = 0; i < debugger_data().indent; ++i)
      ostr << "  ";
    // As syslog would do, don't issue the users' \n.
    if (!msg.empty() && msg[msg.size() - 1] == '\n')
      ostr.write(msg.c_str(), msg.size() - 1);
    else
      ostr << msg;
    if (locations())
      ostr << color(colors::blue)
           << "    (" << fun << ", " << file << ":" << line << ")";
    ostr << color(colors::white);
    std::cerr << ostr.str() << std::endl;
  }

  void
  ConsoleDebug::message_push(debug::category_type category,
                             const std::string& msg,
                             const std::string& fun,
                             const std::string& file,
                             unsigned line)
  {
    debug(msg, types::info, category, fun, file, line);
    GD_INDENTATION_INC();
  }

  void
  ConsoleDebug::pop()
  {
    assert_gt(debugger_data().indent, 0u);
    GD_INDENTATION_DEC();
  }

  std::string gd_ihexdump(const unsigned char* data, unsigned size)
  {
    std::string res =
      format("\"%s\"",
             libport::escape(std::string((const char*)data, (size_t)(size))));

    bool first = true;
    for (unsigned i = 0; i < size; ++i)
    {
      if (first)
        first = false;
      else
        res += " ";
      // Cast to int, or boost::format will print the character.
      res += format("0x%x", static_cast<unsigned int>(data[i]));
    }
    return res;
  }

#ifndef WIN32
  /*-------------.
  | Syslog debug |
  `-------------*/

  SyslogDebug::SyslogDebug(const std::string& program)
  {
    openlog(strdup(program.c_str()), LOG_PID, LOG_DAEMON);
    syslog(LOG_INFO | LOG_DAEMON, "%s",
           format("Opening syslog session for '%s'", program).c_str());
  }

  SyslogDebug::~SyslogDebug()
  {
    syslog(LOG_INFO | LOG_DAEMON, "Closing syslog session.");
    closelog();
  }

  static
  int type_to_prio(Debug::types::Type t)
  {
    switch (t)
    {
#define CASE(In, Out)                           \
      case Debug::types::In: return Out; break
      CASE(info,  LOG_INFO);
      CASE(warn,  LOG_WARNING);
      CASE(error, LOG_ERR);
#undef CASE
    }
    // Pacify Gcc.
    libport::abort();
  }

  void
  SyslogDebug::message(debug::category_type category,
                       const std::string& msg,
                       types::Type type,
                       const std::string& fun,
                       const std::string& file,
                       unsigned line)
  {
    std::stringstream s;
    s << "[" << category_format(category) << "] ";
    for (unsigned i = 0; i < debugger_data().indent; ++i)
      s << "  ";
    // As syslog would do, don't issue the users' \n.
    if (!msg.empty() && msg[msg.size() - 1] == '\n')
      s.write(msg.c_str(), msg.size() - 1);
    else
      s << msg;
    if (locations())
      s << "    (" << fun << ", " << file << ":" << line << ")";
    int prio = type_to_prio(type) | LOG_DAEMON;
    syslog(prio, "%s", s.str().c_str());
  }

  void
  SyslogDebug::message_push(debug::category_type category,
                            const std::string& msg,
                            const std::string& fun,
                            const std::string& file,
                            unsigned line)
  {
    debug(msg, types::info, category, fun, file, line);
    GD_INDENTATION_INC();
  }

  void
  SyslogDebug::pop()
  {
    assert_gt(debugger_data().indent, 0u);
    GD_INDENTATION_DEC();
  }
#endif

  boost::function0<Debug*> make_debugger;

  namespace debug
  {
    void clear()
    {
#if FIXME
      delete debugger();
#endif
    }
  }
}

#endif
<commit_msg>Libport.Debug: avoid extraneous \n.<commit_after>/*
 * Copyright (C) 2008-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <iostream>

#include <boost/thread/tss.hpp>

#include <libport/cassert>
#include <libport/containers.hh>
#include <libport/cstdio>
#include <libport/debug.hh>
#include <libport/escape.hh>
#include <libport/fnmatch.h>
#include <libport/foreach.hh>
#include <libport/format.hh>
#include <libport/ip-semaphore.hh>
#include <libport/lockable.hh>
#include <libport/pthread.h>
#include <libport/thread-data.hh>
#include <libport/tokenizer.hh>
#include <libport/unistd.h>
#include <libport/utime.hh>
#include <libport/windows.hh>
#include <sched/coroutine-data.hh>

#ifndef WIN32
# include <syslog.h>
#endif

#ifndef LIBPORT_DEBUG_DISABLE

GD_CATEGORY(Libport.Debug);

namespace libport
{
  LIBPORT_API boost::function0<local_data&> debugger_data;
  LIBPORT_API Debug* debugger = 0;
  LIBPORT_API Debug::levels::Level Debug::filter_(levels::log);

  local_data&
  debugger_data_thread_local()
  {
    static boost::thread_specific_ptr<local_data> storage;
    if (!storage.get())
      storage.reset(new local_data);
    return *storage;
  }

  local_data::local_data()
    : indent(0)
  {}

  namespace debug
  {
    // Wether categories are enabled by default.
    static bool default_category_state = true;

    LIBPORT_API void
    uninitialized_msg(const std::string& msg)
    {
      static bool tail = false;
      if (!tail++)
        std::cerr << "[Libport.Debug] "
                  << "Uninitialized debug, fallback to stderr." << std::endl;
      std::cerr << "[Libport.Debug] " << msg;
      if (msg.empty() || msg[msg.size() - 1] != '\n')
        std::cerr << std::endl;
    }

    // Categories added so far.
    categories_type&
    categories()
    {
      static categories_type categories;
      return categories;
    }

    static unsigned
    current_pattern()
    {
      static unsigned current = 0;
      return current++;
    }

    // Patterns added so far.
    patterns_type&
    patterns()
    {
      static patterns_type patterns;
      return patterns;
    }

    // Maximum category width.
    size_t&
    categories_largest()
    {
      static size_t res = 0;
      return res;
    }

    // Add a new category, look if it matches a pattern.
    Symbol
    add_category(Symbol name)
    {
      int order = -1;
      bool value = default_category_state;
      foreach (patterns_type::value_type& s, patterns())
      {
        if (fnmatch(s.first.name_get(), name.name_get()) == 0)
        {
          if (int(s.second.second) > order)
          {
            value = s.second.first;
            order = s.second.second;
          }
        }
      }

      categories()[name] = value;

      size_t size = name.name_get().size();
      if (categories_largest() < size)
        categories_largest() = size;

      return name;
    }

    // Add a new category pattern.
    int
    enable_category(Symbol pattern)
    {
      patterns()[pattern] = std::make_pair(true, current_pattern());
      foreach (categories_type::value_type& s, categories())
      {
        if (fnmatch(pattern.name_get(), s.first.name_get()) == 0)
          s.second = true;
      }

      return 42;
    }

    // Disable a new category pattern.
    int
    disable_category(Symbol pattern)
    {
      patterns()[pattern] = std::make_pair(false, current_pattern());
      foreach (categories_type::value_type& s, categories())
      {
        if (fnmatch(pattern.name_get(), s.first.name_get()) == 0)
          s.second = false;
      }

      return 42;
    }

    // Enable/Disable a new category pattern with modifier.
    int
    auto_category(Symbol pattern)
    {
      std::string p = pattern.name_get();
      char modifier = p[0];
      if (modifier == '+' || modifier == '-')
        p = p.substr(1);
      else
        modifier = '+';
      bool value = modifier == '+';

      patterns()[Symbol(p)] = std::make_pair(value, current_pattern());
      foreach (categories_type::value_type& s, categories())
      {
        if (fnmatch(p, s.first.name_get()) == 0)
          s.second = value;
      }

      return 42;
    }

    bool test_category(Symbol name)
    {
      return categories()[name];
    }

    typedef enum
    {
      ENABLE,
      DISABLE,
      AUTO,
    } category_modifier_type;

    static void set_category_state(const char* list,
                                   const category_modifier_type state)
    {
      if (state == ENABLE)
        debug::default_category_state = false;
      else
        debug::default_category_state = true;

      // Also set existing to default_category_state.
      foreach(categories_type::value_type& v, categories())
        v.second = debug::default_category_state;

      std::string s(list); // Do not pass temporary to make_tokenizer.
      tokenizer_type t = make_tokenizer(s, ",");
      foreach(const std::string& elem, t)
      {
        Symbol pattern(elem);
        switch(state)
        {
          case ENABLE:
            enable_category(pattern);
            break;
          case DISABLE:
            disable_category(pattern);
            break;
          case AUTO:
            auto_category(pattern);
            break;
        }
      }
    }
  }

  Debug::Debug()
    : locations_(getenv("GD_LOC"))
    , timestamps_(getenv("GD_TIME") || getenv("GD_TIMESTAMP_US"))
  {
    // Process enabled/disabled/auto categories in environment.
    if (const char* autolist = getenv("GD_CATEGORY"))
      debug::set_category_state(autolist, debug::AUTO);
    else
    {
      if (const char* enablelist = getenv("GD_ENABLE_CATEGORY"))
        debug::set_category_state(enablelist, debug::ENABLE);
      if (const char* disablelist = getenv("GD_DISABLE_CATEGORY"))
        debug::set_category_state(disablelist, debug::DISABLE);
    }

    if (const char* lvl_c = getenv("GD_LEVEL"))
      filter(lvl_c);
  }

  Debug::~Debug()
  {}

  void
  Debug::filter(levels::Level lvl)
  {
    filter_ = lvl;
  }

  void
  Debug::filter(const std::string& lvl)
  {
    if (lvl == "NONE" || lvl == "0")
      filter(Debug::levels::none);
    else if (lvl == "LOG" || lvl == "1")
      filter(Debug::levels::log);
    else if (lvl == "TRACE" || lvl == "2")
      filter(Debug::levels::trace);
    else if (lvl == "DEBUG" || lvl == "3")
      filter(Debug::levels::debug);
    else if (lvl == "DUMP" || lvl == "4")
      filter(Debug::levels::dump);
    else
      // Don't use GD_ABORT here, we can be in the debugger constructor!
      pabort("invalid debug level (NONE, LOG, TRACE, DEBUG, DUMP or [0-4])");
  }

  unsigned
  Debug::indentation() const
  {
    return debugger_data().indent;
  }

  Debug::levels::Level
  Debug::level()
  {
    return filter_;
  }

# ifdef LIBPORT_HAVE_IP_SEMAPHORE
  static IPSemaphore& sem()
  {
    static IPSemaphore res(1);
    return res;
  }
# endif

  void
  Debug::debug(const std::string& msg,
               types::Type type,
               debug::category_type category,
               const std::string& fun,
               const std::string& file,
               unsigned line)
  {
# ifdef LIBPORT_HAVE_IP_SEMAPHORE
    static bool useLock = getenv("GD_USE_LOCK") || getenv("GD_PID");
    libport::Finally f;
    if (useLock)
    {
      --sem();
      f << boost::bind(&IPSemaphore::operator++, boost::ref(sem()));
    }
# endif
    message(category, msg, type, fun, file, line);
  }

  Debug*
  Debug::push(debug::category_type category,
              const std::string& msg,
              const std::string& fun,
              const std::string& file,
              unsigned line)
  {
    message_push(category, msg, fun, file, line);
    return this;
  }

  std::string
  Debug::category_format(debug::category_type cat) const
  {
    std::string res = cat;
    size_t size = res.size();
    size_t largest = debug::categories_largest();
    if (size < largest)
    {
      size_t diff = largest - size;
      res = std::string(diff / 2, ' ')
        + res
        + std::string(diff / 2 + diff % 2, ' ');
    }

    return res;
  }

  namespace opts
  {

    void cb_debug_fun(const std::string& lvl)
    {
      GD_DEBUGGER->filter(lvl);
    }

    OptionValued::callback_type cb_debug(cb_debug_fun);

    OptionValue
    debug("set the debug level in NONE, LOG (default), TRACE, DEBUG, DUMP",
          "debug", 'd', "LEVEL", cb_debug);

  }

  ConsoleDebug::ConsoleDebug()
  {}

  namespace
  {
    inline
    std::string
    time()
    {
      static bool us = getenv("GD_TIMESTAMP_US");
      if (us)
        return string_cast(utime());
      time_t now = std::time(0);
      struct tm* ts = std::localtime(&now);
      char buf[80];
      strftime(buf, sizeof buf, "%a %Y-%m-%d %H:%M:%S %Z", ts);
      return buf;
    }

    inline
    std::string
    color(int color, bool bold = true)
    {
      static bool tty = isatty(STDERR_FILENO);
      static bool force = getenv("GD_COLOR");
      static bool force_disable = getenv("GD_NO_COLOR");
      return (((tty || force) && !force_disable)
              ? format("[33;0%s;%sm", bold ? 1 : 0, color)
              : "");
    }
  }

  static Debug::colors::Color
  msg_color(Debug::types::Type type)
  {
    switch (type)
    {
      case Debug::types::info:
        return Debug::colors::white;
      case Debug::types::warn:
        return Debug::colors::yellow;
      case Debug::types::error:
        return Debug::colors::red;
    };
    GD_UNREACHABLE();
  }

  void
  ConsoleDebug::message(debug::category_type category,
                        const std::string& msg,
                        types::Type type,
                        const std::string& fun,
                        const std::string& file,
                        unsigned line)
  {
    std::ostringstream ostr;
    Debug::colors::Color c = msg_color(type);
    if (timestamps())
      ostr << color(c) << time() << "    ";
    ostr << color(colors::purple)
         << "[" << category_format(category) << "] ";
    {
      static bool pid = getenv("GD_PID");
      if (pid)
        ostr << "[" << getpid() << "] ";
    }
#ifndef WIN32
    {
      static bool thread = getenv("GD_THREAD");
      if (thread)
        ostr << "[" << pthread_self() << "] ";
    }
#endif
    ostr << color(c);
    for (unsigned i = 0; i < debugger_data().indent; ++i)
      ostr << "  ";
    // As syslog would do, don't issue the users' \n.
    if (!msg.empty() && msg[msg.size() - 1] == '\n')
      ostr.write(msg.c_str(), msg.size() - 1);
    else
      ostr << msg;
    if (locations())
      ostr << color(colors::blue)
           << "    (" << fun << ", " << file << ":" << line << ")";
    ostr << color(colors::white);
    std::cerr << ostr.str() << std::endl;
  }

  void
  ConsoleDebug::message_push(debug::category_type category,
                             const std::string& msg,
                             const std::string& fun,
                             const std::string& file,
                             unsigned line)
  {
    debug(msg, types::info, category, fun, file, line);
    GD_INDENTATION_INC();
  }

  void
  ConsoleDebug::pop()
  {
    assert_gt(debugger_data().indent, 0u);
    GD_INDENTATION_DEC();
  }

  std::string gd_ihexdump(const unsigned char* data, unsigned size)
  {
    std::string res =
      format("\"%s\"",
             libport::escape(std::string((const char*)data, (size_t)(size))));

    bool first = true;
    for (unsigned i = 0; i < size; ++i)
    {
      if (first)
        first = false;
      else
        res += " ";
      // Cast to int, or boost::format will print the character.
      res += format("0x%x", static_cast<unsigned int>(data[i]));
    }
    return res;
  }

#ifndef WIN32
  /*-------------.
  | Syslog debug |
  `-------------*/

  SyslogDebug::SyslogDebug(const std::string& program)
  {
    openlog(strdup(program.c_str()), LOG_PID, LOG_DAEMON);
    syslog(LOG_INFO | LOG_DAEMON, "%s",
           format("Opening syslog session for '%s'", program).c_str());
  }

  SyslogDebug::~SyslogDebug()
  {
    syslog(LOG_INFO | LOG_DAEMON, "Closing syslog session.");
    closelog();
  }

  static
  int type_to_prio(Debug::types::Type t)
  {
    switch (t)
    {
#define CASE(In, Out)                           \
      case Debug::types::In: return Out; break
      CASE(info,  LOG_INFO);
      CASE(warn,  LOG_WARNING);
      CASE(error, LOG_ERR);
#undef CASE
    }
    // Pacify Gcc.
    libport::abort();
  }

  void
  SyslogDebug::message(debug::category_type category,
                       const std::string& msg,
                       types::Type type,
                       const std::string& fun,
                       const std::string& file,
                       unsigned line)
  {
    std::stringstream s;
    s << "[" << category_format(category) << "] ";
    for (unsigned i = 0; i < debugger_data().indent; ++i)
      s << "  ";
    // As syslog would do, don't issue the users' \n.
    if (!msg.empty() && msg[msg.size() - 1] == '\n')
      s.write(msg.c_str(), msg.size() - 1);
    else
      s << msg;
    if (locations())
      s << "    (" << fun << ", " << file << ":" << line << ")";
    int prio = type_to_prio(type) | LOG_DAEMON;
    syslog(prio, "%s", s.str().c_str());
  }

  void
  SyslogDebug::message_push(debug::category_type category,
                            const std::string& msg,
                            const std::string& fun,
                            const std::string& file,
                            unsigned line)
  {
    debug(msg, types::info, category, fun, file, line);
    GD_INDENTATION_INC();
  }

  void
  SyslogDebug::pop()
  {
    assert_gt(debugger_data().indent, 0u);
    GD_INDENTATION_DEC();
  }
#endif

  boost::function0<Debug*> make_debugger;

  namespace debug
  {
    void clear()
    {
#if FIXME
      delete debugger();
#endif
    }
  }
}

#endif
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <unistd.h>

#include <map>
#include <string>

#include <mesos/mesos.hpp>

#include <mesos/module/container_logger.hpp>

#include <mesos/slave/container_logger.hpp>
#include <mesos/slave/containerizer.hpp>

#include <process/dispatch.hpp>
#include <process/future.hpp>
#include <process/process.hpp>
#include <process/subprocess.hpp>

#include <stout/bytes.hpp>
#include <stout/error.hpp>
#include <stout/try.hpp>
#include <stout/none.hpp>
#include <stout/nothing.hpp>
#include <stout/path.hpp>
#include <stout/strings.hpp>

#include <stout/os/constants.hpp>
#include <stout/os/environment.hpp>
#include <stout/os/fcntl.hpp>
#include <stout/os/killtree.hpp>

#ifdef __linux__
#include "linux/systemd.hpp"
#endif // __linux__

#include "slave/container_loggers/logrotate.hpp"
#include "slave/container_loggers/lib_logrotate.hpp"

using namespace mesos;
using namespace process;

using std::map;
using std::string;

using mesos::slave::ContainerConfig;
using mesos::slave::ContainerLogger;
using mesos::slave::ContainerIO;

namespace mesos {
namespace internal {
namespace logger {

class LogrotateContainerLoggerProcess :
  public Process<LogrotateContainerLoggerProcess>
{
public:
  LogrotateContainerLoggerProcess(const Flags& _flags) : flags(_flags) {}

  // Spawns two subprocesses that read from their stdin and write to
  // "stdout" and "stderr" files in the sandbox.  The subprocesses will rotate
  // the files according to the configured maximum size and number of files.
  Future<ContainerIO> prepare(
      const ContainerID& containerId,
      const ContainerConfig& containerConfig)
  {
    // Prepare the environment for the container logger subprocess.
    // We inherit agent environment variables except for those
    // LIBPROCESS or MESOS prefixed environment variables. See MESOS-6747.
    map<string, string> environment;

    foreachpair (
        const string& key, const string& value, os::environment()) {
      if (!strings::startsWith(key, "LIBPROCESS_") &&
          !strings::startsWith(key, "MESOS_")) {
        environment.emplace(key, value);
      }
    }

    // Make sure the libprocess of the subprocess can properly
    // initialize and find the IP. Since we don't need to use the TCP
    // socket for communication, it's OK to use a local address.
    environment.emplace("LIBPROCESS_IP", "127.0.0.1");

    // Use the number of worker threads for libprocess that was passed
    // in through the flags.
    CHECK_GT(flags.libprocess_num_worker_threads, 0u);
    environment["LIBPROCESS_NUM_WORKER_THREADS"] =
      stringify(flags.libprocess_num_worker_threads);

    // Copy the global rotation flags.
    // These will act as the defaults in case the container's environment
    // overrides a subset of them.
    LoggerFlags overriddenFlags;
    overriddenFlags.max_stdout_size = flags.max_stdout_size;
    overriddenFlags.logrotate_stdout_options = flags.logrotate_stdout_options;
    overriddenFlags.max_stderr_size = flags.max_stderr_size;
    overriddenFlags.logrotate_stderr_options = flags.logrotate_stderr_options;

    // Check for overrides of the rotation settings in the
    // `CommandInfo`s environment variables.
    if (containerConfig.command_info().has_environment()) {
      // Search the environment for prefixed environment variables.
      // We un-prefix those variables before parsing the flag values.
      map<string, string> containerEnvironment;
      foreach (const Environment::Variable variable,
               containerConfig.command_info().environment().variables()) {
        if (strings::startsWith(
              variable.name(), flags.environment_variable_prefix)) {
          string unprefixed = strings::lower(strings::remove(
              variable.name(),
              flags.environment_variable_prefix,
              strings::PREFIX));
          containerEnvironment[unprefixed] = variable.value();
        }
      }

      // We will error out if there are unknown flags with the same prefix.
      Try<flags::Warnings> load = overriddenFlags.load(containerEnvironment);

      if (load.isError()) {
        return Failure(
            "Failed to load container logger settings: " + load.error());
      }

      // Log any flag warnings.
      foreach (const flags::Warning& warning, load->warnings) {
        LOG(WARNING) << warning.message;
      }
    }

    // NOTE: We manually construct a pipe here instead of using
    // `Subprocess::PIPE` so that the ownership of the FDs is properly
    // represented.  The `Subprocess` spawned below owns the read-end
    // of the pipe and will be solely responsible for closing that end.
    // The ownership of the write-end will be passed to the caller
    // of this function.
    int pipefd[2];
    if (::pipe(pipefd) == -1) {
      return Failure(ErrnoError("Failed to create pipe").message);
    }

    Subprocess::IO::InputFileDescriptors outfds;
    outfds.read = pipefd[0];
    outfds.write = pipefd[1];

    // NOTE: We need to `cloexec` this FD so that it will be closed when
    // the child subprocess is spawned and so that the FD will not be
    // inherited by the second child for stderr.
    Try<Nothing> cloexec = os::cloexec(outfds.write.get());
    if (cloexec.isError()) {
      os::close(outfds.read);
      os::close(outfds.write.get());
      return Failure("Failed to cloexec: " + cloexec.error());
    }

    // Spawn a process to handle stdout.
    mesos::internal::logger::rotate::Flags outFlags;
    outFlags.max_size = overriddenFlags.max_stdout_size;
    outFlags.logrotate_options = overriddenFlags.logrotate_stdout_options;
    outFlags.log_filename = path::join(containerConfig.directory(), "stdout");
    outFlags.logrotate_path = flags.logrotate_path;
    outFlags.user = containerConfig.has_user()
      ? Option<string>(containerConfig.user())
      : Option<string>::none();

    // If we are on systemd, then extend the life of the process as we
    // do with the executor. Any grandchildren's lives will also be
    // extended.
    std::vector<Subprocess::ParentHook> parentHooks;
#ifdef __linux__
    if (systemd::enabled()) {
      parentHooks.emplace_back(Subprocess::ParentHook(
          &systemd::mesos::extendLifetime));
    }
#endif // __linux__

    Try<Subprocess> outProcess = subprocess(
        path::join(flags.launcher_dir, mesos::internal::logger::rotate::NAME),
        {mesos::internal::logger::rotate::NAME},
        Subprocess::FD(outfds.read, Subprocess::IO::OWNED),
        Subprocess::PATH(os::DEV_NULL),
        Subprocess::FD(STDERR_FILENO),
        &outFlags,
        environment,
        None(),
        parentHooks);

    if (outProcess.isError()) {
      os::close(outfds.write.get());
      return Failure("Failed to create logger process: " + outProcess.error());
    }

    // NOTE: We manually construct a pipe here to properly express
    // ownership of the FDs.  See the NOTE above.
    if (::pipe(pipefd) == -1) {
      os::close(outfds.write.get());
      os::killtree(outProcess->pid(), SIGKILL);
      return Failure(ErrnoError("Failed to create pipe").message);
    }

    Subprocess::IO::InputFileDescriptors errfds;
    errfds.read = pipefd[0];
    errfds.write = pipefd[1];

    // NOTE: We need to `cloexec` this FD so that it will be closed when
    // the child subprocess is spawned.
    cloexec = os::cloexec(errfds.write.get());
    if (cloexec.isError()) {
      os::close(outfds.write.get());
      os::close(errfds.read);
      os::close(errfds.write.get());
      os::killtree(outProcess->pid(), SIGKILL);
      return Failure("Failed to cloexec: " + cloexec.error());
    }

    // Spawn a process to handle stderr.
    mesos::internal::logger::rotate::Flags errFlags;
    errFlags.max_size = overriddenFlags.max_stderr_size;
    errFlags.logrotate_options = overriddenFlags.logrotate_stderr_options;
    errFlags.log_filename = path::join(containerConfig.directory(), "stderr");
    errFlags.logrotate_path = flags.logrotate_path;
    errFlags.user = containerConfig.has_user()
      ? Option<string>(containerConfig.user())
      : Option<string>::none();

    Try<Subprocess> errProcess = subprocess(
        path::join(flags.launcher_dir, mesos::internal::logger::rotate::NAME),
        {mesos::internal::logger::rotate::NAME},
        Subprocess::FD(errfds.read, Subprocess::IO::OWNED),
        Subprocess::PATH(os::DEV_NULL),
        Subprocess::FD(STDERR_FILENO),
        &errFlags,
        environment,
        None(),
        parentHooks);

    if (errProcess.isError()) {
      os::close(outfds.write.get());
      os::close(errfds.write.get());
      os::killtree(outProcess->pid(), SIGKILL);
      return Failure("Failed to create logger process: " + errProcess.error());
    }

    // NOTE: The ownership of these FDs is given to the caller of this function.
    ContainerIO io;
    io.out = ContainerIO::IO::FD(outfds.write.get());
    io.err = ContainerIO::IO::FD(errfds.write.get());
    return io;
  }

protected:
  Flags flags;
};

LogrotateContainerLogger::LogrotateContainerLogger(const Flags& _flags)
  : flags(_flags),
    process(new LogrotateContainerLoggerProcess(flags))
{
  // Spawn and pass validated parameters to the process.
  spawn(process.get());
}

LogrotateContainerLogger::~LogrotateContainerLogger()
{
  terminate(process.get());
  wait(process.get());
}

Try<Nothing> LogrotateContainerLogger::initialize()
{
  return Nothing();
}

Future<ContainerIO> LogrotateContainerLogger::prepare(
    const ContainerID& containerId,
    const ContainerConfig& containerConfig)
{
  return dispatch(
      process.get(),
      &LogrotateContainerLoggerProcess::prepare,
      containerId,
      containerConfig);
}

} // namespace logger {
} // namespace internal {
} // namespace mesos {

mesos::modules::Module<ContainerLogger>
org_apache_mesos_LogrotateContainerLogger(
    MESOS_MODULE_API_VERSION,
    MESOS_VERSION,
    "Apache Mesos",
    "modules@mesos.apache.org",
    "Logrotate Container Logger module.",
    nullptr,
    [](const Parameters& parameters) -> ContainerLogger* {
      // Convert `parameters` into a map.
      map<string, string> values;
      foreach (const Parameter& parameter, parameters.parameter()) {
        values[parameter.key()] = parameter.value();
      }

      // Load and validate flags from the map.
      mesos::internal::logger::Flags flags;
      Try<flags::Warnings> load = flags.load(values);

      if (load.isError()) {
        LOG(ERROR) << "Failed to parse parameters: " << load.error();
        return nullptr;
      }

      // Log any flag warnings.
      foreach (const flags::Warning& warning, load->warnings) {
        LOG(WARNING) << warning.message;
      }

      return new mesos::internal::logger::LogrotateContainerLogger(flags);
    });
<commit_msg>Updated the ::pipe() system calls to pipe2 in lib_logrotate.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <unistd.h>

#include <map>
#include <string>

#include <mesos/mesos.hpp>

#include <mesos/module/container_logger.hpp>

#include <mesos/slave/container_logger.hpp>
#include <mesos/slave/containerizer.hpp>

#include <process/dispatch.hpp>
#include <process/future.hpp>
#include <process/process.hpp>
#include <process/subprocess.hpp>

#include <stout/bytes.hpp>
#include <stout/error.hpp>
#include <stout/try.hpp>
#include <stout/none.hpp>
#include <stout/nothing.hpp>
#include <stout/path.hpp>
#include <stout/strings.hpp>

#include <stout/os/constants.hpp>
#include <stout/os/environment.hpp>
#include <stout/os/fcntl.hpp>
#include <stout/os/killtree.hpp>
#include <stout/os/pipe.hpp>

#ifdef __linux__
#include "linux/systemd.hpp"
#endif // __linux__

#include "slave/container_loggers/logrotate.hpp"
#include "slave/container_loggers/lib_logrotate.hpp"

using namespace mesos;
using namespace process;

using std::array;
using std::map;
using std::string;

using mesos::slave::ContainerConfig;
using mesos::slave::ContainerLogger;
using mesos::slave::ContainerIO;

namespace mesos {
namespace internal {
namespace logger {

class LogrotateContainerLoggerProcess :
  public Process<LogrotateContainerLoggerProcess>
{
public:
  LogrotateContainerLoggerProcess(const Flags& _flags) : flags(_flags) {}

  // Spawns two subprocesses that read from their stdin and write to
  // "stdout" and "stderr" files in the sandbox.  The subprocesses will rotate
  // the files according to the configured maximum size and number of files.
  Future<ContainerIO> prepare(
      const ContainerID& containerId,
      const ContainerConfig& containerConfig)
  {
    // Prepare the environment for the container logger subprocess.
    // We inherit agent environment variables except for those
    // LIBPROCESS or MESOS prefixed environment variables. See MESOS-6747.
    map<string, string> environment;

    foreachpair (
        const string& key, const string& value, os::environment()) {
      if (!strings::startsWith(key, "LIBPROCESS_") &&
          !strings::startsWith(key, "MESOS_")) {
        environment.emplace(key, value);
      }
    }

    // Make sure the libprocess of the subprocess can properly
    // initialize and find the IP. Since we don't need to use the TCP
    // socket for communication, it's OK to use a local address.
    environment.emplace("LIBPROCESS_IP", "127.0.0.1");

    // Use the number of worker threads for libprocess that was passed
    // in through the flags.
    CHECK_GT(flags.libprocess_num_worker_threads, 0u);
    environment["LIBPROCESS_NUM_WORKER_THREADS"] =
      stringify(flags.libprocess_num_worker_threads);

    // Copy the global rotation flags.
    // These will act as the defaults in case the container's environment
    // overrides a subset of them.
    LoggerFlags overriddenFlags;
    overriddenFlags.max_stdout_size = flags.max_stdout_size;
    overriddenFlags.logrotate_stdout_options = flags.logrotate_stdout_options;
    overriddenFlags.max_stderr_size = flags.max_stderr_size;
    overriddenFlags.logrotate_stderr_options = flags.logrotate_stderr_options;

    // Check for overrides of the rotation settings in the
    // `CommandInfo`s environment variables.
    if (containerConfig.command_info().has_environment()) {
      // Search the environment for prefixed environment variables.
      // We un-prefix those variables before parsing the flag values.
      map<string, string> containerEnvironment;
      foreach (const Environment::Variable variable,
               containerConfig.command_info().environment().variables()) {
        if (strings::startsWith(
              variable.name(), flags.environment_variable_prefix)) {
          string unprefixed = strings::lower(strings::remove(
              variable.name(),
              flags.environment_variable_prefix,
              strings::PREFIX));
          containerEnvironment[unprefixed] = variable.value();
        }
      }

      // We will error out if there are unknown flags with the same prefix.
      Try<flags::Warnings> load = overriddenFlags.load(containerEnvironment);

      if (load.isError()) {
        return Failure(
            "Failed to load container logger settings: " + load.error());
      }

      // Log any flag warnings.
      foreach (const flags::Warning& warning, load->warnings) {
        LOG(WARNING) << warning.message;
      }
    }

    // NOTE: We manually construct a pipe here instead of using
    // `Subprocess::PIPE` so that the ownership of the FDs is properly
    // represented.  The `Subprocess` spawned below owns the read-end
    // of the pipe and will be solely responsible for closing that end.
    // The ownership of the write-end will be passed to the caller
    // of this function.
    Try<array<int, 2>> pipefd = os::pipe();
    if (pipefd.isError()) {
      return Failure("Failed to create pipe: " + pipefd.error());
    }

    Subprocess::IO::InputFileDescriptors outfds;
    outfds.read = pipefd->at(0);
    outfds.write = pipefd->at(1);

    const std::vector<int_fd> whitelistOutFds{pipefd->at(0), pipefd->at(1)};

    // Spawn a process to handle stdout.
    mesos::internal::logger::rotate::Flags outFlags;
    outFlags.max_size = overriddenFlags.max_stdout_size;
    outFlags.logrotate_options = overriddenFlags.logrotate_stdout_options;
    outFlags.log_filename = path::join(containerConfig.directory(), "stdout");
    outFlags.logrotate_path = flags.logrotate_path;
    outFlags.user = containerConfig.has_user()
      ? Option<string>(containerConfig.user())
      : Option<string>::none();

    // If we are on systemd, then extend the life of the process as we
    // do with the executor. Any grandchildren's lives will also be
    // extended.
    std::vector<Subprocess::ParentHook> parentHooks;
#ifdef __linux__
    if (systemd::enabled()) {
      parentHooks.emplace_back(Subprocess::ParentHook(
          &systemd::mesos::extendLifetime));
    }
#endif // __linux__

    // TODO(gilbert): libprocess should take care of this, see MESOS-9164.
    std::vector<Subprocess::ChildHook> childHooks;
    foreach (int_fd fd, whitelistOutFds) {
      childHooks.push_back(Subprocess::ChildHook::UNSET_CLOEXEC(fd));
    }

    Try<Subprocess> outProcess = subprocess(
        path::join(flags.launcher_dir, mesos::internal::logger::rotate::NAME),
        {mesos::internal::logger::rotate::NAME},
        Subprocess::FD(outfds.read, Subprocess::IO::OWNED),
        Subprocess::PATH(os::DEV_NULL),
        Subprocess::FD(STDERR_FILENO),
        &outFlags,
        environment,
        None(),
        parentHooks,
        childHooks,
        whitelistOutFds);

    if (outProcess.isError()) {
      os::close(outfds.write.get());
      return Failure("Failed to create logger process: " + outProcess.error());
    }

    // NOTE: We manually construct a pipe here to properly express
    // ownership of the FDs.  See the NOTE above.
    pipefd = os::pipe();
    if (pipefd.isError()) {
      os::close(outfds.write.get());
      os::killtree(outProcess->pid(), SIGKILL);
      return Failure("Failed to create pipe: " + pipefd.error());
    }

    Subprocess::IO::InputFileDescriptors errfds;
    errfds.read = pipefd->at(0);
    errfds.write = pipefd->at(1);

    const std::vector<int_fd> whitelistErrFds{pipefd->at(0), pipefd->at(1)};

    // Spawn a process to handle stderr.
    mesos::internal::logger::rotate::Flags errFlags;
    errFlags.max_size = overriddenFlags.max_stderr_size;
    errFlags.logrotate_options = overriddenFlags.logrotate_stderr_options;
    errFlags.log_filename = path::join(containerConfig.directory(), "stderr");
    errFlags.logrotate_path = flags.logrotate_path;
    errFlags.user = containerConfig.has_user()
      ? Option<string>(containerConfig.user())
      : Option<string>::none();

    // TODO(gilbert): libprocess should take care of this, see MESOS-9164.
    childHooks.clear();
    foreach (int_fd fd, whitelistErrFds) {
      childHooks.push_back(Subprocess::ChildHook::UNSET_CLOEXEC(fd));
    }

    Try<Subprocess> errProcess = subprocess(
        path::join(flags.launcher_dir, mesos::internal::logger::rotate::NAME),
        {mesos::internal::logger::rotate::NAME},
        Subprocess::FD(errfds.read, Subprocess::IO::OWNED),
        Subprocess::PATH(os::DEV_NULL),
        Subprocess::FD(STDERR_FILENO),
        &errFlags,
        environment,
        None(),
        parentHooks,
        childHooks,
        whitelistErrFds);

    if (errProcess.isError()) {
      os::close(outfds.write.get());
      os::close(errfds.write.get());
      os::killtree(outProcess->pid(), SIGKILL);
      return Failure("Failed to create logger process: " + errProcess.error());
    }

    // NOTE: The ownership of these FDs is given to the caller of this function.
    ContainerIO io;
    io.out = ContainerIO::IO::FD(outfds.write.get());
    io.err = ContainerIO::IO::FD(errfds.write.get());
    return io;
  }

protected:
  Flags flags;
};

LogrotateContainerLogger::LogrotateContainerLogger(const Flags& _flags)
  : flags(_flags),
    process(new LogrotateContainerLoggerProcess(flags))
{
  // Spawn and pass validated parameters to the process.
  spawn(process.get());
}

LogrotateContainerLogger::~LogrotateContainerLogger()
{
  terminate(process.get());
  wait(process.get());
}

Try<Nothing> LogrotateContainerLogger::initialize()
{
  return Nothing();
}

Future<ContainerIO> LogrotateContainerLogger::prepare(
    const ContainerID& containerId,
    const ContainerConfig& containerConfig)
{
  return dispatch(
      process.get(),
      &LogrotateContainerLoggerProcess::prepare,
      containerId,
      containerConfig);
}

} // namespace logger {
} // namespace internal {
} // namespace mesos {

mesos::modules::Module<ContainerLogger>
org_apache_mesos_LogrotateContainerLogger(
    MESOS_MODULE_API_VERSION,
    MESOS_VERSION,
    "Apache Mesos",
    "modules@mesos.apache.org",
    "Logrotate Container Logger module.",
    nullptr,
    [](const Parameters& parameters) -> ContainerLogger* {
      // Convert `parameters` into a map.
      map<string, string> values;
      foreach (const Parameter& parameter, parameters.parameter()) {
        values[parameter.key()] = parameter.value();
      }

      // Load and validate flags from the map.
      mesos::internal::logger::Flags flags;
      Try<flags::Warnings> load = flags.load(values);

      if (load.isError()) {
        LOG(ERROR) << "Failed to parse parameters: " << load.error();
        return nullptr;
      }

      // Log any flag warnings.
      foreach (const flags::Warning& warning, load->warnings) {
        LOG(WARNING) << warning.message;
      }

      return new mesos::internal::logger::LogrotateContainerLogger(flags);
    });
<|endoftext|>


<commit_before>#ifndef __STAN__GM__ARGUMENTS__STEPSIZE__JITTER__HPP__
#define __STAN__GM__ARGUMENTS__STEPSIZE__JITTER__HPP__

#include <stan/gm/arguments/singleton_argument.hpp>

namespace stan {

  namespace gm {

    class arg_stepsize_jitter: public real_argument {

    public:

      arg_stepsize_jitter(): real_argument() {
        _name = "stepsize_jitter";
        _description = "Uniformly random jitter of the stepsize, in percent";
        _validity = "0 < stepsize_jitter < 1";
        _default = "0";
        _default_value = 0.0;
        _constrained = true;
        _good_value = 0.5;
        _bad_value = -1.0;
        _value = _default_value;
      };

      bool is_valid(double value) { return 0 < value && value < 1; }

    };

  } // gm

} // stan

#endif<commit_msg>Use inclusive range of validity<commit_after>#ifndef __STAN__GM__ARGUMENTS__STEPSIZE__JITTER__HPP__
#define __STAN__GM__ARGUMENTS__STEPSIZE__JITTER__HPP__

#include <stan/gm/arguments/singleton_argument.hpp>

namespace stan {

  namespace gm {

    class arg_stepsize_jitter: public real_argument {

    public:

      arg_stepsize_jitter(): real_argument() {
        _name = "stepsize_jitter";
        _description = "Uniformly random jitter of the stepsize, in percent";
        _validity = "0 <= stepsize_jitter <= 1";
        _default = "0";
        _default_value = 0.0;
        _constrained = true;
        _good_value = 0.5;
        _bad_value = -1.0;
        _value = _default_value;
      };

      bool is_valid(double value) { return 0 <= value && value <= 1; }

    };

  } // gm

} // stan

#endif<|endoftext|>


<commit_before>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_VALUES_H_
#define LUWRA_VALUES_H_

#include "common.hpp"
#include "internal/indexsequence.hpp"

#include <utility>
#include <string>

LUWRA_NS_BEGIN

template <typename UserType>
struct Value;

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<const Type>: Value<Type> {};

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<volatile Type>: Value<Type> {};

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<const volatile Type>: Value<Type> {};

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<Type&>: Value<Type> {};

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<Type&&>: Value<Type> {};

namespace internal {
	struct InferValueType {
		State* state;
		int index;

		template <typename Type>
		operator Type() const && {
			return Value<Type>::read(state, index);
		}

		template <typename Type>
		operator Type&() const & {
			return Value<Type&>::read(state, index);
		}
	};
}

/// Enables reading of type-infered values
template <>
struct Value<internal::InferValueType> {
	static inline
	const internal::InferValueType read(State* state, int index) {
		return {state, index};
	}
};

/// Enables reading/pushing `nil`
template <>
struct Value<std::nullptr_t> {
	static inline
	std::nullptr_t read(State* state, int n) {
		luaL_checktype(state, n, LUA_TNIL);
		return nullptr;
	}

	static inline
	void push(State* state, std::nullptr_t) {
		lua_pushnil(state);
	}
};

/// Enables reading Lua threads
template <>
struct Value<State*> {
	static inline
	State* read(State* state, int n) {
		luaL_checktype(state, n, LUA_TTHREAD);
		return lua_tothread(state, n);
	}
};

/// Enables reading/pushing light data
template <>
struct Value<void*> {
	static inline
	void* read(State* state, int n) {
		luaL_checktype(state, n, LUA_TLIGHTUSERDATA);
		return lua_touserdata(state, n);
	}

	static inline
	void push(State* state, void* data) {
		lua_pushlightuserdata(state, data);
	}
};

/// Enables reading constant light data
template <>
struct Value<const void*> {
	static inline
	const void* read(State* state, int n) {
		luaL_checktype(state, n, LUA_TLIGHTUSERDATA);
		return lua_touserdata(state, n);
	}
};

namespace internal {
	template <typename Type>
	struct NumericTransportValue {
		static_assert(
			sizeof(Type) == -1,
			"Parameter to NumericTransportValue is not a numeric base type"
		);
	};

	// Transport unit `Integer`
	template <>
	struct NumericTransportValue<Integer> {
		static inline
		Integer read(State* state, int index) {
			return luaL_checkinteger(state, index);
		}

		static inline
		void push(State* state, Integer value) {
			lua_pushinteger(state, value);
		}
	};

	// Transport unit `Number`
	template <>
	struct NumericTransportValue<Number> {
		static inline
		Number read(State* state, int index) {
			return luaL_checknumber(state, index);
		}

		static inline
		void push(State* state, Number value) {
			lua_pushnumber(state, value);
		}
	};

	// Base for `Value<Type>` specializations which uses `Transport` as transport unit
	template <typename Type, typename Transport>
	struct NumericValueBase {
		static inline
		Type read(State* state, int index) {
			return static_cast<Type>(NumericTransportValue<Transport>::read(state, index));
		}

		static inline
		void push(State* state, Type value) {
			NumericTransportValue<Transport>::push(state, static_cast<Transport>(value));
		}
	};
}

// Define an integral type which will be transported via `base`.
#define LUWRA_DEF_NUMERIC(base, type) \
	template <> \
	struct Value<type>: internal::NumericValueBase<type, base> {};

// Lua-dependent types
LUWRA_DEF_NUMERIC(Number, float)
LUWRA_DEF_NUMERIC(Number, double)
LUWRA_DEF_NUMERIC(Number, long double)

// Integral types
LUWRA_DEF_NUMERIC(Integer, signed   char)
LUWRA_DEF_NUMERIC(Integer, unsigned char)
LUWRA_DEF_NUMERIC(Integer, signed   short)
LUWRA_DEF_NUMERIC(Integer, unsigned short)
LUWRA_DEF_NUMERIC(Integer, signed   int)
LUWRA_DEF_NUMERIC(Integer, unsigned int)
LUWRA_DEF_NUMERIC(Integer, signed   long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long int)
LUWRA_DEF_NUMERIC(Integer, signed   long long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long long int)

// Do not export this macros
#undef LUWRA_DEF_NUMERIC

/// Enables reading/pushing strings as C strings
template <>
struct Value<const char*> {
	static inline
	const char* read(State* state, int n) {
		return luaL_checkstring(state, n);
	}

	static inline
	void push(State* state, const char* value) {
		lua_pushstring(state, value);
	}
};

/// Enables reading/pushing string as `std::string`.
template <>
struct Value<std::string> {
	static inline
	std::string read(State* state, int n) {
		size_t length;
		const char* value = luaL_checklstring(state, n, &length);
		return {value, length};
	}

	static inline
	void push(State* state, const std::string& value) {
		lua_pushstring(state, value.c_str());
	}
};

/// Enables reading/pushing booleans
template <>
struct Value<bool> {
	static inline
	bool read(State* state, int n) {
		luaL_checktype(state, n, LUA_TBOOLEAN);
		return lua_toboolean(state, n) == 1;
	}

	static inline
	void push(State* state, bool value) {
		lua_pushboolean(state, static_cast<int>(value));
	}
};

/// Alias for @ref Value<const char*>
template <>
struct Value<char*>: Value<const char*> {};

/// Alias for @ref Value<const char*>
template <size_t N>
struct Value<char[N]>: Value<const char*> {};

/// Alias for @ref Value<const char*>
template <size_t N>
struct Value<const char[N]>: Value<const char*> {};

/// A version of @ref Value for pushing return values onto the stack. @ref ReturnValue inherits
/// `push` implementations from @ref Value.
template <typename Type>
struct ReturnValue {
	template <typename... Args> static inline
	size_t push(State* state, Args&&... args) {
		Value<Type>::push(state, std::forward<Args>(args)...);
		return 1;
	}
};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<const Type>: ReturnValue<Type> {};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<volatile Type>: ReturnValue<Type> {};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<const volatile Type>: ReturnValue<Type> {};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<Type&>: ReturnValue<Type> {};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<Type&&>: ReturnValue<Type> {};

LUWRA_NS_END

#endif
<commit_msg>Make 'InferValueType' conversion operators as inline<commit_after>/* Luwra
 * Minimal-overhead Lua wrapper for C++
 *
 * Copyright (C) 2015, Ole Krüger <ole@vprsm.de>
 */

#ifndef LUWRA_VALUES_H_
#define LUWRA_VALUES_H_

#include "common.hpp"
#include "internal/indexsequence.hpp"

#include <utility>
#include <string>

LUWRA_NS_BEGIN

template <typename UserType>
struct Value;

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<const Type>: Value<Type> {};

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<volatile Type>: Value<Type> {};

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<const volatile Type>: Value<Type> {};

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<Type&>: Value<Type> {};

/// Alias for @ref Value<Type>
template <typename Type>
struct Value<Type&&>: Value<Type> {};

namespace internal {
	struct InferValueType {
		State* state;
		int index;

		template <typename Type> inline
		operator Type() const && {
			return Value<Type>::read(state, index);
		}

		template <typename Type> inline
		operator Type&() const & {
			return Value<Type&>::read(state, index);
		}
	};
}

/// Enables reading of type-infered values
template <>
struct Value<internal::InferValueType> {
	static inline
	const internal::InferValueType read(State* state, int index) {
		return {state, index};
	}
};

/// Enables reading/pushing `nil`
template <>
struct Value<std::nullptr_t> {
	static inline
	std::nullptr_t read(State* state, int n) {
		luaL_checktype(state, n, LUA_TNIL);
		return nullptr;
	}

	static inline
	void push(State* state, std::nullptr_t) {
		lua_pushnil(state);
	}
};

/// Enables reading Lua threads
template <>
struct Value<State*> {
	static inline
	State* read(State* state, int n) {
		luaL_checktype(state, n, LUA_TTHREAD);
		return lua_tothread(state, n);
	}
};

/// Enables reading/pushing light data
template <>
struct Value<void*> {
	static inline
	void* read(State* state, int n) {
		luaL_checktype(state, n, LUA_TLIGHTUSERDATA);
		return lua_touserdata(state, n);
	}

	static inline
	void push(State* state, void* data) {
		lua_pushlightuserdata(state, data);
	}
};

/// Enables reading constant light data
template <>
struct Value<const void*> {
	static inline
	const void* read(State* state, int n) {
		luaL_checktype(state, n, LUA_TLIGHTUSERDATA);
		return lua_touserdata(state, n);
	}
};

namespace internal {
	template <typename Type>
	struct NumericTransportValue {
		static_assert(
			sizeof(Type) == -1,
			"Parameter to NumericTransportValue is not a numeric base type"
		);
	};

	// Transport unit `Integer`
	template <>
	struct NumericTransportValue<Integer> {
		static inline
		Integer read(State* state, int index) {
			return luaL_checkinteger(state, index);
		}

		static inline
		void push(State* state, Integer value) {
			lua_pushinteger(state, value);
		}
	};

	// Transport unit `Number`
	template <>
	struct NumericTransportValue<Number> {
		static inline
		Number read(State* state, int index) {
			return luaL_checknumber(state, index);
		}

		static inline
		void push(State* state, Number value) {
			lua_pushnumber(state, value);
		}
	};

	// Base for `Value<Type>` specializations which uses `Transport` as transport unit
	template <typename Type, typename Transport>
	struct NumericValueBase {
		static inline
		Type read(State* state, int index) {
			return static_cast<Type>(NumericTransportValue<Transport>::read(state, index));
		}

		static inline
		void push(State* state, Type value) {
			NumericTransportValue<Transport>::push(state, static_cast<Transport>(value));
		}
	};
}

// Define an integral type which will be transported via `base`.
#define LUWRA_DEF_NUMERIC(base, type) \
	template <> \
	struct Value<type>: internal::NumericValueBase<type, base> {};

// Lua-dependent types
LUWRA_DEF_NUMERIC(Number, float)
LUWRA_DEF_NUMERIC(Number, double)
LUWRA_DEF_NUMERIC(Number, long double)

// Integral types
LUWRA_DEF_NUMERIC(Integer, signed   char)
LUWRA_DEF_NUMERIC(Integer, unsigned char)
LUWRA_DEF_NUMERIC(Integer, signed   short)
LUWRA_DEF_NUMERIC(Integer, unsigned short)
LUWRA_DEF_NUMERIC(Integer, signed   int)
LUWRA_DEF_NUMERIC(Integer, unsigned int)
LUWRA_DEF_NUMERIC(Integer, signed   long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long int)
LUWRA_DEF_NUMERIC(Integer, signed   long long int)
LUWRA_DEF_NUMERIC(Integer, unsigned long long int)

// Do not export this macros
#undef LUWRA_DEF_NUMERIC

/// Enables reading/pushing strings as C strings
template <>
struct Value<const char*> {
	static inline
	const char* read(State* state, int n) {
		return luaL_checkstring(state, n);
	}

	static inline
	void push(State* state, const char* value) {
		lua_pushstring(state, value);
	}
};

/// Enables reading/pushing string as `std::string`.
template <>
struct Value<std::string> {
	static inline
	std::string read(State* state, int n) {
		size_t length;
		const char* value = luaL_checklstring(state, n, &length);
		return {value, length};
	}

	static inline
	void push(State* state, const std::string& value) {
		lua_pushstring(state, value.c_str());
	}
};

/// Enables reading/pushing booleans
template <>
struct Value<bool> {
	static inline
	bool read(State* state, int n) {
		luaL_checktype(state, n, LUA_TBOOLEAN);
		return lua_toboolean(state, n) == 1;
	}

	static inline
	void push(State* state, bool value) {
		lua_pushboolean(state, static_cast<int>(value));
	}
};

/// Alias for @ref Value<const char*>
template <>
struct Value<char*>: Value<const char*> {};

/// Alias for @ref Value<const char*>
template <size_t N>
struct Value<char[N]>: Value<const char*> {};

/// Alias for @ref Value<const char*>
template <size_t N>
struct Value<const char[N]>: Value<const char*> {};

/// A version of @ref Value for pushing return values onto the stack. @ref ReturnValue inherits
/// `push` implementations from @ref Value.
template <typename Type>
struct ReturnValue {
	template <typename... Args> static inline
	size_t push(State* state, Args&&... args) {
		Value<Type>::push(state, std::forward<Args>(args)...);
		return 1;
	}
};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<const Type>: ReturnValue<Type> {};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<volatile Type>: ReturnValue<Type> {};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<const volatile Type>: ReturnValue<Type> {};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<Type&>: ReturnValue<Type> {};

/// Alias for `ReturnValue<Type>`
template <typename Type>
struct ReturnValue<Type&&>: ReturnValue<Type> {};

LUWRA_NS_END

#endif
<|endoftext|>


<commit_before>#include "Memory.h"

#include <vector>
#include <iostream>
#include <iomanip>
#include <cstdint>
#include <cassert>

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>

#include <libdevcore/Common.h>

#include "Type.h"
#include "Runtime.h"
#include "GasMeter.h"
#include "Endianness.h"
#include "Runtime.h"

namespace dev
{
namespace eth
{
namespace jit
{

Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
	RuntimeHelper(_runtimeManager)
{
	auto module = getModule();
	auto i64Ty = m_builder.getInt64Ty();
	llvm::Type* argTypes[] = {i64Ty, i64Ty};
	auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false);
	m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
									   "evmccrt_memory_dump", module);

	m_data = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data");
	m_data->setUnnamedAddr(true); // Address is not important

	m_size = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size");
	m_size->setUnnamedAddr(true); // Address is not important

	llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr};
	m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module);
	llvm::AttrBuilder attrBuilder;
	attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
	m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder));

	m_require = createRequireFunc(_gasMeter, _runtimeManager);
	m_loadWord = createFunc(false, Type::i256, _gasMeter);
	m_storeWord = createFunc(true, Type::i256, _gasMeter);
	m_storeByte = createFunc(true, Type::Byte,  _gasMeter);
}

llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager)
{
	auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", getModule());

	auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func);
	auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func);
	auto returnBB = llvm::BasicBlock::Create(func->getContext(), "return", func);

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	// BB "check"
	m_builder.SetInsertPoint(checkBB);
	llvm::Value* sizeRequired = func->arg_begin();
	sizeRequired->setName("sizeRequired");
	auto size = m_builder.CreateLoad(m_size, "size");
	auto resizeNeeded = m_builder.CreateICmpULE(size, sizeRequired, "resizeNeeded");
	m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?

	// BB "resize"
	m_builder.SetInsertPoint(resizeBB);
	// Check gas first
	auto wordsRequired = m_builder.CreateUDiv(m_builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired");
	auto words = m_builder.CreateUDiv(m_builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words");
	auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
	_gasMeter.checkMemory(newWords, m_builder);
	// Resize
	m_builder.CreateStore(sizeRequired, m_size);
	auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData");
	m_builder.CreateStore(newData, m_data);
	m_builder.CreateBr(returnBB);

	// BB "return"
	m_builder.SetInsertPoint(returnBB);
	m_builder.CreateRetVoid();
	return func;
}

llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&)
{
	auto isWord = _valueType == Type::i256;

	llvm::Type* storeArgs[] = {Type::i256, _valueType};
	auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
	auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false);
	auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
	llvm::Value* index = func->arg_begin();
	index->setName("index");

	auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
	this->require(index, Constant::get(valueSize));
	auto data = m_builder.CreateLoad(m_data, "data");
	auto ptr = m_builder.CreateGEP(data, index, "ptr");
	if (isWord)
		ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
	if (_isStore)
	{
		llvm::Value* value = ++func->arg_begin();
		value->setName("value");
		if (isWord)
			value = Endianness::toBE(m_builder, value);
		m_builder.CreateStore(value, ptr);
		m_builder.CreateRetVoid();
	}
	else
	{
		llvm::Value* ret = m_builder.CreateLoad(ptr);
		ret = Endianness::toNative(m_builder, ret);
		m_builder.CreateRet(ret);
	}

	return func;
}

llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
	auto value = m_builder.CreateCall(m_loadWord, _addr);

	dump(0);
	return value;
}

void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
	m_builder.CreateCall2(m_storeWord, _addr, _word);

	dump(0);
}

void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
	auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
	m_builder.CreateCall2(m_storeByte, _addr, byte);

	dump(0);
}

llvm::Value* Memory::getData()
{
	return m_builder.CreateLoad(m_data);
}

llvm::Value* Memory::getSize()
{
	return m_builder.CreateLoad(m_size);
}

void Memory::require(llvm::Value* _size)
{
	m_builder.CreateCall(m_require, _size);
}

void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
	auto sizeRequired = m_builder.CreateAdd(_offset, _size, "sizeRequired");
	require(sizeRequired);
}

void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
					   llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
{
	auto zero256 = llvm::ConstantInt::get(Type::i256, 0);

	auto reqMemSize = m_builder.CreateAdd(_destMemIdx, _reqBytes, "req_mem_size");
	require(reqMemSize);

	auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx");

	auto memPtr = getData();
	auto destPtr = m_builder.CreateGEP(memPtr, _destMemIdx, "dest_mem_ptr");

	// remaining source bytes:
	auto remSrcSize = m_builder.CreateSub(_srcSize, _srcIdx);
	auto remSizeNegative = m_builder.CreateICmpSLT(remSrcSize, zero256);
	auto remSrcBytes = m_builder.CreateSelect(remSizeNegative, zero256, remSrcSize, "rem_src_bytes");

	auto tooFewSrcBytes = m_builder.CreateICmpULT(remSrcBytes, _reqBytes);
	auto bytesToCopy = m_builder.CreateSelect(tooFewSrcBytes, remSrcBytes, _reqBytes, "bytes_to_copy");

	m_builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0);
}

void Memory::dump(uint64_t _begin, uint64_t _end)
{
	if (getenv("EVMCC_DEBUG_MEMORY") == nullptr)
		return;

	auto beginVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _begin);
	auto endVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _end);

	std::vector<llvm::Value*> args = {beginVal, endVal};
	m_builder.CreateCall(m_memDump, llvm::ArrayRef<llvm::Value*>(args));
}

}
}
}

extern "C"
{

	using namespace dev::eth::jit;

	EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size)
	{
		auto size = _size->a; // Trunc to 64-bit
		auto& memory = _rt->getMemory();
		memory.resize(size);
		return memory.data();
	}

}   // extern "C"
<commit_msg>Fix MSIZE and memory resize step [Delivers #81777708]<commit_after>#include "Memory.h"

#include <vector>
#include <iostream>
#include <iomanip>
#include <cstdint>
#include <cassert>

#include <llvm/IR/GlobalVariable.h>
#include <llvm/IR/Function.h>

#include <libdevcore/Common.h>

#include "Type.h"
#include "Runtime.h"
#include "GasMeter.h"
#include "Endianness.h"
#include "Runtime.h"

namespace dev
{
namespace eth
{
namespace jit
{

Memory::Memory(RuntimeManager& _runtimeManager, GasMeter& _gasMeter):
	RuntimeHelper(_runtimeManager)
{
	auto module = getModule();
	auto i64Ty = m_builder.getInt64Ty();
	llvm::Type* argTypes[] = {i64Ty, i64Ty};
	auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false);
	m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
									   "evmccrt_memory_dump", module);

	m_data = new llvm::GlobalVariable(*module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data");
	m_data->setUnnamedAddr(true); // Address is not important

	m_size = new llvm::GlobalVariable(*module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(0), "mem.size");
	m_size->setUnnamedAddr(true); // Address is not important

	llvm::Type* resizeArgs[] = {Type::RuntimePtr, Type::WordPtr};
	m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, resizeArgs, false), llvm::Function::ExternalLinkage, "mem_resize", module);
	llvm::AttrBuilder attrBuilder;
	attrBuilder.addAttribute(llvm::Attribute::NoAlias).addAttribute(llvm::Attribute::NoCapture).addAttribute(llvm::Attribute::NonNull).addAttribute(llvm::Attribute::ReadOnly);
	m_resize->setAttributes(llvm::AttributeSet::get(m_resize->getContext(), 1, attrBuilder));

	m_require = createRequireFunc(_gasMeter, _runtimeManager);
	m_loadWord = createFunc(false, Type::i256, _gasMeter);
	m_storeWord = createFunc(true, Type::i256, _gasMeter);
	m_storeByte = createFunc(true, Type::Byte,  _gasMeter);
}

llvm::Function* Memory::createRequireFunc(GasMeter& _gasMeter, RuntimeManager& _runtimeManager)
{
	auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::i256, false), llvm::Function::PrivateLinkage, "mem.require", getModule());

	auto checkBB = llvm::BasicBlock::Create(func->getContext(), "check", func);
	auto resizeBB = llvm::BasicBlock::Create(func->getContext(), "resize", func);
	auto returnBB = llvm::BasicBlock::Create(func->getContext(), "return", func);

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	// BB "check"
	m_builder.SetInsertPoint(checkBB);
	llvm::Value* sizeRequired = func->arg_begin();
	sizeRequired->setName("sizeRequired");
	auto size = m_builder.CreateLoad(m_size, "size");
	auto resizeNeeded = m_builder.CreateICmpULE(size, sizeRequired, "resizeNeeded");
	m_builder.CreateCondBr(resizeNeeded, resizeBB, returnBB); // OPT branch weights?

	// BB "resize"
	m_builder.SetInsertPoint(resizeBB);
	// Check gas first
	auto wordsRequired = m_builder.CreateUDiv(m_builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired");
	sizeRequired = m_builder.CreateMul(wordsRequired, Constant::get(32), "roundedSizeRequired");
	auto words = m_builder.CreateUDiv(size, Constant::get(32), "words");	// size is always 32*k
	auto newWords = m_builder.CreateSub(wordsRequired, words, "addtionalWords");
	_gasMeter.checkMemory(newWords, m_builder);
	// Resize
	m_builder.CreateStore(sizeRequired, m_size);
	auto newData = m_builder.CreateCall2(m_resize, _runtimeManager.getRuntimePtr(), m_size, "newData");
	m_builder.CreateStore(newData, m_data);
	m_builder.CreateBr(returnBB);

	// BB "return"
	m_builder.SetInsertPoint(returnBB);
	m_builder.CreateRetVoid();
	return func;
}

llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, GasMeter&)
{
	auto isWord = _valueType == Type::i256;

	llvm::Type* storeArgs[] = {Type::i256, _valueType};
	auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
	auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::i256, Type::i256, false);
	auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());

	InsertPointGuard guard(m_builder); // Restores insert point at function exit

	m_builder.SetInsertPoint(llvm::BasicBlock::Create(func->getContext(), {}, func));
	llvm::Value* index = func->arg_begin();
	index->setName("index");

	auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
	this->require(index, Constant::get(valueSize));
	auto data = m_builder.CreateLoad(m_data, "data");
	auto ptr = m_builder.CreateGEP(data, index, "ptr");
	if (isWord)
		ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
	if (_isStore)
	{
		llvm::Value* value = ++func->arg_begin();
		value->setName("value");
		if (isWord)
			value = Endianness::toBE(m_builder, value);
		m_builder.CreateStore(value, ptr);
		m_builder.CreateRetVoid();
	}
	else
	{
		llvm::Value* ret = m_builder.CreateLoad(ptr);
		ret = Endianness::toNative(m_builder, ret);
		m_builder.CreateRet(ret);
	}

	return func;
}

llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
	auto value = m_builder.CreateCall(m_loadWord, _addr);

	dump(0);
	return value;
}

void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
	m_builder.CreateCall2(m_storeWord, _addr, _word);

	dump(0);
}

void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
	auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
	m_builder.CreateCall2(m_storeByte, _addr, byte);

	dump(0);
}

llvm::Value* Memory::getData()
{
	return m_builder.CreateLoad(m_data);
}

llvm::Value* Memory::getSize()
{
	return m_builder.CreateLoad(m_size);
}

void Memory::require(llvm::Value* _size)
{
	m_builder.CreateCall(m_require, _size);
}

void Memory::require(llvm::Value* _offset, llvm::Value* _size)
{
	auto sizeRequired = m_builder.CreateAdd(_offset, _size, "sizeRequired");
	require(sizeRequired);
}

void Memory::copyBytes(llvm::Value* _srcPtr, llvm::Value* _srcSize, llvm::Value* _srcIdx,
					   llvm::Value* _destMemIdx, llvm::Value* _reqBytes)
{
	auto zero256 = llvm::ConstantInt::get(Type::i256, 0);

	auto reqMemSize = m_builder.CreateAdd(_destMemIdx, _reqBytes, "req_mem_size");
	require(reqMemSize);

	auto srcPtr = m_builder.CreateGEP(_srcPtr, _srcIdx, "src_idx");

	auto memPtr = getData();
	auto destPtr = m_builder.CreateGEP(memPtr, _destMemIdx, "dest_mem_ptr");

	// remaining source bytes:
	auto remSrcSize = m_builder.CreateSub(_srcSize, _srcIdx);
	auto remSizeNegative = m_builder.CreateICmpSLT(remSrcSize, zero256);
	auto remSrcBytes = m_builder.CreateSelect(remSizeNegative, zero256, remSrcSize, "rem_src_bytes");

	auto tooFewSrcBytes = m_builder.CreateICmpULT(remSrcBytes, _reqBytes);
	auto bytesToCopy = m_builder.CreateSelect(tooFewSrcBytes, remSrcBytes, _reqBytes, "bytes_to_copy");

	m_builder.CreateMemCpy(destPtr, srcPtr, bytesToCopy, 0);
}

void Memory::dump(uint64_t _begin, uint64_t _end)
{
	if (getenv("EVMCC_DEBUG_MEMORY") == nullptr)
		return;

	auto beginVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _begin);
	auto endVal = llvm::ConstantInt::get(m_builder.getInt64Ty(), _end);

	std::vector<llvm::Value*> args = {beginVal, endVal};
	m_builder.CreateCall(m_memDump, llvm::ArrayRef<llvm::Value*>(args));
}

}
}
}

extern "C"
{

	using namespace dev::eth::jit;

	EXPORT uint8_t* mem_resize(Runtime* _rt, i256* _size)
	{
		auto size = _size->a; // Trunc to 64-bit
		auto& memory = _rt->getMemory();
		memory.resize(size);
		return memory.data();
	}

}   // extern "C"
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "ProcessInfoProvider.h"

class Handle;

ProcessInfoProvider::ProcessInfoProvider()
{
}

ProcessInfoProvider::~ProcessInfoProvider()
{
}

typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
bool ProcessInfoProvider::IsWow64() const
{
	int bIsWow64 = false;
	LPFN_ISWOW64PROCESS fnIsWow64Process;
	fnIsWow64Process = reinterpret_cast<LPFN_ISWOW64PROCESS>(GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"));
	if (NULL != fnIsWow64Process)
	{
		if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
		{
			return false;
		}
	}

	return bIsWow64 != 0;
}

bool ProcessInfoProvider::IsSuitableOS() const
{
#if defined(_M_X64) || defined(x86_64)
#else
	if (Is64OS())
	{
		return false;
	}
#endif

	return true;
}
<commit_msg>Fix build<commit_after>#include "stdafx.h"
#include "ProcessInfoProvider.h"

class Handle;

ProcessInfoProvider::ProcessInfoProvider()
{
}

ProcessInfoProvider::~ProcessInfoProvider()
{
}

typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
bool ProcessInfoProvider::IsWow64() const
{
	int bIsWow64 = false;
	LPFN_ISWOW64PROCESS fnIsWow64Process;
	fnIsWow64Process = reinterpret_cast<LPFN_ISWOW64PROCESS>(GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"));
	if (NULL != fnIsWow64Process)
	{
		if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
		{
			return false;
		}
	}

	return bIsWow64 != 0;
}

bool ProcessInfoProvider::IsSuitableOS() const
{
#if defined(_M_X64) || defined(x86_64)
#else
	if (Is64OS())
	{
		return false;
	}
#endif

	return true;
}

bool ProcessInfoProvider::Is64OS() const
{
#if defined(_M_X64) || defined(x86_64)
	return true;
#else
	return IsWow64() == true;
#endif
}<|endoftext|>


<commit_before>//--------------------------------------------------------------
//-- Oscillator.pde
//-- Generate sinusoidal oscillations in the servos
//--------------------------------------------------------------
//-- (c) Juan Gonzalez-Gomez (Obijuan), Dec 2011
//-- GPL license
//--------------------------------------------------------------
#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
  #include <pins_arduino.h>
#endif
#include "Oscillator.h"
#include <Servo.h>

//-- This function returns true if another sample
//-- should be taken (i.e. the TS time has passed since
//-- the last sample was taken
bool Oscillator::next_sample()
{

  //-- Read current time
  _currentMillis = millis();

  //-- Check if the timeout has passed
  if(_currentMillis - _previousMillis > _TS) {
    _previousMillis = _currentMillis;

    return true;
  }

  return false;
}

//-- Attach an oscillator to a servo
//-- Input: pin is the arduino pin were the servo
//-- is connected
void Oscillator::attach(int pin, bool rev)
{
  //-- If the oscillator is detached, attach it.
  if(!_servo.attached()){

    //-- Attach the servo and move it to the home position
      _servo.attach(pin);
      _servo.write(90);

      //-- Initialization of oscilaltor parameters
      _TS=30;
      _T=2000;
      _N = _T/_TS;
      _inc = 2*M_PI/_N;

      _previousMillis=0;

      //-- Default parameters
      _A=45;
      _phase=0;
      _phase0=0;
      _O=0;
      _stop=false;

      //-- Reverse mode
      _rev = rev;
  }

}

//-- Detach an oscillator from his servo
void Oscillator::detach()
{
   //-- If the oscillator is attached, detach it.
  if(_servo.attached())
        _servo.detach();

}

/*************************************/
/* Set the oscillator period, in ms  */
/*************************************/
void Oscillator::SetT(unsigned int T)
{
  //-- Assign the new period
  _T=T;

  //-- Recalculate the parameters
  _N = _T/_TS;
  _inc = 2*M_PI/_N;
};

/*******************************/
/* Manual set of the position  */
/******************************/

void Oscillator::SetPosition(int position)
{
  _servo.write(position+_trim);
};

/*******************************************************************/
/* This function should be periodically called                     */
/* in order to maintain the oscillations. It calculates            */
/* if another sample should be taken and position the servo if so  */
/*******************************************************************/
void Oscillator::refresh()
{

  //-- Only When TS milliseconds have passed, the new sample is obtained
  if (next_sample()) {

      //-- If the oscillator is not stopped, calculate the servo position
      if (!_stop) {
        //-- Sample the sine function and set the servo pos
         _pos = round(_A * sin(_phase + _phase0) + _O);
	       if (_rev) _pos=-_pos;
         _servo.write(_pos+90+_trim);
      }

      //-- Increment the phase
      //-- It is always increased, even when the oscillator is stop
      //-- so that the coordination is always kept
      _phase = _phase + _inc;

  }
}
<commit_msg>Delete Oscillator.cpp<commit_after><|endoftext|>