Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * message_queue.cpp - BlackBoard Interface message queue 00004 * 00005 * Created: Tue Oct 18 15:43:29 2006 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 <interface/message_queue.h> 00025 #include <interface/message.h> 00026 00027 #include <core/threading/mutex.h> 00028 #include <core/exceptions/software.h> 00029 00030 #include <cstddef> 00031 #include <cstdlib> 00032 00033 namespace fawkes { 00034 00035 /** @class MessageAlreadyQueuedException <interface/message_queue.h> 00036 * Message already enqueued exception. 00037 * This exception is thrown if you try to enqueue a message that has already 00038 * been enqueued in another message queue. This is an illegal operation. If you 00039 * need to enqueue a message multiple times use the copy constructor to do this. 00040 */ 00041 00042 00043 /** Constructor. */ 00044 MessageAlreadyQueuedException::MessageAlreadyQueuedException() 00045 : Exception("Message already enqueued in another MessageQueue.") 00046 { 00047 } 00048 00049 00050 00051 /** @class MessageQueue <interface/message_queue.h> 00052 * Message queue used in interfaces. 00053 * This message queue handles the basic messaging operations. The methods the 00054 * Interface provides for handling message queues are forwarded to a 00055 * MessageQueue instance. 00056 * @see Interface 00057 */ 00058 00059 00060 /** Constructor. */ 00061 MessageQueue::MessageQueue() 00062 { 00063 __list = NULL; 00064 __end_el = NULL; 00065 __mutex = new Mutex(); 00066 } 00067 00068 00069 /** Destructor */ 00070 MessageQueue::~MessageQueue() 00071 { 00072 flush(); 00073 delete __mutex; 00074 } 00075 00076 00077 /** Delete all messages from queue. 00078 * This method deletes all messages from the queue. 00079 */ 00080 void 00081 MessageQueue::flush() 00082 { 00083 __mutex->lock(); 00084 // free list elements 00085 msg_list_t *l = __list; 00086 msg_list_t *next; 00087 while ( l ) { 00088 next = l->next; 00089 l->msg->unref(); 00090 free(l); 00091 l = next; 00092 } 00093 __list = NULL; 00094 __mutex->unlock(); 00095 } 00096 00097 00098 /** Append message to queue. 00099 * @param msg Message to append 00100 * @exception MessageAlreadyQueuedException thrown if the message has already been 00101 * enqueued to an interface. 00102 */ 00103 void 00104 MessageQueue::append(Message *msg) 00105 { 00106 if ( msg->enqueued() != 0 ) { 00107 throw MessageAlreadyQueuedException(); 00108 } 00109 __mutex->lock(); 00110 msg->mark_enqueued(); 00111 if ( __list == NULL ) { 00112 __list = (msg_list_t *)malloc(sizeof(msg_list_t)); 00113 __list->next = NULL; 00114 __list->msg = msg; 00115 __list->msg_id = msg->id(); 00116 __end_el = __list; 00117 } else { 00118 msg_list_t *l = (msg_list_t *)malloc(sizeof(msg_list_t)); 00119 l->next = NULL; 00120 l->msg = msg; 00121 l->msg_id = msg->id(); 00122 __end_el->next = l; 00123 __end_el = l; 00124 } 00125 00126 __mutex->unlock(); 00127 } 00128 00129 00130 /** Enqueue message after given iterator. 00131 * @param it Iterator 00132 * @param msg Message to enqueue 00133 * @return message queue id of the appended message. 00134 * @exception NullPointerException thrown if iterator is end iterator. 00135 * @exception NotLockedException thrown if message queue is not locked during this operation. 00136 * @exception MessageAlreadyQueuedException thrown if the message has already been 00137 * enqueued to an interface. 00138 */ 00139 void 00140 MessageQueue::insert_after(const MessageIterator &it, Message *msg) 00141 { 00142 if ( __mutex->try_lock() ) { 00143 __mutex->unlock(); 00144 throw NotLockedException("Message queue must be locked to insert messages after iterator."); 00145 } 00146 if ( it.cur == NULL ) { 00147 throw NullPointerException("Cannot append message at end element."); 00148 } 00149 if ( msg->enqueued() != 0 ) { 00150 throw MessageAlreadyQueuedException(); 00151 } 00152 msg->mark_enqueued(); 00153 msg_list_t *l = (msg_list_t *)malloc(sizeof(msg_list_t)); 00154 l->next = it.cur->next; 00155 l->msg = msg; 00156 l->msg_id = msg->id(); 00157 it.cur->next = l; 00158 if ( l->next == NULL ) { 00159 __end_el = l; 00160 } 00161 } 00162 00163 00164 /** Remove message from queue. 00165 * @param msg message to remove 00166 */ 00167 void 00168 MessageQueue::remove(const Message *msg) 00169 { 00170 __mutex->lock(); 00171 msg_list_t *l = __list; 00172 msg_list_t *p = NULL; 00173 while ( l ) { 00174 if ( l->msg == msg ) { 00175 remove(l, p); 00176 break; 00177 } else { 00178 p = l; 00179 l = l->next; 00180 } 00181 } 00182 __mutex->unlock(); 00183 } 00184 00185 00186 /** Remove message from queue by message id. 00187 * @param msg_id id of message to remove 00188 */ 00189 void 00190 MessageQueue::remove(const unsigned int msg_id) 00191 { 00192 __mutex->lock(); 00193 msg_list_t *l = __list; 00194 msg_list_t *p = NULL; 00195 while ( l ) { 00196 if ( l->msg_id == msg_id ) { 00197 remove(l, p); 00198 break; 00199 } else { 00200 p = l; 00201 l = l->next; 00202 } 00203 } 00204 __mutex->unlock(); 00205 } 00206 00207 00208 /** Remove message from list. 00209 * @param l list item to remove 00210 * @param p predecessor of element, may be NULL if there is none 00211 */ 00212 void 00213 MessageQueue::remove(msg_list_t *l, msg_list_t *p) 00214 { 00215 if ( __mutex->try_lock() ) { 00216 __mutex->unlock(); 00217 throw NotLockedException("Protected remove must be made safe by locking."); 00218 } 00219 if ( p ) { 00220 p->next = l->next; 00221 } else { 00222 // was first element 00223 __list = l->next; 00224 } 00225 l->msg->unref(); 00226 free(l); 00227 } 00228 00229 00230 /** Get number of messages in queue. 00231 * @return number of messages in queue. 00232 */ 00233 unsigned int 00234 MessageQueue::size() const 00235 { 00236 __mutex->lock(); 00237 unsigned int rv = 0; 00238 msg_list_t *l = __list; 00239 while ( l ) { 00240 ++rv; 00241 l = l->next; 00242 } 00243 00244 __mutex->unlock(); 00245 return rv; 00246 } 00247 00248 00249 /** Check if message queue is empty. 00250 * @return true if message queue is empty, false otherwise 00251 */ 00252 bool 00253 MessageQueue::empty() const 00254 { 00255 __mutex->lock(); 00256 bool rv = ( __list == NULL ); 00257 __mutex->unlock(); 00258 return rv; 00259 } 00260 00261 00262 /** Lock message queue. 00263 * No operations can be performed on the message queue after locking it. 00264 * Note that you cannot call any method of the message queue as long as 00265 * the queue is locked. Use lock() only to have a secure run-through with 00266 * the MessageIterator. 00267 */ 00268 void 00269 MessageQueue::lock() 00270 { 00271 __mutex->lock(); 00272 } 00273 00274 00275 /** Try to lock message queue. 00276 * No operations can be performed on the message queue after locking it. 00277 * Note that you cannot call any method of the message queue as long as 00278 * the queue is locked. Use try_lock() only to have a secure run-through with 00279 * the MessageIterator. 00280 * @return true, if the lock has been aquired, false otherwise. 00281 */ 00282 bool 00283 MessageQueue::try_lock() 00284 { 00285 return __mutex->try_lock(); 00286 } 00287 00288 00289 /** Unlock message queue. 00290 */ 00291 void 00292 MessageQueue::unlock() 00293 { 00294 __mutex->unlock(); 00295 } 00296 00297 00298 /** Get first message from queue. 00299 * @return first message from queue 00300 */ 00301 Message * 00302 MessageQueue::first() 00303 { 00304 if ( __list ) { 00305 return __list->msg; 00306 } else { 00307 return NULL; 00308 } 00309 } 00310 00311 00312 /** Erase first message from queue. 00313 */ 00314 void 00315 MessageQueue::pop() 00316 { 00317 __mutex->lock(); 00318 if ( __list ) { 00319 remove(__list, NULL); 00320 } 00321 __mutex->unlock(); 00322 } 00323 00324 00325 /** Get iterator to first element in message queue. 00326 * @return iterator to first element in message queue 00327 * @exception NotLockedException thrown if message queue is not locked during this operation. 00328 */ 00329 MessageQueue::MessageIterator 00330 MessageQueue::begin() 00331 { 00332 if ( __mutex->try_lock() ) { 00333 __mutex->unlock(); 00334 throw NotLockedException("Message queue must be locked to get begin iterator."); 00335 } 00336 return MessageIterator(__list); 00337 } 00338 00339 00340 /** Get iterator to element beyond end of message queue list. 00341 * @return iterator to element beyond end of message queue list 00342 * @exception NotLockedException thrown if message queue is not locked during this operation. 00343 */ 00344 MessageQueue::MessageIterator 00345 MessageQueue::end() 00346 { 00347 if ( __mutex->try_lock() ) { 00348 __mutex->unlock(); 00349 throw NotLockedException("Message queue must be locked to get end iterator."); 00350 } 00351 return MessageIterator(); 00352 } 00353 00354 00355 /** @class MessageQueue::MessageIterator message_queue.h <interface/message_queue.h> 00356 * Message iterator. 00357 * Use this iterator to iterate over messages in a message queue. 00358 * Use MessageQueue::begin() to get the iterator. 00359 * @author Tim Niemueller 00360 */ 00361 00362 /** Constructor 00363 * @param cur Current element for message list 00364 */ 00365 MessageQueue::MessageIterator::MessageIterator(msg_list_t *cur) 00366 { 00367 this->cur = cur; 00368 } 00369 00370 00371 /** Constructor */ 00372 MessageQueue::MessageIterator::MessageIterator() 00373 { 00374 cur = NULL; 00375 } 00376 00377 00378 /** Copy constructor. 00379 * @param it Iterator to copy 00380 */ 00381 MessageQueue::MessageIterator::MessageIterator(const MessageIterator &it) 00382 { 00383 cur = it.cur; 00384 } 00385 00386 00387 /** Increment iterator. 00388 * Advances to the next element. This is the infix-operator. It may be used 00389 * like this: 00390 * @code 00391 * for (MessageIterator cit = msgq->begin(); cit != msgq->end(); ++cit) { 00392 * // your code here 00393 * } 00394 * @endcode 00395 * @return Reference to instance itself after advancing to the next element. 00396 */ 00397 MessageQueue::MessageIterator & 00398 MessageQueue::MessageIterator::operator++() 00399 { 00400 if ( cur != NULL ) 00401 cur = cur->next; 00402 00403 return *this; 00404 } 00405 00406 00407 /** Increment iterator. 00408 * Advances to the next element in allocated chunk list. This is the postfix-operator. 00409 * It may be used like this: 00410 * @code 00411 * for (MessageIterator cit = memmgr->begin(); cit != memmgr->end(); cit++) { 00412 * // your code here 00413 * } 00414 * @endcode 00415 * Note that since a copy of the original iterator has to be created an returned it 00416 * the postfix operation takes both, more CPU time and more memory. If possible (especially 00417 * if used in a for loop like the example) use the prefix operator! 00418 * @see operator++() 00419 * @param inc ignored 00420 * @return copy of the current instance before advancing to the next element. 00421 */ 00422 MessageQueue::MessageIterator 00423 MessageQueue::MessageIterator::operator++(int inc) 00424 { 00425 MessageIterator rv(cur); 00426 if ( cur != NULL ) 00427 cur = cur->next; 00428 00429 return rv; 00430 } 00431 00432 00433 /** Advance by a certain amount. 00434 * Can be used to add an integer to the iterator to advance many steps in one go. 00435 * This operation takes linear time depending on i. 00436 * @param i steps to advance in list. If i is bigger than the number of remaining 00437 * elements in the list will stop beyond list. 00438 * @return reference to current instance after advancing i steps or after reaching 00439 * end of list. 00440 */ 00441 MessageQueue::MessageIterator & 00442 MessageQueue::MessageIterator::operator+(unsigned int i) 00443 { 00444 for (unsigned int j = 0; (cur != NULL) && (j < i); ++j) { 00445 cur = cur->next; 00446 } 00447 return *this; 00448 } 00449 00450 00451 /** Advance by a certain amount. 00452 * Works like operator+(unsigned int i), provided for convenience. 00453 * @param i steps to advance in list 00454 * @return reference to current instance after advancing i steps or after reaching 00455 * end of list. 00456 */ 00457 MessageQueue::MessageIterator & 00458 MessageQueue::MessageIterator::operator+=(unsigned int i) 00459 { 00460 for (unsigned int j = 0; (cur != NULL) && (j < i); ++j) { 00461 cur = cur->next; 00462 } 00463 return *this; 00464 } 00465 00466 00467 /** Check equality of two iterators. 00468 * Can be used to determine if two iterators point to the same chunk. 00469 * @param c iterator to compare current instance to 00470 * @return true, if iterators point to the same chunk, false otherwise 00471 */ 00472 bool 00473 MessageQueue::MessageIterator::operator==(const MessageIterator & c) const 00474 { 00475 return (cur == c.cur); 00476 } 00477 00478 00479 /** Check inequality of two iterators. 00480 * Can be used to determine if two iterators point to different chunks. 00481 * @param c iterator to compare current instance to 00482 * @return true, if iterators point to different chunks of memory, false otherwise 00483 */ 00484 bool 00485 MessageQueue::MessageIterator::operator!=(const MessageIterator & c) const 00486 { 00487 return (cur != c.cur); 00488 } 00489 00490 00491 /** Get memory pointer of chunk. 00492 * Use this operator to get the pointer to the chunk of memory that this iterator 00493 * points to. 00494 * @return pointer to memory 00495 */ 00496 Message * 00497 MessageQueue::MessageIterator::operator*() const 00498 { 00499 return ( cur != NULL ) ? cur->msg : NULL; 00500 } 00501 00502 00503 /** Act on current message. 00504 * Node that you have to make sure that this is not called on the end node! 00505 * @return current message 00506 */ 00507 Message * 00508 MessageQueue::MessageIterator::operator->() const 00509 { 00510 return cur->msg; 00511 } 00512 00513 00514 /** Assign iterator. 00515 * Makes the current instance to point to the same memory element as c. 00516 * @param c assign value 00517 * @return reference to current instance 00518 */ 00519 MessageQueue::MessageIterator & 00520 MessageQueue::MessageIterator::operator=(const MessageIterator & c) 00521 { 00522 this->cur = c.cur; 00523 return *this; 00524 } 00525 00526 00527 /** Get ID of current element or 0 if element is end. 00528 * @return ID of current element or 0 if element is end. 00529 */ 00530 unsigned int 00531 MessageQueue::MessageIterator::id() const 00532 { 00533 if ( cur == NULL ) return 0; 00534 return cur->msg_id; 00535 } 00536 00537 } // end namespace fawkes