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