Fawkes API  Fawkes Development Version
eclipse_thread.cpp
1 
2 /***************************************************************************
3  * eclipse_thread.cpp - Fawkes ECLiPSe Thread
4  *
5  * Created: Wed Jul 16 10:42:49 2009
6  * Copyright 2009 Daniel Beck
7  * 2013-2014 Gesche Gierse
8  * 2014 Tim Niemueller
9  ****************************************************************************/
10 
11 /* This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL file in the doc directory.
22  */
23 
24 #include "eclipse_thread.h"
25 
26 #include "blackboard_listener_thread.h"
27 #include "externals/blackboard.h"
28 #include "externals/eclipse_path.h"
29 #include "externals/eclipseclp_config.h"
30 #include "externals/fawkes_logger.h"
31 
32 #include <core/exception.h>
33 #include <core/threading/mutex_locker.h>
34 #include <interfaces/TestInterface.h>
35 
36 #include <cstdio>
37 #include <cstdlib>
38 #include <cstring>
39 #include <vector>
40 
41 namespace fawkes {
43 };
44 
45 using namespace std;
46 using namespace fawkes;
47 
48 /** @class EclipseAgentThread "eclipse_thread.h"
49  * This thread creates an ECLiPSe context in which the ECLiPSe
50  * interpreter and the program are loaded.
51  * @author Daniel Beck
52  */
53 
54 extern "C" int ec_external(dident, int (*)(...), dident);
55 
56 EclipseAgentThread *EclipseAgentThread::m_instance = NULL;
57 
58 /** Constructor. */
60 : Thread("ECLiPSe thread", fawkes::Thread::OPMODE_CONTINUOUS), m_initialized(false)
61 {
63  m_instance = this;
64  mutex = new fawkes::Mutex();
65 }
66 
67 /** Destructor. */
69 {
70  if (EclExternalBlackBoard::instance()) {
71  logger->log_info(name(), "Cleaning up");
72  EclExternalBlackBoard::cleanup_instance();
73  }
74  delete mutex;
75 }
76 
77 void
79 {
82  // set ECLiPSe installation directory
83  char *eclipse_dir = NULL;
84  try {
85  eclipse_dir = strdup(config->get_string("/eclipse-clp/eclipse_dir").c_str());
86  logger->log_info(name(), "Setting ECLIPSEDIR to %s", eclipse_dir);
87  ec_set_option_ptr(EC_OPTION_ECLIPSEDIR, (void *)eclipse_dir);
88  } catch (...) {
89  // ignore
90  }
91 
92  agent = config->get_string("/eclipse-clp/agent");
93 
94  try {
95  //set default module in which goals called from the top-level will be executed
96  ec_set_option_ptr(EC_OPTION_DEFAULT_MODULE, (void *)agent.c_str());
97 
98  } catch (...) {
99  throw fawkes::Exception("Failed to set default ECLiPSe module");
100  }
101  // initialize ECLiPSe context
102  if (0 != ec_init()) {
103  throw fawkes::Exception("Failed to initialize ECLiPSe context");
104  }
105 
106  free(eclipse_dir);
107 
108  m_initialized = true;
109 
110  std::vector<std::string> paths = config->get_strings("/eclipse-clp/file_path");
111 
112  // initialise pathfinding utility
114  EclipsePath::instance()->add_regex(boost::regex("@AGENT@"), agent);
115  for (size_t i = 0; i < paths.size(); ++i) {
116  EclipsePath::instance()->add_path(paths[i]);
117  }
118 
120 
121  // debug
123 
124  // make locate_file/2 available
125  std::string filepath_path = EclipsePath::instance()->locate_file("filepath.ecl");
126  if (filepath_path.empty()) {
127  throw Exception("Failed to determine path to filepath module");
128  }
129  load_file(filepath_path.c_str());
130  char *filepath = ::strdup("filepath");
131  post_goal(term(EC_functor(":", 2),
132  EC_atom(filepath),
133  term(EC_functor("add_library_path", 1),
134  ::list(EC_word(SRCDIR "/externals"),
135  ::list(EC_word(SRCDIR "/utils"),
136  ::list(EC_word(SRCDIR "/consoletool"),
137  ::list(EC_word(SRCDIR "/interpreter"), nil())))))));
138  if (EC_succeed != EC_resume())
139  throw Exception("Failed to add " SRCDIR "/externals to library path");
140 
141  // check if navgraph is used and pass config value
142  if (config->get_bool(("/eclipse-clp/" + agent + "/use_graph").c_str())) {
143  graph_path =
144  CONFDIR + config->get_string(("/eclipse-clp/" + agent + "/rel_graph_path").c_str());
145 
146  logger->log_info(name(), "Setting graph_path to %s", graph_path.c_str());
147  post_goal(term(EC_functor("load_graph", 1), graph_path.c_str()));
148  if (EC_succeed != EC_resume()) {
149  throw Exception("Error loading graph config to agent");
150  }
151  }
152 
153  // load interpreter and agent
154  std::string agent_path = EclipsePath::instance()->locate_file(agent + ".ecl");
155  if (agent_path.empty()) {
156  throw Exception("Failed to determine path to agent module");
157  }
158  load_file(agent_path.c_str());
159 
160  // register external predicates
161  if (EC_succeed != ec_external(ec_did("log", 2), p_log, ec_did(agent.c_str(), 0))) {
162  throw Exception("Registering external predicate log/2 failed");
163  }
164 }
165 
166 void
168 {
169  ec_cleanup();
170  if (EclExternalBlackBoard::instance())
172 }
173 
174 void
176 {
177  post_goal("run");
178  ec_result = EC_resume("init", ec_yield_reason);
179 }
180 
181 void
183 {
184  if (ec_result == EC_status::EC_yield) {
185  EC_word bb_updates(::nil());
186  if (EC_word(ec_yield_reason) == EC_atom("exogenous_update")) {
187  while (BlackboardListenerThread::instance()->event_pending())
188  bb_updates = ::list(bb_updates, *BlackboardListenerThread::instance()->event_pop());
189  } else if (BlackboardListenerThread::instance()->event_pending())
190  post_event("event_exogUpdate");
191 
192  ec_result = EC_resume(bb_updates, ec_yield_reason);
193  } else {
194  if (ec_result == EC_status::EC_succeed)
195  logger->log_warn(name(), "Agent program terminated successfully.");
196  else
197  logger->log_error(name(), "Agent program failed.");
198 
199  logger->log_warn(name(), "Stopping Agent thread.");
200  exit();
201  }
202 }
203 
204 /** Post an event to the ECLiPSe context.
205  * @param event the name of the event
206  */
207 void
209 {
210  if (!m_initialized) {
211  return;
212  }
213 
214  // send event to the interpreter
215  char *atom = strdup(event);
216  ::post_event(EC_atom(atom));
217  free(atom);
218 }
219 
220 /** Load a file into the ECLiPSe context.
221  * @param filename the name of the file
222  * @return false if the ECLiPSe context hasn't been intialized yet
223  */
224 bool
225 EclipseAgentThread::load_file(const char *filename)
226 {
227  if (!m_initialized) {
228  return false;
229  }
230 
231  char *ensure_loaded = strdup("ensure_loaded");
232  post_goal(term(EC_functor(ensure_loaded, 1), filename));
233  free(ensure_loaded);
234 
235  if (EC_succeed != ec_resume()) {
236  throw Exception("File %s could not be loaded", filename);
237  }
238 
239  return true;
240 }
241 
242 /** Get the logger.
243  * @return the logger
244  */
247 {
248  return logger;
249 }
250 
251 /** Get the EclipseAgentThread instance.
252  * @return the instance
253  */
256 {
257  if (!m_instance) {
258  throw Exception("No instance of type EclipseThread instantiated");
259  }
260 
261  return m_instance;
262 }
EclipseAgentThread::instance
static EclipseAgentThread * instance()
Get the EclipseAgentThread instance.
Definition: eclipse_thread.cpp:255
EclipseAgentThread::get_logger
fawkes::Logger * get_logger()
Get the logger.
Definition: eclipse_thread.cpp:246
fawkes::Thread::set_prepfin_conc_loop
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:720
fawkes::EclExternalBlackBoard
Definition: blackboard.h:38
EclipseAgentThread::~EclipseAgentThread
virtual ~EclipseAgentThread()
Destructor.
Definition: eclipse_thread.cpp:68
EclipsePath::instance
static EclipsePath * instance()
Get the EclipsePath instance.
Definition: eclipse_path.cpp:68
fawkes::Mutex
Definition: mutex.h:36
EclipseAgentThread::init
virtual void init()
Initialize the thread.
Definition: eclipse_thread.cpp:78
EclipseAgentThread::EclipseAgentThread
EclipseAgentThread()
Constructor.
Definition: eclipse_thread.cpp:59
fawkes::Configuration::get_bool
virtual bool get_bool(const char *path)=0
fawkes::Logger::log_info
virtual void log_info(const char *component, const char *format,...)=0
BlackboardListenerThread::instance
static BlackboardListenerThread * instance()
Get the singleton instance of this thread.
Definition: blackboard_listener_thread.cpp:39
EclipsePath::apply_regexes
void apply_regexes()
Apply the regexes to all paths.
Definition: eclipse_path.cpp:127
EclipsePath::locate_file
std::string locate_file(const std::string &filename)
Locate a file by filename.
Definition: eclipse_path.cpp:98
fawkes::Thread::name
const char * name() const
Definition: thread.h:99
EclipseAgentThread
Definition: eclipse_thread.h:40
fawkes::Thread::exit
void exit()
Exit the thread.
Definition: thread.cpp:586
EclipseAgentThread::loop
virtual void loop()
Code to execute in the thread.
Definition: eclipse_thread.cpp:182
EclipsePath::print_all_paths
void print_all_paths()
Debug method to print all path to the command line.
Definition: eclipse_path.cpp:145
fawkes::LoggingAspect::logger
Logger * logger
Definition: logging.h:50
EclipsePath::add_path
void add_path(const std::string &path)
Add a new path.
Definition: eclipse_path.cpp:78
fawkes::Logger::log_error
virtual void log_error(const char *component, const char *format,...)=0
fawkes::EclExternalBlackBoard::create_initial_object
static void create_initial_object(BlackBoard *bb, Logger *logger)
Creates the initial EclExternalBlackBoard object.
Definition: blackboard.cpp:69
fawkes::Logger
Definition: logger.h:40
fawkes
fawkes::Logger::log_warn
virtual void log_warn(const char *component, const char *format,...)=0
fawkes::Configuration::get_strings
virtual std::vector< std::string > get_strings(const char *path)=0
EclipseAgentThread::post_event
void post_event(const char *)
Post an event to the ECLiPSe context.
Definition: eclipse_thread.cpp:208
fawkes::ConfigurableAspect::config
Configuration * config
Definition: configurable.h:50
fawkes::EclExternalBlackBoard::cleanup_instance
static void cleanup_instance()
Delete the current EclExternalBlackBoard instance and set it to NULL.
Definition: blackboard.cpp:76
EclipsePath::add_regex
void add_regex(boost::regex re, const std::string &str)
Add a regex.
Definition: eclipse_path.cpp:158
fawkes::Thread
Definition: thread.h:44
fawkes::BlackBoardAspect::blackboard
BlackBoard * blackboard
Definition: blackboard.h:47
fawkes::Configuration::get_string
virtual std::string get_string(const char *path)=0
fawkes::EclExternalConfig::create_initial_object
static void create_initial_object(Configuration *config)
Creates the initial EclExternalConfig object.
Definition: eclipseclp_config.cpp:76
EclipseAgentThread::once
virtual void once()
Execute an action exactly once.
Definition: eclipse_thread.cpp:175
EclipsePath::create_initial_object
static void create_initial_object()
Create the initial EclipsePath object.
Definition: eclipse_path.cpp:53
EclipseAgentThread::finalize
virtual void finalize()
Finalize the thread.
Definition: eclipse_thread.cpp:167
fawkes::Exception
Definition: exception.h:39