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