<commit_before>/*
 * Copyright (C) 2008-2010, <NAME>.
 *
 * 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.
 */

/**
 ** \file object/system.cc
 ** \brief Creation of the Urbi object system.
 */

//#define ENABLE_DEBUG_TRACES
#include <libport/config.h>
#include <libport/asio.hh>
#include <libport/compiler.hh>
#include <libport/cstdlib>
#include <libport/format.hh>
#include <libport/program-name.hh>
#include <libport/xltdl.hh>

#include <libport/cerrno>
#include <memory>
#include <sstream>

#include <kernel/uconnection.hh>
#include <kernel/uobject.hh>
#include <kernel/userver.hh>

#include <urbi/object/code.hh>
#include <urbi/object/cxx-primitive.hh>
#include <urbi/object/dictionary.hh>
#include <urbi/object/float.hh>
#include <urbi/object/global.hh>
#include <urbi/object/list.hh>
#include <urbi/object/path.hh>
#include <object/symbols.hh>
#include <object/system.hh>
#include <urbi/object/tag.hh>
#include <urbi/object/job.hh>
#include <parser/transform.hh>
#include <runner/interpreter.hh>
#include <urbi/runner/raise.hh>
#include <runner/runner.hh>

#include <ast/nary.hh>
#include <ast/routine.hh>

namespace urbi
{
  namespace object
  {

    using ::kernel::interpreter;
    using ::kernel::runner;

    // Extract a filename from a String or a Path object
    static std::string
    filename_get(const rObject& o)
    {
      if (o.is_a<Path>())
        return o->as<Path>()->as_string();
      type_check<String>(o);
      return o->as<String>()->value_get();
    }

    /// \param context  if there is an error message, the string to display.
    rObject
    execute_parsed(parser::parse_result_type p,
                   libport::Symbol fun, const std::string& context)
    {
      runner::Interpreter& run = interpreter();
      // Report errors.
      if (ast::rError errs = p->errors_get())
      {
        // Steal the errors from the ParseResult.  It is tailored to
        // abort if there are some errors that were not reported to
        // the user, which is what we are doing now.
        ast::Error::messages_type ms;
        std::swap(ms, errs->errors_get());
        // FIXME: Yes, we actually raise only the first error.
        foreach (const ast::Error::message_type& s, ms)
          runner::raise_syntax_error(s.first, s.second, context);
      }

      ast::rConstAst ast = parser::transform(p->ast_get());
      if (!ast)
        RAISE(context);

      runner::Interpreter* sub = new runner::Interpreter(run, ast, fun);
      // So that it will resist to the call to yield_until_terminated,
      // and will be reclaimed at the end of the scope.
      sched::rJob job = sub;
      sched::Job::Collector collector(&run);
      run.register_child(sub, collector);
      sub->start_job();
      try
      {
        run.yield_until_terminated(*job);
      }
      catch (const sched::ChildException& ce)
      {
        // Kill the sub-job and propagate.
        ce.rethrow_child_exception();
      }
      return sub->result_get();
    }


    rObject system_class;

    /*--------------------.
    | System primitives.  |
    `--------------------*/


#define SERVER_FUNCTION(Function)               \
    static void                                 \
    system_ ## Function()                       \
    {                                           \
      ::kernel::urbiserver->Function();         \
    }

    SERVER_FUNCTION(reboot)
    SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION


    static void
    system_sleep(const rObject&, libport::ufloat seconds)
    {
      runner::Runner& r = runner();
      if (seconds == std::numeric_limits<ufloat>::infinity())
        r.yield_until_terminated(r);
      else
        r.yield_until(r.scheduler_get().get_time()
                      + static_cast<libport::utime_t>(seconds * 1000000.0));
    }

    static float
    system_time()
    {
      return ::kernel::scheduler().get_time() / 1000000.0;
    }

    static float
    system_shiftedTime()
    {
      runner::Runner& r = runner();
      return (r.scheduler_get().get_time() - r.time_shift_get()) / 1000000.0;
    }

    static rObject
    system_eval(const rObject&, const std::string& code)
    {
      return execute_parsed(parser::parse(code, ast::loc()),
                            SYMBOL(eval), code);
    }

    static rObject
    system_searchFile(const rObject&, const rObject& f)
    {
      const std::string& filename = filename_get(f);
      try
      {
        return new Path(::kernel::urbiserver->find_file(filename));
      }
      catch (libport::file_library::Not_found&)
      {
        runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
        // Never reached
        aver(false);
        return 0;
      }
    }

