24 #include <aspect/manager.h> 25 #include <baseapp/main_thread.h> 26 #include <config/config.h> 27 #include <core/exceptions/system.h> 28 #include <core/macros.h> 29 #include <core/threading/interruptible_barrier.h> 30 #include <core/threading/mutex_locker.h> 31 #include <core/version.h> 32 #include <plugin/loader.h> 33 #include <plugin/manager.h> 34 #include <utils/time/clock.h> 35 #include <utils/time/wait.h> 69 const char * load_plugins,
70 const char * default_plugin)
71 :
Thread(
"FawkesMainThread")
73 plugin_manager_ = plugin_manager;
74 thread_manager_ = thread_manager;
75 syncpoint_manager_ = syncpoint_manager;
76 multi_logger_ = multi_logger;
79 mainloop_thread_ = NULL;
80 mainloop_mutex_ =
new Mutex();
85 load_plugins_ = strdup(load_plugins);
88 default_plugin_ = NULL;
90 default_plugin_ = strdup(default_plugin);
96 loop_start_ =
new Time(clock_);
97 loop_end_ =
new Time(clock_);
99 max_thread_time_usec_ = config_->
get_uint(
"/fawkes/mainapp/max_thread_time");
101 max_thread_time_usec_ = 30000;
102 multi_logger_->
log_info(
"FawkesMainApp",
"Maximum thread time not set, assuming 30ms.");
104 max_thread_time_nanosec_ = max_thread_time_usec_ * 1000;
108 desired_loop_time_usec_ = config_->
get_uint(
"/fawkes/mainapp/desired_loop_time");
109 if (desired_loop_time_usec_ > 0) {
110 time_wait_ =
new TimeWait(clock_, desired_loop_time_usec_);
113 desired_loop_time_usec_ = 0;
114 multi_logger_->
log_info(
"FawkesMainApp",
"Desired loop time not set, assuming 0");
117 desired_loop_time_sec_ = (float)desired_loop_time_usec_ / 1000000.f;
120 enable_looptime_warnings_ = config_->
get_bool(
"/fawkes/mainapp/enable_looptime_warnings");
121 if (!enable_looptime_warnings_) {
122 multi_logger_->
log_debug(
name(),
"loop time warnings are disabled");
125 enable_looptime_warnings_ =
true;
139 FawkesMainThread::destruct()
143 }
catch (CouldNotOpenFileException &e) {
144 if (e.get_errno() == EACCES) {
145 multi_logger_->
log_warn(
"FawkesMainThread",
146 "Cannot write to dump file, " 148 multi_logger_->
log_warn(
"FawkesMainThread",
149 "permission for file or " 151 multi_logger_->
log_warn(
"FawkesMainThread",
152 "usually happens if running " 154 multi_logger_->
log_warn(
"FawkesMainThread",
155 "installed Fawkes as non-root " 157 multi_logger_->
log_warn(
"FawkesMainThread",
158 "configuration changes to the " 160 multi_logger_->
log_warn(
"FawkesMainThread",
161 "database (set as non-default " 164 multi_logger_->
log_warn(
"FawkesMainThread",
165 "Failed to dump default " 166 "config (open), exception follows.");
167 multi_logger_->
log_warn(
"FawkesMainThread", e);
169 }
catch (Exception &e) {
170 multi_logger_->
log_warn(
"FawkesMainThread",
171 "Failed to dump default config, " 172 "exception follows.");
173 multi_logger_->
log_warn(
"FawkesMainThread", e);
179 free(default_plugin_);
185 delete mainloop_barrier_;
186 delete mainloop_mutex_;
196 init_barrier_ =
new Barrier(2);
200 init_barrier_->
wait();
201 delete (init_barrier_);
209 std::vector<BlockedTimingAspect::WakeupHook> hooks;
222 for (std::vector<BlockedTimingAspect::WakeupHook>::const_iterator it = hooks.begin();
225 syncpoints_start_hook_.push_back(syncpoint_manager_->
get_syncpoint(
227 syncpoints_start_hook_.back()->register_emitter(
"FawkesMainThread");
228 syncpoints_end_hook_.push_back(syncpoint_manager_->
get_syncpoint(
232 multi_logger_->
log_error(
"FawkesMainThread",
"Failed to acquire mainloop syncpoint");
239 plugin_manager_->
load(load_plugins_);
241 multi_logger_->
log_error(
"FawkesMainThread",
242 "Failed to load plugins %s, " 245 multi_logger_->
log_error(
"FawkesMainThread", e);
251 if (default_plugin_ && (strcmp(
"default", default_plugin_) != 0)) {
252 plugin_manager_->
load(default_plugin_);
258 multi_logger_->
log_error(
"FawkesMainThread",
259 "Failed to load default " 260 "plugins, exception follows");
261 multi_logger_->
log_error(
"FawkesMainThread", e);
266 if (!load_plugins_) {
268 plugin_manager_->
load(
"default");
273 multi_logger_->
log_error(
"FawkesMainThread",
274 "Failed to load default " 275 "plugins, exception follows");
276 multi_logger_->
log_error(
"FawkesMainThread", e);
279 multi_logger_->
log_error(
"FawkesMainThread",
280 "Failed to load default " 281 "plugins, exception follows");
282 multi_logger_->
log_error(
"FawkesMainThread", e);
287 init_barrier_->
wait();
294 mainloop_mutex_->
lock();
296 mainloop_thread_ = mainloop_thread;
297 mainloop_mutex_->
unlock();
305 multi_logger_->
log_debug(
"FawkesMainThread",
"No timed threads exist, waiting");
308 multi_logger_->
log_debug(
"FawkesMainThread",
309 "Timed threads have been added, " 310 "running main loop now");
312 multi_logger_->
log_debug(
"FawkesMainThread",
"Waiting for timed threads interrupted");
317 plugin_manager_->
lock();
328 mainloop_mutex_->
lock();
330 if (unlikely(mainloop_thread_ != NULL)) {
332 if (likely(mainloop_thread_ != NULL)) {
333 mainloop_thread_->
wakeup(mainloop_barrier_);
334 mainloop_barrier_->
wait();
337 multi_logger_->
log_warn(
"FawkesMainThread", e);
340 uint num_hooks = syncpoints_start_hook_.size();
341 if (syncpoints_end_hook_.size() != num_hooks) {
344 "Hook syncpoints are not initialized properly, not waking up any threads!");
346 for (uint i = 0; i < num_hooks; i++) {
347 syncpoints_start_hook_[i]->emit(
"FawkesMainThread");
348 syncpoints_end_hook_[i]->reltime_wait_for_all(
"FawkesMainThread",
350 max_thread_time_nanosec_);
354 mainloop_mutex_->
unlock();
360 if (!recovered_threads_.empty()) {
363 if (enable_looptime_warnings_) {
364 if (recovered_threads_.size() == 1) {
365 multi_logger_->
log_warn(
"FawkesMainThread",
366 "The thread %s could be " 367 "recovered and resumes normal operation",
368 recovered_threads_.front().c_str());
371 for (std::list<std::string>::iterator i = recovered_threads_.begin();
372 i != recovered_threads_.end();
377 multi_logger_->
log_warn(
"FawkesMainThread",
378 "The following threads could be " 379 "recovered and resumed normal operation: %s",
383 recovered_threads_.clear();
386 if (desired_loop_time_sec_ > 0) {
388 float loop_time = *loop_end_ - loop_start_;
389 if (enable_looptime_warnings_) {
392 if (loop_time > 1.1 * desired_loop_time_sec_) {
393 multi_logger_->
log_warn(
"FawkesMainThread",
394 "Loop time exceeded, " 395 "desired: %f sec (%u usec), actual: %f sec",
396 desired_loop_time_sec_,
397 desired_loop_time_usec_,
403 plugin_manager_->
unlock();
411 multi_logger_->
log_warn(
"FawkesMainThread",
412 "Exception caught while executing default main " 414 multi_logger_->
log_warn(
"FawkesMainThread", e);
415 }
catch (std::exception &e) {
416 multi_logger_->
log_warn(
"FawkesMainThread",
417 "STL Exception caught while executing default main " 418 "loop, ignoring. (what: %s)",
431 return multi_logger_;
447 init_mutex_ =
new Mutex();
448 init_running_ =
true;
450 sigint_running_ =
false;
451 register_signals_ = register_signals;
456 if (register_signals_) {
466 if (register_signals_) {
479 init_running_ =
false;
482 fmt_->logger()->log_info(
"FawkesMainThread",
483 "Fawkes %s startup complete",
484 FAWKES_VERSION_STRING);
485 init_mutex_->unlock();
488 init_mutex_->unlock();
498 if ((signum == SIGINT) && !sigint_running_) {
505 sigint_running_ =
true;
507 }
else if (signum == SIGALRM) {
510 printf(
"\nFawkes shutdown and finalization procedure still running.\n" 511 "Hit Ctrl-C again to force immediate exit.\n\n");
513 }
else if ((signum == SIGTERM) || sigint_running_) {
void full_start()
Start the thread and wait until once() completes.
virtual void try_dump()=0
Try to dump configuration.
act thread (motor module etc.)
void interrupt()
Interrupt the barrier.
static Clock * instance()
Clock initializer.
sensor data preparation thread, convert acquired data to usable format
virtual void log_error(const char *component, const char *format,...)
Log error message.
Time & stamp_systime()
Set this time to the current system time.
Fawkes library namespace.
virtual bool get_bool(const char *path)=0
Get value from configuration which is of type bool.
void unlock()
Unlock the mutex.
virtual void wait()
Wait for other threads.
This exception is thrown if the requested plugin could not be loaded.
A class for handling time.
thread cannot be cancelled
virtual bool timed_threads_exist()
Check if any timed threads exist.
Thread class encapsulation of pthreads.
skill thread (skill module)
FawkesMainThread(Configuration *config, MultiLogger *multi_logger, ThreadManager *thread_manager, SyncPointManager *syncpoint_manager, PluginManager *plugin_manager, const char *load_plugins, const char *default_plugin=0)
Constructor.
RefPtr< SyncPoint > get_syncpoint(const std::string &component, const std::string &identifier)
Get a SyncPoint.
static std::string blocked_timing_hook_to_start_syncpoint(WakeupHook hook)
Get the syncpoint identifier corresponding to the start of a wakeup hook.
sensor data processing thread
static void set_cancel_state(CancelState new_state, CancelState *old_state=0)
Set the cancel state of the current thread.
virtual void loop()
Code to execute in the thread.
A barrier is a synchronization tool which blocks until a given number of threads have reached the bar...
bool wait(unsigned int timeout_sec, unsigned int timeout_nanosec)
Wait for other threads.
void wait_systime()
Wait until minimum loop time has been reached in real time.
void lock()
Lock plugin manager.
Log through multiple loggers.
Mutex * loopinterrupt_antistarve_mutex
Mutex to avoid starvation when trying to lock loop_mutex.
virtual void wait_for_timed_threads()
Wait for timed threads.
virtual ~FawkesMainThread()
Destructor.
void wakeup()
Wake up thread.
static std::string blocked_timing_hook_to_end_syncpoint(WakeupHook hook)
Get the syncpoint identifier corresponding to the end of a wakeup hook.
Base application thread manager.
Base class for exceptions in Fawkes.
This class gives access to SyncPoints.
virtual void log_warn(const char *component, const char *format,...)
Log warning message.
static void ignore(int signum)
Ignore a signal.
const char * name() const
Get name of thread.
Runner(FawkesMainThread *fmt, bool register_signals=true)
Constructor.
static SignalHandler * register_handler(int signum, SignalHandler *handler)
Register a SignalHandler for a signal.
The current system call has been interrupted (for instance by a signal).
virtual void log_info(const char *component, const char *format,...)
Log informational message.
std::string plugin_name() const
Get name of plugin which failed to load.
void load(const std::string &plugin_list)
Load plugin.
void mark_start()
Mark start of loop.
void test_cancel()
Set cancellation point.
static void unregister_handler(int signum)
Unregister a SignalHandler for a signal.
void run()
Run main thread.
virtual void set_mainloop_thread(Thread *mainloop_thread)
Set a new main loop.
void yield()
Yield the processor to another thread or process.
void handle_signal(int signum)
Handle signals.
virtual void try_recover(std::list< std::string > &recovered_threads)
Try to recover threads.
void lock()
Lock this mutex.
void unlock()
Unlock plugin manager.
MultiLogger * logger() const
Get logger.
virtual unsigned int get_uint(const char *path)=0
Get value from configuration which is of type unsigned int.
Mutex mutual exclusion lock.
Fawkes default main thread.
void exit()
Exit the thread.
Interface for configuration handling.
virtual void log_debug(const char *component, const char *format,...)
Log debug message.
A barrier is a synchronization tool which blocks until a given number of threads have reached the bar...
void start(bool wait=true)
Call this method to start the thread.
sensor acquisition thread, acquire data from sensor
virtual void once()
Execute an action exactly once.