Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * inifin.h - Fawkes Aspect initializer/finalizer 00004 * 00005 * Created: Tue Jan 30 13:36:42 2007 00006 * Copyright 2006-2009 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. A runtime exception applies to 00014 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00022 */ 00023 00024 #include <aspect/inifin.h> 00025 00026 #include <core/threading/thread.h> 00027 #include <core/macros.h> 00028 #include <blackboard/blackboard.h> 00029 #include <aspect/blackboard.h> 00030 #include <aspect/blocked_timing.h> 00031 #include <aspect/configurable.h> 00032 #include <aspect/logging.h> 00033 #include <aspect/clock.h> 00034 #include <aspect/fawkes_network.h> 00035 #include <aspect/network.h> 00036 #include <aspect/thread_producer.h> 00037 #include <aspect/time_source.h> 00038 #include <aspect/mainloop.h> 00039 #include <aspect/mainloop/employer.h> 00040 #include <aspect/logger.h> 00041 #include <aspect/logger/employer.h> 00042 #include <aspect/plugin_director.h> 00043 #ifdef HAVE_FIREVISION 00044 #include <aspect/vision_master.h> 00045 #include <aspect/vision.h> 00046 #endif 00047 00048 namespace fawkes { 00049 00050 /** @class AspectIniFin <aspect/inifin.h> 00051 * Fawkes Aspect Initializer/Finalizer. 00052 * Initializes certain thread aspects. 00053 * All aspects defined in the Fawkes tree are supported and properly 00054 * initialized such that guarantees are met. 00055 * @see Aspects 00056 * @author Tim Niemueller 00057 */ 00058 00059 00060 /** Constructor. 00061 * @param blackboard BlackBoard 00062 * @param collector Thread collector 00063 * @param config Configuration 00064 * @param logger Logger 00065 * @param clock Clock 00066 */ 00067 AspectIniFin::AspectIniFin(BlackBoard *blackboard, 00068 ThreadCollector *collector, 00069 Configuration *config, 00070 Logger *logger, 00071 Clock *clock) 00072 00073 { 00074 __blackboard = blackboard; 00075 __thread_collector = collector; 00076 __config = config; 00077 __logger = logger; 00078 __clock = clock; 00079 __fnethub = NULL; 00080 __nnresolver = NULL; 00081 __service_publisher = NULL; 00082 __service_browser = NULL; 00083 __mainloop_employer = NULL; 00084 } 00085 00086 00087 /** Destructor. */ 00088 AspectIniFin::~AspectIniFin() 00089 { 00090 } 00091 00092 00093 /** Set Fawkes Network Hub. 00094 * Use this to set the Fawkes Network Hub. If you do not use the Fawkes Network 00095 * you do not need to call this function to set a hub. In that case threads that 00096 * demand the hub will cause an exception to be thrown that the thread cannot be 00097 * initialized. 00098 * @param fnethub Fawkes Network Hub 00099 */ 00100 void 00101 AspectIniFin::set_fnet_hub(FawkesNetworkHub *fnethub) 00102 { 00103 __fnethub = fnethub; 00104 } 00105 00106 00107 /** Set Fawkes MainLoopEmployer. 00108 * Use this to set the Fawkes main loop employer. The main loop employer is used 00109 * to set a new main loop of a plugin with the MainLoopAspect. Uniqueness is 00110 * quaranteed such that only a single main loop exists at any given time. 00111 * @param employer main loop employer 00112 */ 00113 void 00114 AspectIniFin::set_mainloop_employer(MainLoopEmployer *employer) 00115 { 00116 __mainloop_employer = employer; 00117 } 00118 00119 00120 /** Set Fawkes LoggerEmployer. 00121 * @param employer logger employer 00122 */ 00123 void 00124 AspectIniFin::set_logger_employer(LoggerEmployer *employer) 00125 { 00126 __logger_employer = employer; 00127 } 00128 00129 00130 /** Set Fawkes BlockedTimingExecutor. 00131 * Use this to set the Fawkes blocked timing executor. 00132 * @param btexec blocked timing executor instance 00133 */ 00134 void 00135 AspectIniFin::set_blocked_timing_executor(BlockedTimingExecutor *btexec) 00136 { 00137 __btexec = btexec; 00138 } 00139 00140 00141 /** Set Fawkes Network Hub. 00142 * Use this to initialize the NetworkAspect. If you do not use the Network Aspect 00143 * you do not need to call this function to set a hub. In that case threads that 00144 * demand this aspect will cause an exception to be thrown that the thread cannot be 00145 * initialized. 00146 * @param nnresolver network name resolver 00147 * @param service_publisher service publisher 00148 * @param service_browser service browser 00149 */ 00150 void 00151 AspectIniFin::set_network_members(NetworkNameResolver *nnresolver, 00152 ServicePublisher *service_publisher, 00153 ServiceBrowser *service_browser) 00154 { 00155 __nnresolver = nnresolver; 00156 __service_publisher = service_publisher; 00157 __service_browser = service_browser; 00158 } 00159 00160 00161 /** Set plugin manager. 00162 * @param manager PluginManager instance 00163 */ 00164 void 00165 AspectIniFin::set_plugin_manager(PluginManager *manager) 00166 { 00167 __plugin_manager = manager; 00168 } 00169 00170 00171 /** Initialize thread. 00172 * @param thread thread to initialize 00173 */ 00174 void 00175 AspectIniFin::init(Thread *thread) 00176 { 00177 // printf("Initializing thread %s\n", thread->name()); 00178 00179 BlockedTimingAspect *blocked_timing_thread __unused; 00180 if ( (blocked_timing_thread = dynamic_cast<BlockedTimingAspect *>(thread)) != NULL ) { 00181 if ( thread->opmode() != Thread::OPMODE_WAITFORWAKEUP ) { 00182 throw CannotInitializeThreadException("Thread '%s' not in WAITFORWAKEUP mode " 00183 "(required for BlockedTimingAspect)", 00184 thread->name()); 00185 } 00186 } 00187 00188 BlackBoardAspect *blackboard_thread; 00189 if ( (blackboard_thread = dynamic_cast<BlackBoardAspect *>(thread)) != NULL ) { 00190 blackboard_thread->init_BlackBoardAspect( __blackboard ); 00191 } 00192 00193 ThreadProducerAspect *thread_producer_thread; 00194 if ( (thread_producer_thread = dynamic_cast<ThreadProducerAspect *>(thread)) != NULL ) { 00195 thread_producer_thread->init_ThreadProducerAspect( __thread_collector ); 00196 } 00197 00198 ConfigurableAspect *configurable_thread; 00199 if ( (configurable_thread = dynamic_cast<ConfigurableAspect *>(thread)) != NULL ) { 00200 configurable_thread->init_ConfigurableAspect(__config); 00201 } 00202 00203 LoggingAspect *logging_thread; 00204 if ( (logging_thread = dynamic_cast<LoggingAspect *>(thread)) != NULL ) { 00205 logging_thread->init_LoggingAspect(__logger); 00206 } 00207 00208 ClockAspect *clock_thread; 00209 if ( (clock_thread = dynamic_cast<ClockAspect *>(thread)) != NULL ) { 00210 clock_thread->init_ClockAspect(__clock); 00211 } 00212 00213 PluginDirectorAspect *plugin_director_thread; 00214 if ( (plugin_director_thread = dynamic_cast<PluginDirectorAspect *>(thread)) != NULL ) { 00215 if ( thread->opmode() != Thread::OPMODE_CONTINUOUS ) { 00216 throw CannotInitializeThreadException("Thread '%s' not in CONTINUOUS mode " 00217 "(required for PluginDirectorAspect)", 00218 thread->name()); 00219 } 00220 if ( __plugin_manager ) { 00221 plugin_director_thread->init_PluginDirectorAspect(__plugin_manager); 00222 } else { 00223 throw CannotInitializeThreadException("Thread '%s' has PluginDirectorAspect " 00224 "but no PluginManager has been set in " 00225 "AspectIniFin", thread->name()); 00226 } 00227 } 00228 00229 FawkesNetworkAspect *fnet_thread; 00230 if ( (fnet_thread = dynamic_cast<FawkesNetworkAspect *>(thread)) != NULL ) { 00231 if ( __fnethub == NULL ) { 00232 throw CannotInitializeThreadException("Thread '%s' has FawkesNetworkAspect but no " 00233 "FawkesNetworkHub has been set in AspectIniFin", 00234 thread->name()); 00235 } 00236 fnet_thread->init_FawkesNetworkAspect(__fnethub); 00237 } 00238 00239 #ifdef HAVE_FIREVISION 00240 VisionMasterAspect *vision_master_thread; 00241 if ( (vision_master_thread = dynamic_cast<VisionMasterAspect *>(thread)) != NULL ) { 00242 try { 00243 __vision_dependency.add(vision_master_thread); 00244 thread->add_notification_listener(this); 00245 } catch (DependencyViolationException &e) { 00246 CannotInitializeThreadException ce("Dependency violation for VisionProviderAspect " 00247 "detected"); 00248 ce.append(e); 00249 throw ce; 00250 } 00251 } 00252 00253 VisionAspect *vision_thread; 00254 if ( (vision_thread = dynamic_cast<VisionAspect *>(thread)) != NULL ) { 00255 try { 00256 if ( (vision_thread->vision_thread_mode() == VisionAspect::CONTINUOUS) && 00257 (thread->opmode() != Thread::OPMODE_CONTINUOUS) ) { 00258 throw CannotInitializeThreadException("Vision thread '%s' operates in continuous " 00259 "mode but thread does not", thread->name()); 00260 } 00261 if ( (vision_thread->vision_thread_mode() == VisionAspect::CYCLIC) && 00262 (thread->opmode() != Thread::OPMODE_WAITFORWAKEUP) ) { 00263 throw CannotInitializeThreadException("Vision thread '%s' operates in cyclic mode but" 00264 "thread does not operate in wait-for-wakeup " 00265 "mode.", thread->name()); 00266 } 00267 __vision_dependency.add(vision_thread); 00268 vision_thread->init_VisionAspect( __vision_dependency.provider()->vision_master() ); 00269 thread->add_notification_listener(this); 00270 } catch (DependencyViolationException &e) { 00271 CannotInitializeThreadException ce("Dependency violation for VisionAspect detected"); 00272 ce.append(e); 00273 throw ce; 00274 } 00275 } 00276 #endif /* HAVE_FIREVISION */ 00277 00278 NetworkAspect *net_thread; 00279 if ( (net_thread = dynamic_cast<NetworkAspect *>(thread)) != NULL ) { 00280 if ( (__nnresolver == NULL) || (__service_publisher == NULL) || 00281 (__service_browser == NULL) ) { 00282 throw CannotInitializeThreadException("Thread has NetworkAspect but required data " 00283 "has not been set in AspectIniFin"); 00284 } 00285 net_thread->init_NetworkAspect(__nnresolver, __service_publisher, __service_browser); 00286 } 00287 00288 TimeSourceAspect *timesource_thread; 00289 if ( (timesource_thread = dynamic_cast<TimeSourceAspect *>(thread)) != NULL ) { 00290 try { 00291 __timesource_uc.add(timesource_thread->get_timesource()); 00292 __clock->register_ext_timesource(timesource_thread->get_timesource(), 00293 /* make default */ true); 00294 } catch (...) { 00295 throw CannotInitializeThreadException("Thread has TimeSourceAspect but there is " 00296 "already another time provider."); 00297 } 00298 } 00299 00300 MainLoopAspect *mainloop_thread; 00301 if ( (mainloop_thread = dynamic_cast<MainLoopAspect *>(thread)) != NULL ) { 00302 if (thread->opmode() != Thread::OPMODE_WAITFORWAKEUP) { 00303 throw CannotInitializeThreadException("MainLoopAspect thread must operate " 00304 "in wait-for-wakeup mode."); 00305 00306 } 00307 if ( __mainloop_employer == NULL ) { 00308 throw CannotInitializeThreadException("Thread has MainLoopAspect but no " 00309 "MainLoopEmployer has been set."); 00310 } 00311 if ( __btexec == NULL ) { 00312 throw CannotInitializeThreadException("Thread has MainLoopAspect but no " 00313 "BlockedTimingExecutor has been set."); 00314 } 00315 try { 00316 __mainloop_uc.add(mainloop_thread); 00317 mainloop_thread->init_MainLoopAspect(__btexec); 00318 thread->add_notification_listener(this); 00319 } catch (Exception &e) { 00320 CannotInitializeThreadException ce("Main loop thread failed to initialize"); 00321 ce.append(e); 00322 throw ce; 00323 } 00324 } 00325 00326 LoggerAspect *logger_thread; 00327 if ( (logger_thread = dynamic_cast<LoggerAspect *>(thread)) != NULL ) { 00328 if ( __logger_employer == NULL ) { 00329 throw CannotInitializeThreadException("Thread has LoggerAspect but no " 00330 "LoggerEmployer has been set."); 00331 } 00332 try { 00333 __logger_employer->add_logger(logger_thread->get_logger()); 00334 } catch (Exception &e) { 00335 CannotInitializeThreadException ce("Thread has LoggerAspect but Logger " 00336 "could not be added."); 00337 ce.append(e); 00338 throw ce; 00339 } catch (...) { 00340 throw CannotInitializeThreadException("Thread has LoggerAspect but Logger " 00341 "could not be added."); 00342 } 00343 } 00344 } 00345 00346 00347 bool 00348 AspectIniFin::prepare_finalize(Thread *thread) 00349 { 00350 #ifdef HAVE_FIREVISION 00351 VisionMasterAspect *vision_master_thread; 00352 if ( (vision_master_thread = dynamic_cast<VisionMasterAspect *>(thread)) != NULL ) { 00353 if ( ! __vision_dependency.can_remove(vision_master_thread) ) { 00354 __logger->log_error("AspectIniFin", "Cannot remove vision master, there are " 00355 "still vision threads that depend on it"); 00356 return false; 00357 } 00358 } 00359 00360 VisionAspect *vision_thread; 00361 if ( (vision_thread = dynamic_cast<VisionAspect *>(thread)) != NULL ) { 00362 if ( ! __vision_dependency.can_remove(vision_thread) ) { 00363 __logger->log_error("AspectIniFin", "Cannot remove vision thread, dependency " 00364 "violation"); 00365 return false; 00366 } 00367 } 00368 #endif /* HAVE_FIREVISION */ 00369 00370 return true; 00371 } 00372 00373 00374 /** Finalize thread. 00375 * @param thread thread to finalize 00376 */ 00377 void 00378 AspectIniFin::finalize(Thread *thread) 00379 { 00380 #ifdef HAVE_FIREVISION 00381 VisionMasterAspect *vision_master_thread; 00382 if ( (vision_master_thread = dynamic_cast<VisionMasterAspect *>(thread)) != NULL ) { 00383 try { 00384 __vision_dependency.remove(vision_master_thread); 00385 } catch (DependencyViolationException &e) { 00386 CannotFinalizeThreadException ce("Dependency violation for VisionProviderAspect " 00387 "detected"); 00388 ce.append(e); 00389 throw ce; 00390 } 00391 } 00392 00393 VisionAspect *vision_thread; 00394 if ( (vision_thread = dynamic_cast<VisionAspect *>(thread)) != NULL ) { 00395 __vision_dependency.remove(vision_thread); 00396 } 00397 #endif /* HAVE_FIREVISION */ 00398 00399 TimeSourceAspect *timesource_thread; 00400 if ( (timesource_thread = dynamic_cast<TimeSourceAspect *>(thread)) != NULL ) { 00401 try { 00402 __clock->remove_ext_timesource(timesource_thread->get_timesource()); 00403 __timesource_uc.remove(timesource_thread->get_timesource()); 00404 } catch (Exception &e) { 00405 CannotFinalizeThreadException ce("Failed to remove time source"); 00406 ce.append(e); 00407 throw; 00408 } 00409 } 00410 00411 MainLoopAspect *mainloop_thread; 00412 if ( (mainloop_thread = dynamic_cast<MainLoopAspect *>(thread)) != NULL ) { 00413 try { 00414 if (__mainloop_uc.resource() == mainloop_thread) { 00415 __mainloop_employer->set_mainloop_thread(NULL); 00416 __mainloop_uc.remove(mainloop_thread); 00417 } 00418 } catch (Exception &e) { 00419 CannotFinalizeThreadException ce("Failed to remove main loop"); 00420 ce.append(e); 00421 throw; 00422 } 00423 } 00424 00425 LoggerAspect *logger_thread; 00426 if ( (logger_thread = dynamic_cast<LoggerAspect *>(thread)) != NULL ) { 00427 try { 00428 __logger_employer->remove_logger(logger_thread->get_logger()); 00429 } catch (Exception &e) { 00430 CannotFinalizeThreadException ce("Failed to remove logger"); 00431 ce.append(e); 00432 throw; 00433 } 00434 } 00435 } 00436 00437 00438 bool 00439 AspectIniFin::thread_started(Thread *thread) throw() 00440 { 00441 MainLoopAspect *mainloop_thread; 00442 if ( (mainloop_thread = dynamic_cast<MainLoopAspect *>(thread)) != NULL ) { 00443 try { 00444 __mainloop_employer->set_mainloop_thread(thread); 00445 } catch (Exception &e) { 00446 __logger->log_error("AspectIniFin", "Main loop thread started successfully but " 00447 "could not add main loop thread's main loop"); 00448 } 00449 } 00450 00451 return false; 00452 } 00453 00454 00455 bool 00456 AspectIniFin::thread_init_failed(Thread *thread) throw() 00457 { 00458 MainLoopAspect *mainloop_thread; 00459 if ( (mainloop_thread = dynamic_cast<MainLoopAspect *>(thread)) != NULL ) { 00460 try { 00461 __mainloop_uc.remove(mainloop_thread); 00462 } catch (Exception &e) { 00463 __logger->log_error("AspectIniFin", "Failed to remove main loop from uniqueness " 00464 "constraint on thread init fail of %s", thread->name()); 00465 } 00466 } 00467 00468 try { 00469 finalize(thread); 00470 } catch (Exception &e) { 00471 __logger->log_error("AspectIniFin", "Initialization of thread '%s' failed, but " 00472 "the thread thread could not be internally finalized", 00473 thread->name()); 00474 __logger->log_error("AspectIniFin", e); 00475 } 00476 00477 return false; 00478 } 00479 00480 } // end namespace fawkes