    static List::value_type
    system_searchPath()
    {
      List::value_type res;
      foreach (const libport::path& p,
               ::kernel::urbiserver->search_path.search_path_get())
        res << new Path(p);
      return res;
    }

    static rObject
    system_loadFile(const rObject&, const rObject& f)
    {
      const std::string& filename = filename_get(f);
#if defined ENABLE_SERIALIZATION
      if (!libport::path(filename).exists())
        runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
#endif
      return execute_parsed(parser::parse_file(filename),
                            SYMBOL(loadFile), filename);
    }

    static rObject
    system_currentRunner()
    {
      return runner().as_job();
    }

    static float
    system_cycle()
    {
      return ::kernel::scheduler().cycle_get();
    }

    static void
    system_nonInterruptible()
    {
      runner().non_interruptible_set(true);
    }

    static rObject
    system_spawn(const rObject&,
                 const rCode& code,
                 const rObject& clear_tags)
    {
      runner::Runner& r = runner();
      runner::Interpreter* new_runner =
        new runner::Interpreter(interpreter(),
                                rObject(code),
                                libport::Symbol::fresh(r.name_get()));

      if (clear_tags->as_bool())
        new_runner->tag_stack_clear();

      new_runner->time_shift_set(r.time_shift_get());
      new_runner->start_job();
      return new_runner->as_job();
    }

