Fawkes API
Fawkes Development Version
|
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