inifin.cpp

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