    static rObject
    system_stats()
    {
      const sched::scheduler_stats_type& stats =
        ::kernel::scheduler().stats_get();

      // If statistics have just been reset, return "nil" since we cannot
      // return anything significant.
      if (stats.empty())
        return nil_class;

      // The space after "Symbol(" is mandatory to avoid triggering an error in
      // symbol generation code
      Dictionary::value_type res;
#define ADDSTAT(Suffix, Function, Divisor)      \
      res[libport::Symbol("cycles" # Suffix)] = \
        new Float(stats.Function() / Divisor)
      ADDSTAT(, size, 1);
      ADDSTAT(Max, max, 1e6);
      ADDSTAT(Mean, mean, 1e6);
      ADDSTAT(Min, min, 1e6);
      ADDSTAT(StdDev, standard_deviation, 1e6);
      ADDSTAT(Variance, variance, 1e3);
#undef ADDSTAT
      return new Dictionary(res);
    }

    static void
    system_resetStats()
    {
      ::kernel::scheduler().stats_reset();
    }

    // This should give a backtrace as an urbi object.
    static void
    system_backtrace()
    {
      // FIXME: This method sucks a bit, because show_backtrace sucks a
      // bit, because our channeling/message-sending system sucks a lot.
      runner::Runner::backtrace_type bt = runner().backtrace_get();
      bt.pop_back();
      rforeach (const runner::Runner::frame_type& elt, bt)
      {
        std::ostringstream o;
        o << *elt->slot_get(SYMBOL(name))->call(SYMBOL(asString))
          << " ("
          << *elt->slot_get(SYMBOL(location))->call(SYMBOL(asString))
          << ")";
        // o << *elt->call(SYMBOL(asString));
        runner().send_message("backtrace", o.str());
      }
    }

    static List::value_type
    system_jobs()
    {
      List::value_type res;
      foreach(sched::rJob job, ::kernel::scheduler().jobs_get())
        res.push_back(dynamic_cast<runner::Runner*>(job.get())->as_job());
      return res;
    }

    static int
    system_aliveJobs()
    {
      return sched::Job::alive_jobs();
    }

    static void
    system_breakpoint()
    {
      return;
    }

#define SERVER_SET_VAR(Function, Variable, Value)       \
    static void                                         \
    system_ ## Function ()                              \
    {                                                   \
      ::kernel::urbiserver->Variable = Value;           \
    }

    SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

    static rObject
    system_getenv(const rObject&, const std::string& name)
    {
      char* res = getenv(name.c_str());
      return res ? new String(res) : nil_class;<commit_msg>System.jobs: filter out sched::jobs that are not urbi objects.<commit_after>/*
 * Copyright (C) 2008-2010, <NAME>.
 *
 * 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.
 */

/**
 ** \file object/system.cc
 ** \brief Creation of the Urbi object system.
 */

//#define ENABLE_DEBUG_TRACES
#include <libport/config.h>
#include <libport/asio.hh>
#include <libport/compiler.hh>
#include <libport/cstdlib>
#include <libport/format.hh>
#include <libport/program-name.hh>
#include <libport/xltdl.hh>

#include <libport/cerrno>
#include <memory>
#include <sstream>

#include <kernel/uconnection.hh>
#include <kernel/uobject.hh>
#include <kernel/userver.hh>

#include <urbi/object/code.hh>
#include <urbi/object/cxx-primitive.hh>
#include <urbi/object/dictionary.hh>
#include <urbi/object/float.hh>
#include <urbi/object/global.hh>
#include <urbi/object/list.hh>
#include <urbi/object/path.hh>
#include <object/symbols.hh>
#include <object/system.hh>
#include <urbi/object/tag.hh>
#include <urbi/object/job.hh>
#include <parser/transform.hh>
#include <runner/interpreter.hh>
#include <urbi/runner/raise.hh>
#include <runner/runner.hh>

#include <ast/nary.hh>
#include <ast/routine.hh>

namespace urbi
{
  namespace object
  {

    using ::kernel::interpreter;
    using ::kernel::runner;

    // Extract a filename from a String or a Path object
    static std::string
    filename_get(const rObject& o)
    {
      if (o.is_a<Path>())
        return o->as<Path>()->as_string();
      type_check<String>(o);
      return o->as<String>()->value_get();
    }

    /// \param context  if there is an error message, the string to display.
    rObject
    execute_parsed(parser::parse_result_type p,
                   libport::Symbol fun, const std::string& context)
    {
      runner::Interpreter& run = interpreter();
      // Report errors.
      if (ast::rError errs = p->errors_get())
      {
        // Steal the errors from the ParseResult.  It is tailored to
        // abort if there are some errors that were not reported to
        // the user, which is what we are doing now.
        ast::Error::messages_type ms;
        std::swap(ms, errs->errors_get());
        // FIXME: Yes, we actually raise only the first error.
        foreach (const ast::Error::message_type& s, ms)
          runner::raise_syntax_error(s.first, s.second, context);
      }

      ast::rConstAst ast = parser::transform(p->ast_get());
      if (!ast)
        RAISE(context);

      runner::Interpreter* sub = new runner::Interpreter(run, ast, fun);
      // So that it will resist to the call to yield_until_terminated,
      // and will be reclaimed at the end of the scope.
      sched::rJob job = sub;
      sched::Job::Collector collector(&run);
      run.register_child(sub, collector);
      sub->start_job();
      try
      {
        run.yield_until_terminated(*job);
      }
      catch (const sched::ChildException& ce)
      {
        // Kill the sub-job and propagate.
        ce.rethrow_child_exception();
      }
      return sub->result_get();
    }


    rObject system_class;

    /*--------------------.
    | System primitives.  |
    `--------------------*/


#define SERVER_FUNCTION(Function)               \
    static void                                 \
    system_ ## Function()                       \
    {                                           \
      ::kernel::urbiserver->Function();         \
    }

    SERVER_FUNCTION(reboot)
    SERVER_FUNCTION(shutdown)

#undef SERVER_FUNCTION


    static void
    system_sleep(const rObject&, libport::ufloat seconds)
    {
      runner::Runner& r = runner();
      if (seconds == std::numeric_limits<ufloat>::infinity())
        r.yield_until_terminated(r);
      else
        r.yield_until(r.scheduler_get().get_time()
                      + static_cast<libport::utime_t>(seconds * 1000000.0));
    }

    static float
    system_time()
    {
      return ::kernel::scheduler().get_time() / 1000000.0;
    }

    static float
    system_shiftedTime()
    {
      runner::Runner& r = runner();
      return (r.scheduler_get().get_time() - r.time_shift_get()) / 1000000.0;
    }

    static rObject
    system_eval(const rObject&, const std::string& code)
    {
      return execute_parsed(parser::parse(code, ast::loc()),
                            SYMBOL(eval), code);
    }

    static rObject
    system_searchFile(const rObject&, const rObject& f)
    {
      const std::string& filename = filename_get(f);
      try
      {
        return new Path(::kernel::urbiserver->find_file(filename));
      }
      catch (libport::file_library::Not_found&)
      {
        runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
        // Never reached
        aver(false);
        return 0;
      }
    }

    static List::value_type
    system_searchPath()
    {
      List::value_type res;
      foreach (const libport::path& p,
               ::kernel::urbiserver->search_path.search_path_get())
        res << new Path(p);
      return res;
    }

    static rObject
    system_loadFile(const rObject&, const rObject& f)
    {
      const std::string& filename = filename_get(f);
#if defined ENABLE_SERIALIZATION
      if (!libport::path(filename).exists())
        runner::raise_urbi(SYMBOL(FileNotFound), to_urbi(filename));
#endif
      return execute_parsed(parser::parse_file(filename),
                            SYMBOL(loadFile), filename);
    }

    static rObject
    system_currentRunner()
    {
      return runner().as_job();
    }

    static float
    system_cycle()
    {
      return ::kernel::scheduler().cycle_get();
    }

    static void
    system_nonInterruptible()
    {
      runner().non_interruptible_set(true);
    }

    static rObject
    system_spawn(const rObject&,
                 const rCode& code,
                 const rObject& clear_tags)
    {
      runner::Runner& r = runner();
      runner::Interpreter* new_runner =
        new runner::Interpreter(interpreter(),
                                rObject(code),
                                libport::Symbol::fresh(r.name_get()));

      if (clear_tags->as_bool())
        new_runner->tag_stack_clear();

      new_runner->time_shift_set(r.time_shift_get());
      new_runner->start_job();
      return new_runner->as_job();
    }

    static rObject
    system_stats()
    {
      const sched::scheduler_stats_type& stats =
        ::kernel::scheduler().stats_get();

      // If statistics have just been reset, return "nil" since we cannot
      // return anything significant.
      if (stats.empty())
        return nil_class;

      // The space after "Symbol(" is mandatory to avoid triggering an error in
      // symbol generation code
      Dictionary::value_type res;
#define ADDSTAT(Suffix, Function, Divisor)      \
      res[libport::Symbol("cycles" # Suffix)] = \
        new Float(stats.Function() / Divisor)
      ADDSTAT(, size, 1);
      ADDSTAT(Max, max, 1e6);
      ADDSTAT(Mean, mean, 1e6);
      ADDSTAT(Min, min, 1e6);
      ADDSTAT(StdDev, standard_deviation, 1e6);
      ADDSTAT(Variance, variance, 1e3);
#undef ADDSTAT
      return new Dictionary(res);
    }

    static void
    system_resetStats()
    {
      ::kernel::scheduler().stats_reset();
    }

    // This should give a backtrace as an urbi object.
    static void
    system_backtrace()
    {
      // FIXME: This method sucks a bit, because show_backtrace sucks a
      // bit, because our channeling/message-sending system sucks a lot.
      runner::Runner::backtrace_type bt = runner().backtrace_get();
      bt.pop_back();
      rforeach (const runner::Runner::frame_type& elt, bt)
      {
        std::ostringstream o;
        o << *elt->slot_get(SYMBOL(name))->call(SYMBOL(asString))
          << " ("
          << *elt->slot_get(SYMBOL(location))->call(SYMBOL(asString))
          << ")";
        // o << *elt->call(SYMBOL(asString));
        runner().send_message("backtrace", o.str());
      }
    }

    static List::value_type
    system_jobs()
    {
      List::value_type res;
      foreach(sched::rJob job, ::kernel::scheduler().jobs_get())
      {
        rObject o = dynamic_cast<runner::Runner*>(job.get())->as_job();
        if (o != nil_class)
          res.push_back(o);
      }
      return res;
    }

    static int
    system_aliveJobs()
    {
      return sched::Job::alive_jobs();
    }

    static void
    system_breakpoint()
    {
      return;
    }

#define SERVER_SET_VAR(Function, Variable, Value)       \
    static void                                         \
    system_ ## Function ()                              \
    {                                                   \
      ::kernel::urbiserver->Variable = Value;           \
    }

    SERVER_SET_VAR(stopall, stopall, true)

#undef SERVER_SET_VAR

    static rObject
    system_getenv(const rObject&, const std::string& name)
    {
      char* res = getenv(name.c_str());
      return res ? new String(res) : nil_class;
{'fraction_non_alphanumeric': 0.13081491257010888, 'fraction_numerical': 0.004838887055977125, 'mean_word_length': 2.295343359304222, 'pattern_counts': {'":': 0, '<': 103, '<?xml version=': 0, '>': 127, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5963122', 'n_tokens_mistral': 5665, 'n_tokens_neox': 5477, 'n_words': 1243}