From 56534edb6c73975e31f1f5257a6e9ed817bfb9d2 Mon Sep 17 00:00:00 2001 From: tchernobog Date: Sat, 25 Feb 2006 12:21:30 +0000 Subject: [PATCH] - Make libpyloader a loadable plugin (warning: won't work on Window$ unless you change the string "libpyloader" to "pyloader" into main.cc) - Fix Makefile to support module creation and loading - 2DO: - Add a class into backend to load and manage plugins - Install plugins into separate directory - Remove hardcoded paths git-svn-id: svn://svn.gna.org/svn/sgpemv2/trunk@458 3ecf2c5c-341e-0410-92b4-d18e462d057c --- Makefile.am | 19 ++++--- src/backend/dummy_policy.cc | 71 --------------------------- src/backend/dummy_policy.hh | 56 --------------------- src/backend/policy.hh | 24 +++------ src/backend/policy_manager.cc | 19 ++++++- src/backend/policy_manager.hh | 23 ++++++++- src/backend/pyloader/hook.cc | 54 ++++++++++++++++++++ src/backend/pyloader/python_policy.cc | 7 --- src/backend/pyloader/python_policy.hh | 6 --- src/backend/pyloader/sgpem.i | 2 +- src/backend/scheduler.cc | 45 +++++++++-------- src/backend/scheduler.hh | 22 ++++++--- src/main.cc | 29 ++++++----- src/simulation.cc | 8 +-- src/testsuite/test-python_loader.cc | 17 +++++-- 15 files changed, 187 insertions(+), 215 deletions(-) delete mode 100644 src/backend/dummy_policy.cc delete mode 100644 src/backend/dummy_policy.hh create mode 100644 src/backend/pyloader/hook.cc diff --git a/Makefile.am b/Makefile.am index d4d6680..21e1bf6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ testsdir = $(pkgdatadir)/tests #define empty global variables bin_PROGRAMS = +mod_LTLIBRARIES = mod_PYTHON = noinst_HEADERS = pkglib_LTLIBRARIES = @@ -136,7 +137,8 @@ src_backend_libbackend_la_CXXFLAGS = \ src_backend_libbackend_la_LDFLAGS = \ $(GLIBMM_LDFLAGS) \ $(LT_LDFLAGS) \ - -version-info 0:0:0 + -version-info 0:0:0 \ + -export-dynamic # Please keep this in sorted order: src_backend_libbackend_la_SOURCES = \ @@ -228,7 +230,7 @@ noinst_HEADERS += \ # # ############################################################ -pkglib_LTLIBRARIES += src/backend/pyloader/libpyloader.la +mod_LTLIBRARIES += src/backend/pyloader/libpyloader.la src_backend_pyloader_libpyloader_la_CPPFLAGS = \ -I@top_srcdir@ \ @@ -247,12 +249,14 @@ src_backend_pyloader_libpyloader_la_LIBADD = \ src_backend_pyloader_libpyloader_la_LDFLAGS = \ $(PYTHON_EXTRA_LDFLAGS) \ $(LT_LDFLAGS) \ - -version-info 0:0:0 + -version-info 0:0:0 \ + -module # Please keep this in sorted order: src_backend_pyloader_libpyloader_la_SOURCES = \ src/backend/pyloader/python_policy.cc \ - src/backend/pyloader/python_policy_manager.cc + src/backend/pyloader/python_policy_manager.cc \ + src/backend/pyloader/hook.cc noinst_HEADERS += \ src/backend/pyloader/python_policy.hh \ @@ -272,7 +276,7 @@ mod_PYTHON += \ proxies = src/backend/pyloader/sgpem.py wrappers = src/backend/pyloader/sgpem_wrap.cc -mod_LTLIBRARIES = _sgpem.la +mod_LTLIBRARIES += _sgpem.la mod_PYTHON += $(proxies) # static pattern rule @@ -328,7 +332,6 @@ pyc_PYTHON = \ tests_PROGRAMS = src/testsuite/test-python_loader -# Shouldn't need Gtkmm! This is a coding anomaly src_testsuite_test_python_loader_CPPFLAGS = \ -I@top_srcdir@/src \ -DPYCDIR="\"$(pycdir)\"" \ @@ -336,8 +339,10 @@ src_testsuite_test_python_loader_CPPFLAGS = \ $(PYTHON_CPPFLAGS) \ $(GLIBMM_CFLAGS) \ $(GTHREAD_CFLAGS) +src_testsuite_test_python_loader_DEPENDENCIES = \ + src/backend/pyloader/libpyloader.la src_testsuite_test_python_loader_LDFLAGS = \ - src/backend/pyloader/libpyloader.la \ + src/backend/libbackend.la \ $(GTKMM_LIBS) $(GTHREAD_LIBS) src_testsuite_test_python_loader_SOURCES = \ src/testsuite/test-python_loader.cc \ diff --git a/src/backend/dummy_policy.cc b/src/backend/dummy_policy.cc deleted file mode 100644 index 54a510b..0000000 --- a/src/backend/dummy_policy.cc +++ /dev/null @@ -1,71 +0,0 @@ -// src/backend/dummy_policy.cc - Copyright 2005, 2006, University -// of Padova, dept. of Pure and Applied -// Mathematics -// -// This file is part of SGPEMv2. -// -// This is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// SGPEMv2 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with SGPEMv2; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -#include "dummy_policy.hh" - -using namespace std; -using namespace sgpem; - -DummyPolicy::~DummyPolicy() -{ -} - -void -DummyPolicy::configure() -{ - _id = 100; - _parameters.clear(); - _parameters.register_int("var1", 0, 10, true, 5); - _parameters.register_int("var2", -100, +100, false); - _parameters.register_float("kernel", 0, 10, true, 3.1415); - _parameters.register_float("multiplier", -100000, 100000, true, 1000); - _parameters.register_string("che_ne_so", true); - -} - -Glib::ustring -DummyPolicy::get_description() const -{ - return "This is a dummy policy implemented in C++. It is just needed as a debug stub."; -} - -bool -DummyPolicy::is_pre_emptive() const -{ - return true; -} - -int -DummyPolicy::get_time_slice() const -{ - return _time_slice; -} - -void -DummyPolicy::set_time_slice( const int& i) -{ - _time_slice = i; -} - -void -DummyPolicy::sort_queue(sgpem::Scheduler::event) const -{ - return; -} diff --git a/src/backend/dummy_policy.hh b/src/backend/dummy_policy.hh deleted file mode 100644 index 49a2c2b..0000000 --- a/src/backend/dummy_policy.hh +++ /dev/null @@ -1,56 +0,0 @@ -// src/backend/dummy_policy.hh - Copyright 2005, 2006, University -// of Padova, dept. of Pure and Applied -// Mathematics -// -// This file is part of SGPEMv2. -// -// This is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// SGPEMv2 is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with SGPEMv2; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -#ifndef DUMMYPOLICY_HH -#define DUMMYPOLICY_HH 1 - -#include "config.h" - -#include "glibmm/ustring.h" - -#include "policy.hh" - -namespace sgpem -{ - class DummyPolicy; - - /** \brief This is a trivial policy for demostration purposes only - * - * This trivial schedulation policy was needed during initial development - * as stub. It is now maintained as an example of how built-in policy can - * be implemented in C++. - */ - class SG_DLLEXPORT DummyPolicy : public Policy - { - public: - virtual ~DummyPolicy(); - virtual void configure(); - virtual void sort_queue(sgpem::Scheduler::event) const; - virtual Glib::ustring get_description() const; - virtual bool is_pre_emptive() const; - virtual int get_time_slice() const; - virtual void set_time_slice(const int&); - - private: - int _time_slice; - }; -} //~ namespace sgpem - -#endif // DUMMYPOLICY_HH diff --git a/src/backend/policy.hh b/src/backend/policy.hh index b0dadb9..badef85 100644 --- a/src/backend/policy.hh +++ b/src/backend/policy.hh @@ -28,6 +28,7 @@ #include "scheduler.hh" #include "policy_parameters.hh" +#include "user_interrupt_exception.hh" namespace sgpem { @@ -51,7 +52,7 @@ namespace sgpem Because it's a pure virtual method, must be re-implemented in concrete derived classes. */ - virtual void configure() = 0; + virtual void configure() throw(UserInterruptException) = 0; /** Sort the \ref SchedulableQueue object that contain all the Schedulable objects @@ -61,13 +62,13 @@ namespace sgpem in concrete derived classes. \param event Call reason. Needed only by some scheduling policies. */ - virtual void sort_queue(Scheduler::event event) const = 0; + virtual void sort_queue(Scheduler::event event) const throw(UserInterruptException) = 0; /** Gets the unique identifier (id) of this Policy. \return The Policy id. */ - int get_id() const; + int get_id() const; /** Gets a string description of the policy. @@ -76,7 +77,7 @@ namespace sgpem in concrete derived classes. \return String description of the policy. */ - virtual Glib::ustring get_description() const = 0; + virtual Glib::ustring get_description() const = 0; /** Tell if this policy is preemptible. @@ -88,7 +89,7 @@ namespace sgpem in concrete derived classes. \return True if this policy is preemptible. */ - virtual bool is_pre_emptive() const = 0; + virtual bool is_pre_emptive() const throw(UserInterruptException) = 0; /** Gets the time quantum for the policy. @@ -97,16 +98,7 @@ namespace sgpem in concrete derived classes. \return Time quantum for the policy. */ - virtual int get_time_slice() const = 0; - - /** - Sets the time quantum for the policy. - - Because it's a pure virtual method, must be re-implemented - in concrete derived classes. - \param quantum The desired time quantum for the policy. - */ - virtual void set_time_slice(const int& quantum) = 0; + virtual int get_time_slice() const throw(UserInterruptException) = 0; /** Gets the parameters related with this policy. @@ -115,7 +107,7 @@ namespace sgpem in concrete derived classes. \return The policy parameters. */ - PolicyParameters& get_parameters(); + PolicyParameters& get_parameters(); protected: PolicyParameters _parameters; diff --git a/src/backend/policy_manager.cc b/src/backend/policy_manager.cc index e21068c..30b6763 100644 --- a/src/backend/policy_manager.cc +++ b/src/backend/policy_manager.cc @@ -21,8 +21,23 @@ #include "policy_manager.hh" +PolicyManager* +PolicyManager::_registered = NULL; -PolicyManager::~PolicyManager() -{ +PolicyManager::PolicyManager() +{ + _registered = this; } + +PolicyManager::~PolicyManager() +{ + // This check is necessary: + if(_registered == this) _registered = NULL; +} + +PolicyManager& +PolicyManager::get_registered_manager() +{ + return *_registered; +} diff --git a/src/backend/policy_manager.hh b/src/backend/policy_manager.hh index d073245..de8ef32 100644 --- a/src/backend/policy_manager.hh +++ b/src/backend/policy_manager.hh @@ -36,6 +36,17 @@ namespace sgpem class SG_DLLEXPORT PolicyManager { public: + /** \brief PolicyManager constructor + * + * Saves ``this'' pointer into the _registered attribute, so it can access + * it when requested. This is done so that concrete subclasses can be defined + * even if they are found in external dynamic modules not known at compile time. + * + * For the moment, just an instance of PolicyManager can be saved. This will + * be expanded in next milestones. + */ + PolicyManager(); + virtual ~PolicyManager() = 0; /** @@ -48,7 +59,17 @@ namespace sgpem /** Init (or reset if yet initialized) the manager. */ - virtual void init() = 0; + virtual void init() = 0; + + /** \brief Get the registered manager instance + * + * \return The registered policy manager instance. + */ + static PolicyManager& get_registered_manager(); + + private: + /** A pointer to the registered instance */ + static PolicyManager* _registered; }; } //~ namespace sgpem diff --git a/src/backend/pyloader/hook.cc b/src/backend/pyloader/hook.cc new file mode 100644 index 0000000..b2ed528 --- /dev/null +++ b/src/backend/pyloader/hook.cc @@ -0,0 +1,54 @@ +// src/backend/pyloader/hook.cc - Copyright 2005, 2006, University +// of Padova, dept. of Pure and Applied +// Mathematics +// +// This file is part of SGPEMv2. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// SGPEMv2 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SGPEMv2; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +// The idea of this file is to provide a static function to execute +// when the plugin (this library) is loaded. Thus the name "hook". + +// For the moment, instead of a function hook to be called by the +// libbackend.so module, we have a static PythonPolicyManager object. +// This is a risk. +#warning FIXME : this code is quite a bad idea. Replace me with \ + a hookable structure, and execute a pointer to function stored \ + therein. See "info libtool": "dlopened modules" + +#include "python_policy_manager.hh" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SG_CONSTRUCTOR __attribute__ ((constructor)) +#define SG_DESTRUCTOR __attribute__ ((destructor)) + +PolicyManager* _global_pm = NULL; + +void SG_DLLEXPORT SG_CONSTRUCTOR hook_ctor(void) +{ + _global_pm = PythonPolicyManager::get_instance(); +} + +void SG_DLLEXPORT SG_DESTRUCTOR hook_dtor(void) +{ + delete _global_pm; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/backend/pyloader/python_policy.cc b/src/backend/pyloader/python_policy.cc index bd8fc8e..6fab705 100644 --- a/src/backend/pyloader/python_policy.cc +++ b/src/backend/pyloader/python_policy.cc @@ -152,13 +152,6 @@ PythonPolicy::get_time_slice() const throw(UserInterruptException) { return tmp < 0 ? numeric_limits::max() : static_cast(tmp); } - -void -PythonPolicy::set_time_slice(const int&) -{ - throw "The design is wrong, and I shouldn't be called."; -} - void PythonPolicy::wait_unlock() const throw(UserInterruptException) diff --git a/src/backend/pyloader/python_policy.hh b/src/backend/pyloader/python_policy.hh index 38d6310..8a6466a 100644 --- a/src/backend/pyloader/python_policy.hh +++ b/src/backend/pyloader/python_policy.hh @@ -76,12 +76,6 @@ namespace sgpem */ int get_time_slice() const throw(UserInterruptException); - // Singing with Caipha's voice: "must die, must die, this method must die!" - /** - Changes the time-slice of the policy. - */ - void set_time_slice(const int&); - private: PythonPolicy(const char* name); PythonPolicy(const PythonPolicy&); diff --git a/src/backend/pyloader/sgpem.i b/src/backend/pyloader/sgpem.i index 3e22329..11692f5 100644 --- a/src/backend/pyloader/sgpem.i +++ b/src/backend/pyloader/sgpem.i @@ -185,7 +185,7 @@ namespace sgpem { // --------------------------------------------- class Scheduler { public: - sgpem::Policy* get_policy(); + sgpem::Policy& get_policy(); static sgpem::Scheduler& get_instance(); sgpem::SchedulableList* get_ready_queue(); private: diff --git a/src/backend/scheduler.cc b/src/backend/scheduler.cc index ea42d79..54117ba 100644 --- a/src/backend/scheduler.cc +++ b/src/backend/scheduler.cc @@ -20,29 +20,33 @@ #include "policy.hh" #include "scheduler.hh" +#include "policy_manager.hh" using namespace std; using namespace sgpem; using namespace memory; -//static object -Scheduler Scheduler::_instance(10); //dummy parameter +Scheduler* +Scheduler::_instance = 0; -/** - -*/ -Scheduler::Scheduler(int) //private constructor. The parameter is discarded -{} +//private constructor. The parameter is discarded +Scheduler::Scheduler() + : _policy_manager(PolicyManager::get_registered_manager()) +{ + _policy_manager.init(); +} Scheduler& Scheduler::get_instance() { - return _instance; + if(!_instance) + _instance = new Scheduler(); + return *_instance; } SchedulableList* Scheduler::get_ready_queue() { - return &_ready_queue; + return &_ready_queue; } @@ -58,23 +62,24 @@ Scheduler::reset_status() // restore the policy } -void +/* void Scheduler::set_policy(Policy* p) { - _policy = p; -} + _policy_manager.set_policy(p); + }*/ -Policy* +Policy& Scheduler::get_policy() { - return _policy; + return _policy_manager.get_policy(); } void Scheduler::step_forward() { + Policy& policy = get_policy(); History& h = History::get_instance(); //****************** @@ -107,7 +112,7 @@ Scheduler::step_forward() //cout << "\nnuovo running: " << initial->get_item_at(i)->get_schedulable()->get_name(); //restore the old running schedulable - if (_policy->is_pre_emptive() == false && running_ptr) + if (policy.is_pre_emptive() == false && running_ptr) _ready_queue.remove(0); //adds the NEW one @@ -116,10 +121,10 @@ Scheduler::step_forward() initial->get_item_at(i)->set_state(SchedulableStatus::state_ready); // Sort the queue - _policy->sort_queue(event_schedulable_arrival); + policy.sort_queue(event_schedulable_arrival); //restore the old running schedulable - if (_policy->is_pre_emptive() == false && running_ptr) + if (policy.is_pre_emptive() == false && running_ptr) _ready_queue.add_at_top(*running_ptr); } @@ -143,14 +148,14 @@ Scheduler::step_forward() running_ptr = NULL; //IF _ready_queue.size() == 0 sort_queue(...) is called but has no effect!! - _policy->sort_queue(event_schedulable_termination); + policy.sort_queue(event_schedulable_termination); } //***************** // Check for time slice //***************** - if (_policy->get_time_slice() != numeric_limits::max()) //time-slice - _policy->sort_queue(event_end_time_slice); + if (policy.get_time_slice() != numeric_limits::max()) //time-slice + policy.sort_queue(event_end_time_slice); //****************** // Create the final list of schedulable diff --git a/src/backend/scheduler.hh b/src/backend/scheduler.hh index 4bccc98..13267c4 100644 --- a/src/backend/scheduler.hh +++ b/src/backend/scheduler.hh @@ -22,7 +22,9 @@ #define SCHEDULER_HH 1 namespace sgpem { - class Policy; + class Scheduler; + class PolicyManager; + class Policy; } #include "config.h" @@ -71,9 +73,11 @@ namespace sgpem event_end_time_slice }; - /** - Returns the unique instance of this class, conforming to the Singleton pattern. - \return the unique instance of this class, conforming to the Singleton pattern. + /** \brief Returns the unique instance of this class, conforming to the Singleton pattern. + * + * If Scheduler isn't initialized, creates it. Should be called at least once before + * starting the Simulation. + * \return the unique instance of this class, conforming to the Singleton pattern. */ static Scheduler& get_instance(); /** @@ -97,19 +101,21 @@ namespace sgpem Sets the policy that will be used to generate the simulation at the next instant. \param policy the policy that will be used to generate the simulation at the next instant. */ + /* DISABLED until we don't have PolicyManager::set_policy() void set_policy(Policy* policy); + */ /** Returns the policy that will be used to generate the simulation at the next instant. \return the policy that will be used to generate the simulation at the next instant. */ - Policy* get_policy(); + Policy& get_policy(); private: - Scheduler(int); //private constructor. The parameter is discarded - static Scheduler _instance; + Scheduler(); //private constructor. + static Scheduler* _instance; SchedulableList _ready_queue; - Policy* _policy; + PolicyManager& _policy_manager; }; }//~ namespace sgpem diff --git a/src/main.cc b/src/main.cc index e065300..dccbb3b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -39,8 +39,10 @@ #include "backend/dummy_policy.hh" +#include #include +#include #include #include #include @@ -60,6 +62,15 @@ main(int argc, char* argv[]) bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); + // FIXME: this will need to be moved to an + // appropriate PluginManager class in the backend, + // and the Makefile fixed accordingly + using Glib::Module; + std::string pyloader_path = Module::build_path(MODDIR, "pyloader"); + Module pyloader(pyloader_path); + std::cerr << Module::get_last_error() << std::endl; + assert(pyloader); + // Set up Glib thread support Glib::thread_init(); @@ -75,15 +86,6 @@ main(int argc, char* argv[]) } */ - // Set the unique POLICY - DummyPolicy pol; - pol.configure(); - pol.get_parameters().set_int("var2", 33); - pol.get_parameters().set_float("multiplier", 100); - pol.get_parameters().set_string("che_ne_so", "ciao"); - Scheduler::get_instance().set_policy(&pol); - - // Create an INITIAL STATE Process p1("P1", 0,5,1); Process p2("P2", 0,5,2); @@ -107,6 +109,10 @@ main(int argc, char* argv[]) initial.add_at_bottom(ss5); initial.add_at_bottom(ss6); History::get_instance().enqueue_slice(initial); + + Scheduler::get_instance(); // Forces initialization of scheduler. + // Cross fingers (depends if PythonPolicyManager + // static object has been initialized before?). //the textual simulation TextSimulation text_sim; @@ -125,7 +131,7 @@ main(int argc, char* argv[]) - //************** TEST HISTORY + // ************** TEST HISTORY SchedulableList l1; l1.add_at_top(ss1); l1.add_at_top(ss2); l1.add_at_top(ss3); @@ -194,5 +200,6 @@ main(int argc, char* argv[]) cout << "\n\n"; */ -return 0; + + return 0; } diff --git a/src/simulation.cc b/src/simulation.cc index 7aac98e..8a976d4 100644 --- a/src/simulation.cc +++ b/src/simulation.cc @@ -159,23 +159,23 @@ Simulation::jump_to(const uint& where) _mode = old; } -void +/*void Simulation::set_policy(Policy* p) { Scheduler::get_instance().set_policy(p); -} + }*/ Policy* Simulation::get_policy() { - return Scheduler::get_instance().get_policy(); + return &Scheduler::get_instance().get_policy(); } vector Simulation::get_avaiable_policies() { vector v; - v.push_back(Scheduler::get_instance().get_policy()); + v.push_back(&Scheduler::get_instance().get_policy()); return v; } diff --git a/src/testsuite/test-python_loader.cc b/src/testsuite/test-python_loader.cc index b91be54..e3b3c68 100644 --- a/src/testsuite/test-python_loader.cc +++ b/src/testsuite/test-python_loader.cc @@ -31,12 +31,20 @@ #include "text_simulation.hh" #include "templates/smartp.hh" +#include + #include +#include int main(int argc, char** argv) { using namespace sgpem; + using Glib::Module; + std::string pyloader_path = Module::build_path(MODDIR, "pyloader"); + Glib::Module pyloader(pyloader_path); + assert(pyloader); + Glib::thread_init(); // Create an INITIAL STATE @@ -62,12 +70,11 @@ main(int argc, char** argv) { initial.add_at_bottom(ss5); initial.add_at_bottom(ss6); History::get_instance().enqueue_slice(initial); - - PythonPolicyManager* ppm = PythonPolicyManager::get_instance(); - ppm->init(); - Policy& pol = ppm->get_policy(); - Scheduler::get_instance().set_policy(&pol); + Scheduler::get_instance(); // Forces initialization of scheduler. + // Cross fingers (depends if PythonPolicyManager + // static object has been initialized before?). + //the textual simulation TextSimulation text_sim; History::get_instance().attach(&text_sim);