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()
Constructor.
static void create_initial_object(BlackBoard *bb, Logger *logger)
Creates the initial EclExternalBlackBoard object.
Definition: blackboard.cpp:64
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
void apply_regexes()
Apply the regexes to all paths.
virtual void finalize()
Finalize the thread.
std::string locate_file(const std::string &filename)
Locate a file by filename.
static EclipsePath * instance()
Get the EclipsePath instance.
fawkes::Logger * get_logger()
Get the logger.
Fawkes library namespace.
virtual bool get_bool(const char *path)=0
Get value from configuration which is of type bool.
Thread class encapsulation of pthreads.
Definition: thread.h:45
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:716
virtual void loop()
Code to execute in the thread.
virtual ~EclipseAgentThread()
Destructor.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
static void cleanup_instance()
Delete the current EclExternalBlackBoard instance and set it to NULL.
Definition: blackboard.cpp:71
void post_event(const char *)
Post an event to the ECLiPSe context.
void print_all_paths()
Debug method to print all path to the command line.
static EclipseAgentThread * instance()
Get the EclipseAgentThread instance.
Base class for exceptions in Fawkes.
Definition: exception.h:35
void add_path(const std::string &path)
Add a new path.
Wrapper class for using the blackboard in the implementation of the external predicates.
Definition: blackboard.h:39
const char * name() const
Get name of thread.
Definition: thread.h:100
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
This thread creates an ECLiPSe context in which the ECLiPSe interpreter and the program are loaded.
virtual void init()
Initialize the thread.
static void create_initial_object(Configuration *config)
Creates the initial EclExternalConfig object.
virtual std::vector< std::string > get_strings(const char *path)=0
Get list of values from configuration which is of type string.
virtual void once()
Execute an action exactly once.
static void create_initial_object()
Create the initial EclipsePath object.
void add_regex(boost::regex re, const std::string &str)
Add a regex.
static BlackboardListenerThread * instance()
Get the singleton instance of this thread.
Mutex mutual exclusion lock.
Definition: mutex.h:32
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:41
void exit()
Exit the thread.
Definition: thread.cpp:582
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:44
Interface for logging.
Definition: logger.h:41