interface_manager.cpp

00001  
00002 /***************************************************************************
00003  *  interface_manager.cpp - BlackBoard interface manager
00004  *
00005  *  Created: Mon Oct 09 19:08:29 2006
00006  *  Copyright  2006-2008  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 <blackboard/internal/interface_manager.h>
00025 
00026 #include <blackboard/blackboard.h>
00027 #include <blackboard/internal/memory_manager.h>
00028 #include <blackboard/internal/message_manager.h>
00029 #include <blackboard/exceptions.h>
00030 #include <blackboard/internal/interface_mem_header.h>
00031 #include <blackboard/interface_listener.h>
00032 #include <blackboard/interface_observer.h>
00033 #include <blackboard/internal/instance_factory.h>
00034 #include <blackboard/internal/notifier.h>
00035 
00036 #include <interface/interface.h>
00037 #include <interface/interface_info.h>
00038 
00039 #include <core/threading/mutex.h>
00040 #include <core/threading/refc_rwlock.h>
00041 #include <core/exceptions/system.h>
00042 #include <utils/system/dynamic_module/module_dl.h>
00043 #include <utils/logging/liblogger.h>
00044 
00045 #include <cstdlib>
00046 #include <cstring>
00047 #include <fnmatch.h>
00048 
00049 namespace fawkes {
00050 
00051 /** @class BlackBoardInterfaceManager <blackboard/internal/interface_manager.h>
00052  * BlackBoard interface manager.
00053  * This class is used by the BlackBoard to manage interfaces stored in the
00054  * shared memory.
00055  *
00056  * @author Tim Niemueller
00057  */
00058 
00059 
00060 /** Constructor.
00061  * The shared memory segment is created with data from bbconfig.h.
00062  * @param bb_memmgr BlackBoard memory manager to use
00063  * @param bb_msgmgr BlackBoard message manager to use
00064  * @param bb_notifier BlackBoard notifier to all for events
00065  * @see bbconfig.h
00066  */
00067 BlackBoardInterfaceManager::BlackBoardInterfaceManager(BlackBoardMemoryManager *bb_memmgr,
00068                                                        BlackBoardMessageManager *bb_msgmgr,
00069                                                        BlackBoardNotifier *bb_notifier)
00070 {
00071   memmgr = bb_memmgr;
00072   msgmgr = bb_msgmgr;
00073   notifier = bb_notifier;
00074 
00075   instance_serial = 1;
00076   instance_factory = new BlackBoardInstanceFactory();
00077   mutex = new Mutex();
00078 
00079   writer_interfaces.clear();
00080   rwlocks.clear();
00081 }
00082 
00083 
00084 /** Destructor */
00085 BlackBoardInterfaceManager::~BlackBoardInterfaceManager()
00086 {
00087   delete mutex;
00088   delete instance_factory;
00089 }
00090 
00091 
00092 /** Creates a new interface instance.
00093  * This method will look in the libinterfaces shared object for a factory function
00094  * for the interface of the given type. If this was found a new instance of the
00095  * interface is returned.
00096  * @param type type of the interface
00097  * @param identifier identifier of the interface
00098  * @return a new instance of the requested interface type
00099  * @exception BlackBoardInterfaceNotFoundException thrown if the factory function
00100  * for the given interface type could not be found
00101  */
00102 Interface *
00103 BlackBoardInterfaceManager::new_interface_instance(const char *type, const char *identifier)
00104 {
00105   Interface *iface = instance_factory->new_interface_instance(type, identifier);
00106 
00107   iface->set_instance_serial(next_instance_serial());
00108   iface->set_mediators(this, msgmgr);
00109   return iface;
00110 }
00111 
00112 
00113 /** Destroy an interface instance.
00114  * The destroyer function for the given interface is called to destroy the given
00115  * interface instance.
00116  * @param interface to destroy
00117  * @exception BlackBoardInterfaceNotFoundException thrown if the destroyer function
00118  * for the given interface could not be found. The interface will not be freed.
00119  */
00120 void
00121 BlackBoardInterfaceManager::delete_interface_instance(Interface *interface)
00122 {
00123   instance_factory->delete_interface_instance(interface);
00124 }
00125 
00126 
00127 /** search memory chunks if the desired interface has been allocated already.
00128  * @param type type of the interface to look for
00129  * @param identifier identifier of the interface to look for
00130  * @return a pointer to the memory of the interface or NULL if not found
00131  */
00132 void *
00133 BlackBoardInterfaceManager::find_interface_in_memory(const char *type, const char *identifier)
00134 {
00135   interface_header_t *ih;
00136   BlackBoardMemoryManager::ChunkIterator cit;
00137   for ( cit = memmgr->begin(); cit != memmgr->end(); ++cit ) {
00138     ih = (interface_header_t *)*cit;
00139     if ( (strncmp(ih->type, type, __INTERFACE_TYPE_SIZE) == 0) &&
00140          (strncmp(ih->id, identifier, __INTERFACE_ID_SIZE) == 0)
00141          ) {
00142       // found it!
00143       return *cit;
00144     }
00145   }
00146 
00147   return NULL;
00148 }
00149 
00150 
00151 /** Get next mem serial.
00152  * @return next unique memory serial
00153  */
00154 unsigned int
00155 BlackBoardInterfaceManager::next_mem_serial()
00156 {
00157   unsigned int serial = 1;
00158   interface_header_t *ih;
00159   BlackBoardMemoryManager::ChunkIterator cit;
00160   for ( cit = memmgr->begin(); cit != memmgr->end(); ++cit ) {
00161     ih = (interface_header_t *)*cit;
00162     if ( ih->serial >= serial ) {
00163       serial = ih->serial + 1;
00164     }
00165   }
00166 
00167   return serial;
00168 }
00169 
00170 
00171 /** Get next instance serial.
00172  * @return next unique instance serial
00173  */
00174 unsigned int
00175 BlackBoardInterfaceManager::next_instance_serial()
00176 {
00177   if ( memmgr->is_master() ) {
00178     // simple, just increment value and return it
00179     return instance_serial++;
00180   } else {
00181     throw BBNotMasterException("Instance serial can only be requested by BB Master");
00182   }
00183 }
00184 
00185 
00186 /** Create an interface instance.
00187  * This will create a new interface instance. Storage in the shared memory
00188  * is allocated to hold the interface data.
00189  * @param type type of the interface
00190  * @param identifier identifier of the interface
00191  * @param interface reference to a pointer where the interface will be created
00192  * @param ptr reference to pointer of interface memory
00193  * @exception OutOfMemoryException thrown if there is not enough memory in the
00194  * BlackBoard to create the interface
00195  */
00196 void
00197 BlackBoardInterfaceManager::create_interface(const char *type, const char *identifier,
00198                                              Interface* &interface, void* &ptr)
00199 {
00200   interface_header_t *ih;
00201 
00202   // create new interface and allocate appropriate chunk
00203   interface = new_interface_instance(type, identifier);
00204   try {
00205     ptr = memmgr->alloc_nolock(interface->datasize() + sizeof(interface_header_t));
00206     ih  = (interface_header_t *)ptr;
00207   } catch (OutOfMemoryException &e) {
00208     e.append("BlackBoardInterfaceManager::createInterface: interface of type %s could not be created", type);
00209     memmgr->unlock();
00210     mutex->unlock();
00211     throw;
00212   }
00213   memset(ptr, 0, interface->datasize() + sizeof(interface_header_t));
00214 
00215   strncpy(ih->type, type, __INTERFACE_TYPE_SIZE);
00216   strncpy(ih->id, identifier, __INTERFACE_ID_SIZE);
00217   memcpy(ih->hash, interface->hash(), __INTERFACE_HASH_SIZE);
00218 
00219   ih->refcount           = 0;
00220   ih->serial             = next_mem_serial();
00221   ih->flag_writer_active = 0;
00222   ih->num_readers        = 0;
00223   rwlocks[ih->serial] = new RefCountRWLock();
00224 
00225   interface->set_memory(ih->serial, ptr, (char *)ptr + sizeof(interface_header_t));
00226 }
00227 
00228 
00229 /** Open interface for reading.
00230  * This will create a new interface instance of the given type. The result can be
00231  * casted to the appropriate type.
00232  * @param type type of the interface
00233  * @param identifier identifier of the interface
00234  * @return new fully initialized interface instance of requested type
00235  * @exception OutOfMemoryException thrown if there is not enough free space for
00236  * the requested interface.
00237  */
00238 Interface *
00239 BlackBoardInterfaceManager::open_for_reading(const char *type, const char *identifier)
00240 {
00241   mutex->lock();
00242   Interface *iface = NULL;
00243   void *ptr = NULL;
00244   interface_header_t *ih;
00245   bool created = false;
00246 
00247   memmgr->lock();
00248 
00249   ptr = find_interface_in_memory(type, identifier);
00250 
00251   try {
00252     if ( ptr != NULL ) {
00253       // found, instantiate new interface for given memory chunk
00254       iface = new_interface_instance(type, identifier);
00255       ih  = (interface_header_t *)ptr;
00256       if ( (iface->hash_size() != __INTERFACE_HASH_SIZE ) ||
00257            (memcmp(iface->hash(), ih->hash, __INTERFACE_HASH_SIZE) != 0) ) {
00258         throw BlackBoardInterfaceVersionMismatchException();
00259       }
00260       iface->set_memory(ih->serial, ptr, (char *)ptr + sizeof(interface_header_t));
00261       rwlocks[ih->serial]->ref();
00262     } else {
00263       created = true;
00264       create_interface(type, identifier, iface, ptr);
00265       ih  = (interface_header_t *)ptr;
00266     }
00267 
00268     iface->set_readwrite(false, rwlocks[ih->serial]);
00269     ih->refcount++;
00270     ih->num_readers++;
00271 
00272     memmgr->unlock();
00273     mutex->unlock();
00274 
00275     if ( created ) {
00276       notifier->notify_of_interface_created(type, identifier);
00277     }
00278     notifier->notify_of_reader_added(iface, iface->serial());
00279 
00280   } catch (Exception &e) {
00281     if (iface)  delete_interface_instance(iface);
00282     memmgr->unlock();
00283     mutex->unlock();
00284     throw;
00285   }
00286 
00287   return iface;
00288 }
00289 
00290 
00291 /** Open all interfaces of the given type for reading.
00292  * This will create interface instances for all currently registered interfaces of
00293  * the given type. The result can be casted to the appropriate type.
00294  * @param type type of the interface
00295  * @param id_pattern pattern of interface IDs to open, supports wildcards similar
00296  * to filenames (*, ?, []), see "man fnmatch" for all supported.
00297  * @return list of new fully initialized interface instances of requested type. The
00298  * is allocated using new and you have to free it using delete after you are done
00299  * with it!
00300  */
00301 std::list<Interface *>
00302 BlackBoardInterfaceManager::open_multiple_for_reading(const char *type,
00303                                                       const char *id_pattern)
00304 {
00305   mutex->lock();
00306   memmgr->lock();
00307 
00308   std::list<Interface *> rv;
00309 
00310   Interface *iface = NULL;
00311   interface_header_t *ih;
00312   BlackBoardMemoryManager::ChunkIterator cit;
00313 
00314   try {
00315     for ( cit = memmgr->begin(); cit != memmgr->end(); ++cit ) {
00316       iface = NULL;
00317       ih = (interface_header_t *)*cit;
00318 
00319       if ((strncmp(type, ih->type, __INTERFACE_TYPE_SIZE) != 0) ||
00320           (fnmatch(id_pattern, ih->id, 0) == FNM_NOMATCH) ) {
00321         // type or ID prefix does not match, go on
00322         continue;
00323       }
00324 
00325       void *ptr = *cit;
00326       iface = new_interface_instance(ih->type, ih->id);
00327       iface->set_memory(ih->serial, ptr, (char *)ptr + sizeof(interface_header_t));
00328 
00329       if ( (iface->hash_size() != __INTERFACE_HASH_SIZE ) ||
00330            (memcmp(iface->hash(), ih->hash, __INTERFACE_HASH_SIZE) != 0) ) {
00331         throw BlackBoardInterfaceVersionMismatchException();
00332       }
00333 
00334       rwlocks[ih->serial]->ref();
00335 
00336       iface->set_readwrite(false, rwlocks[ih->serial]);
00337       ih->refcount++;
00338       ih->num_readers++;
00339 
00340       rv.push_back(iface);
00341     }
00342 
00343     mutex->unlock();
00344     memmgr->unlock();
00345 
00346     for (std::list<Interface *>::iterator j = rv.begin(); j != rv.end(); ++j) {
00347       notifier->notify_of_reader_added(*j, (*j)->serial());
00348     }
00349 
00350 
00351   } catch (Exception &e) {
00352     if (iface)  delete_interface_instance( iface );
00353     for (std::list<Interface *>::iterator i = rv.begin(); i != rv.end(); ++i) {
00354       delete_interface_instance(*i);
00355     }
00356     memmgr->unlock();
00357     mutex->unlock();
00358     throw;
00359   }
00360 
00361   return rv;
00362 }
00363 
00364 
00365 /** Open interface for writing.
00366  * This will create a new interface instance of the given type. The result can be
00367  * casted to the appropriate type. This will only succeed if there is not already
00368  * a writer for the given interface type/id!
00369  * @param type type of the interface
00370  * @param identifier identifier of the interface
00371  * @return new fully initialized interface instance of requested type
00372  * @exception OutOfMemoryException thrown if there is not enough free space for
00373  * the requested interface.
00374  * @exception BlackBoardWriterActiveException thrown if there is already a writing
00375  * instance with the same type/id
00376  */
00377 Interface *
00378 BlackBoardInterfaceManager::open_for_writing(const char *type, const char *identifier)
00379 {
00380   mutex->lock();
00381   memmgr->lock();
00382 
00383   Interface *iface = NULL;
00384   void *ptr = NULL;
00385   interface_header_t *ih;
00386   bool created = false;
00387 
00388   try {
00389     ptr = find_interface_in_memory(type, identifier);
00390 
00391     if ( ptr != NULL ) {
00392       // found, check if there is already a writer
00393       //instantiate new interface for given memory chunk
00394       ih  = (interface_header_t *)ptr;
00395       if ( ih->flag_writer_active ) {
00396         throw BlackBoardWriterActiveException(identifier, type);
00397       }
00398       iface = new_interface_instance(type, identifier);
00399       if ( (iface->hash_size() != __INTERFACE_HASH_SIZE ) ||
00400            (memcmp(iface->hash(), ih->hash, __INTERFACE_HASH_SIZE) != 0) ) {
00401         throw BlackBoardInterfaceVersionMismatchException();
00402       }
00403       iface->set_memory(ih->serial, ptr, (char *)ptr + sizeof(interface_header_t));
00404       rwlocks[ih->serial]->ref();
00405     } else {
00406       created = true;
00407       create_interface(type, identifier, iface, ptr);
00408       ih = (interface_header_t *)ptr;
00409     }
00410 
00411     iface->set_readwrite(true, rwlocks[ih->serial]);
00412     ih->flag_writer_active = 1;
00413     ih->refcount++;
00414 
00415     memmgr->unlock();
00416     writer_interfaces[ih->serial] = iface;
00417 
00418     mutex->unlock();
00419 
00420     if ( created ) {
00421       notifier->notify_of_interface_created(type, identifier);
00422     }
00423     notifier->notify_of_writer_added(iface, iface->serial());
00424   } catch (Exception &e) {
00425     if (iface)  delete_interface_instance(iface);
00426     memmgr->unlock();
00427     mutex->unlock();
00428     throw;
00429   }
00430 
00431   return iface;
00432 }
00433 
00434 
00435 /** Close interface.
00436  * @param interface interface to close
00437  */
00438 void
00439 BlackBoardInterfaceManager::close(Interface *interface)
00440 {
00441   if ( interface == NULL ) return;
00442   mutex->lock();
00443   bool destroyed = false;
00444 
00445   // reduce refcount and free memory if refcount is zero
00446   interface_header_t *ih = (interface_header_t *)interface->__mem_real_ptr;
00447   bool killed_writer = interface->__write_access;
00448   if ( --(ih->refcount) == 0 ) {
00449     // redeem from memory
00450     if ( interface->__write_access ) {
00451       writer_interfaces.erase( interface->__mem_serial );
00452     }
00453     memmgr->free( interface->__mem_real_ptr );
00454     destroyed = true;
00455   } else {
00456     if ( interface->__write_access ) {
00457       ih->flag_writer_active = 0;
00458       writer_interfaces.erase( interface->__mem_serial );
00459     } else {
00460       ih->num_readers--;
00461     }
00462   }
00463 
00464   mutex->unlock();
00465   if (killed_writer) {
00466     notifier->notify_of_writer_removed(interface, interface->serial());
00467   } else {
00468     notifier->notify_of_reader_removed(interface, interface->serial());
00469   }
00470   if ( destroyed ) {
00471     notifier->notify_of_interface_destroyed(interface->__type, interface->__id);
00472   }
00473 
00474   mutex->lock();
00475   delete_interface_instance( interface );
00476   mutex->unlock();
00477 }
00478 
00479 
00480 /** Get a list of interfaces.
00481  * @return list of currently existing interfaces. List may be outdated on
00482  * return since there maybe concurrent actions.
00483  */
00484 InterfaceInfoList *
00485 BlackBoardInterfaceManager::list_all() const
00486 {
00487   InterfaceInfoList *infl = new InterfaceInfoList();
00488 
00489   memmgr->lock();
00490   interface_header_t *ih;
00491   BlackBoardMemoryManager::ChunkIterator cit;
00492   for ( cit = memmgr->begin(); cit != memmgr->end(); ++cit ) {
00493     ih = (interface_header_t *)*cit;
00494     infl->append(ih->type, ih->id, ih->hash, ih->serial,
00495                  ih->flag_writer_active, ih->num_readers);
00496   }
00497 
00498   memmgr->unlock();
00499 
00500   return infl;
00501 }
00502 
00503 
00504 /** Get the writer interface for the given mem serial.
00505  * @param mem_serial memory serial to get writer for
00506  * @return writer interface for given mem serial, or NULL if non exists
00507  * @exception BlackBoardNoWritingInstanceException thrown if no writer
00508  * was found for the given interface.
00509  */
00510 Interface *
00511 BlackBoardInterfaceManager::writer_for_mem_serial(unsigned int mem_serial)
00512 {
00513   if ( writer_interfaces.find(mem_serial) != writer_interfaces.end() ) {
00514     return writer_interfaces[mem_serial];
00515   } else {
00516     throw BlackBoardNoWritingInstanceException();
00517   }
00518 }
00519 
00520 
00521 void
00522 BlackBoardInterfaceManager::notify_of_data_change(const Interface *interface)
00523 {
00524   notifier->notify_of_data_change(interface);
00525 }
00526 
00527 
00528 bool
00529 BlackBoardInterfaceManager::exists_writer(const Interface *interface) const
00530 {
00531   return (writer_interfaces.find(interface->__mem_serial) != writer_interfaces.end());
00532 }
00533 
00534 
00535 unsigned int
00536 BlackBoardInterfaceManager::num_readers(const Interface *interface) const
00537 {
00538   const interface_header_t *ih = (interface_header_t *)interface->__mem_real_ptr;
00539   return ih->num_readers;
00540 }
00541 
00542 } // end namespace fawkes

Generated on 1 Mar 2011 for Fawkes API by  doxygen 1.6.1