Fawkes API Fawkes Development Version
message_queue.cpp
1
2/***************************************************************************
3 * message_queue.cpp - BlackBoard Interface message queue
4 *
5 * Created: Tue Oct 18 15:43:29 2006
6 * Copyright 2006-2009 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version. A runtime exception applies to
14 * this software (see LICENSE.GPL_WRE file mentioned below for details).
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22 */
23
24#include <core/exceptions/software.h>
25#include <core/threading/mutex.h>
26#include <interface/message.h>
27#include <interface/message_queue.h>
28
29#include <cstddef>
30#include <cstdlib>
31
32namespace fawkes {
33
34/** @class MessageAlreadyQueuedException <interface/message_queue.h>
35 * Message already enqueued exception.
36 * This exception is thrown if you try to enqueue a message that has already
37 * been enqueued in another message queue. This is an illegal operation. If you
38 * need to enqueue a message multiple times use the copy constructor to do this.
39 */
40
41/** Constructor. */
43: Exception("Message already enqueued in another MessageQueue.")
44{
45}
46
47/** @class MessageQueue <interface/message_queue.h>
48 * Message queue used in interfaces.
49 * This message queue handles the basic messaging operations. The methods the
50 * Interface provides for handling message queues are forwarded to a
51 * MessageQueue instance.
52 * @see Interface
53 */
54
55/** Constructor. */
57{
58 list_ = NULL;
59 end_el_ = NULL;
60 mutex_ = new Mutex();
61}
62
63/** Destructor */
65{
66 flush();
67 delete mutex_;
68}
69
70/** Delete all messages from queue.
71 * This method deletes all messages from the queue.
72 */
73void
75{
76 mutex_->lock();
77 // free list elements
78 msg_list_t *l = list_;
79 msg_list_t *next;
80 while (l) {
81 next = l->next;
82 l->msg->unref();
83 free(l);
84 l = next;
85 }
86 list_ = NULL;
87 mutex_->unlock();
88}
89
90/** Append message to queue.
91 * @param msg Message to append
92 * @exception MessageAlreadyQueuedException thrown if the message has already been
93 * enqueued to an interface.
94 */
95void
97{
98 if (msg->enqueued() != 0) {
100 }
101 mutex_->lock();
102 msg->mark_enqueued();
103 if (list_ == NULL) {
104 list_ = (msg_list_t *)malloc(sizeof(msg_list_t));
105 list_->next = NULL;
106 list_->msg = msg;
107 list_->msg_id = msg->id();
108 end_el_ = list_;
109 } else {
110 msg_list_t *l = (msg_list_t *)malloc(sizeof(msg_list_t));
111 l->next = NULL;
112 l->msg = msg;
113 l->msg_id = msg->id();
114 end_el_->next = l;
115 end_el_ = l;
116 }
117
118 mutex_->unlock();
119}
120
121/** Enqueue message after given iterator.
122 * @param it Iterator
123 * @param msg Message to enqueue
124 * @exception NullPointerException thrown if iterator is end iterator.
125 * @exception NotLockedException thrown if message queue is not locked during this operation.
126 * @exception MessageAlreadyQueuedException thrown if the message has already been
127 * enqueued to an interface.
128 */
129void
131{
132 if (mutex_->try_lock()) {
133 mutex_->unlock();
134 throw NotLockedException("Message queue must be locked to insert messages after iterator.");
135 }
136 if (it.cur == NULL) {
137 throw NullPointerException("Cannot append message at end element.");
138 }
139 if (msg->enqueued() != 0) {
141 }
142 msg->mark_enqueued();
143 msg_list_t *l = (msg_list_t *)malloc(sizeof(msg_list_t));
144 l->next = it.cur->next;
145 l->msg = msg;
146 l->msg_id = msg->id();
147 it.cur->next = l;
148 if (l->next == NULL) {
149 end_el_ = l;
150 }
151}
152
153/** Remove message from queue.
154 * @param msg message to remove
155 */
156void
158{
159 mutex_->lock();
160 msg_list_t *l = list_;
161 msg_list_t *p = NULL;
162 while (l) {
163 if (l->msg == msg) {
164 remove(l, p);
165 break;
166 } else {
167 p = l;
168 l = l->next;
169 }
170 }
171 mutex_->unlock();
172}
173
174/** Remove message from queue by message id.
175 * @param msg_id id of message to remove
176 */
177void
178MessageQueue::remove(const unsigned int msg_id)
179{
180 mutex_->lock();
181 msg_list_t *l = list_;
182 msg_list_t *p = NULL;
183 while (l) {
184 if (l->msg_id == msg_id) {
185 remove(l, p);
186 break;
187 } else {
188 p = l;
189 l = l->next;
190 }
191 }
192 mutex_->unlock();
193}
194
195/** Remove message from list.
196 * @param l list item to remove
197 * @param p predecessor of element, may be NULL if there is none
198 */
199void
200MessageQueue::remove(msg_list_t *l, msg_list_t *p)
201{
202 if (mutex_->try_lock()) {
203 mutex_->unlock();
204 throw NotLockedException("Protected remove must be made safe by locking.");
205 }
206 if (p) {
207 p->next = l->next;
208 } else {
209 // was first element
210 list_ = l->next;
211 }
212 l->msg->unref();
213 free(l);
214}
215
216/** Get number of messages in queue.
217 * @return number of messages in queue.
218 */
219unsigned int
221{
222 mutex_->lock();
223 unsigned int rv = 0;
224 msg_list_t * l = list_;
225 while (l) {
226 ++rv;
227 l = l->next;
228 }
229
230 mutex_->unlock();
231 return rv;
232}
233
234/** Check if message queue is empty.
235 * @return true if message queue is empty, false otherwise
236 */
237bool
239{
240 mutex_->lock();
241 bool rv = (list_ == NULL);
242 mutex_->unlock();
243 return rv;
244}
245
246/** Lock message queue.
247 * No operations can be performed on the message queue after locking it.
248 * Note that you cannot call any method of the message queue as long as
249 * the queue is locked. Use lock() only to have a secure run-through with
250 * the MessageIterator.
251 */
252void
254{
255 mutex_->lock();
256}
257
258/** Try to lock message queue.
259 * No operations can be performed on the message queue after locking it.
260 * Note that you cannot call any method of the message queue as long as
261 * the queue is locked. Use try_lock() only to have a secure run-through with
262 * the MessageIterator.
263 * @return true, if the lock has been aquired, false otherwise.
264 */
265bool
267{
268 return mutex_->try_lock();
269}
270
271/** Unlock message queue.
272 */
273void
275{
276 mutex_->unlock();
277}
278
279/** Get first message from queue.
280 * @return first message from queue
281 */
282Message *
284{
285 if (list_) {
286 return list_->msg;
287 } else {
288 return NULL;
289 }
290}
291
292/** Erase first message from queue.
293 */
294void
296{
297 mutex_->lock();
298 if (list_) {
299 remove(list_, NULL);
300 }
301 mutex_->unlock();
302}
303
304/** Get iterator to first element in message queue.
305 * @return iterator to first element in message queue
306 * @exception NotLockedException thrown if message queue is not locked during this operation.
307 */
310{
311 if (mutex_->try_lock()) {
312 mutex_->unlock();
313 throw NotLockedException("Message queue must be locked to get begin iterator.");
314 }
315 return MessageIterator(list_);
316}
317
318/** Get iterator to element beyond end of message queue list.
319 * @return iterator to element beyond end of message queue list
320 * @exception NotLockedException thrown if message queue is not locked during this operation.
321 */
324{
325 if (mutex_->try_lock()) {
326 mutex_->unlock();
327 throw NotLockedException("Message queue must be locked to get end iterator.");
328 }
329 return MessageIterator();
330}
331
332/** @class MessageQueue::MessageIterator message_queue.h <interface/message_queue.h>
333 * Message iterator.
334 * Use this iterator to iterate over messages in a message queue.
335 * Use MessageQueue::begin() to get the iterator.
336 * @author Tim Niemueller
337 */
338
339/** Constructor
340 * @param cur Current element for message list
341 */
343{
344 this->cur = cur;
345}
346
347/** Constructor */
349{
350 cur = NULL;
351}
352
353/** Copy constructor.
354 * @param it Iterator to copy
355 */
357{
358 cur = it.cur;
359}
360
361/** Increment iterator.
362 * Advances to the next element. This is the infix-operator. It may be used
363 * like this:
364 * @code
365 * for (MessageIterator cit = msgq->begin(); cit != msgq->end(); ++cit) {
366 * // your code here
367 * }
368 * @endcode
369 * @return Reference to instance itself after advancing to the next element.
370 */
373{
374 if (cur != NULL)
375 cur = cur->next;
376
377 return *this;
378}
379
380/** Increment iterator.
381 * Advances to the next element in allocated chunk list. This is the postfix-operator.
382 * It may be used like this:
383 * @code
384 * for (MessageIterator cit = memmgr->begin(); cit != memmgr->end(); cit++) {
385 * // your code here
386 * }
387 * @endcode
388 * Note that since a copy of the original iterator has to be created an returned it
389 * the postfix operation takes both, more CPU time and more memory. If possible (especially
390 * if used in a for loop like the example) use the prefix operator!
391 * @see operator++()
392 * @param inc ignored
393 * @return copy of the current instance before advancing to the next element.
394 */
397{
398 MessageIterator rv(cur);
399 if (cur != NULL)
400 cur = cur->next;
401
402 return rv;
403}
404
405/** Advance by a certain amount.
406 * Can be used to add an integer to the iterator to advance many steps in one go.
407 * This operation takes linear time depending on i.
408 * @param i steps to advance in list. If i is bigger than the number of remaining
409 * elements in the list will stop beyond list.
410 * @return reference to current instance after advancing i steps or after reaching
411 * end of list.
412 */
415{
416 for (unsigned int j = 0; (cur != NULL) && (j < i); ++j) {
417 cur = cur->next;
418 }
419 return *this;
420}
421
422/** Advance by a certain amount.
423 * Works like operator+(unsigned int i), provided for convenience.
424 * @param i steps to advance in list
425 * @return reference to current instance after advancing i steps or after reaching
426 * end of list.
427 */
430{
431 for (unsigned int j = 0; (cur != NULL) && (j < i); ++j) {
432 cur = cur->next;
433 }
434 return *this;
435}
436
437/** Check equality of two iterators.
438 * Can be used to determine if two iterators point to the same chunk.
439 * @param c iterator to compare current instance to
440 * @return true, if iterators point to the same chunk, false otherwise
441 */
442bool
444{
445 return (cur == c.cur);
446}
447
448/** Check inequality of two iterators.
449 * Can be used to determine if two iterators point to different chunks.
450 * @param c iterator to compare current instance to
451 * @return true, if iterators point to different chunks of memory, false otherwise
452 */
453bool
455{
456 return (cur != c.cur);
457}
458
459/** Get memory pointer of chunk.
460 * Use this operator to get the pointer to the chunk of memory that this iterator
461 * points to.
462 * @return pointer to memory
463 */
464Message *
466{
467 return (cur != NULL) ? cur->msg : NULL;
468}
469
470/** Act on current message.
471 * Node that you have to make sure that this is not called on the end node!
472 * @return current message
473 */
474Message *
476{
477 return cur->msg;
478}
479
480/** Assign iterator.
481 * Makes the current instance to point to the same memory element as c.
482 * @param c assign value
483 * @return reference to current instance
484 */
487{
488 this->cur = c.cur;
489 return *this;
490}
491
492/** Get ID of current element or 0 if element is end.
493 * @return ID of current element or 0 if element is end.
494 */
495unsigned int
497{
498 if (cur == NULL)
499 return 0;
500 return cur->msg_id;
501}
502
503} // end namespace fawkes
Base class for exceptions in Fawkes.
Definition: exception.h:36
Message already enqueued exception.
Definition: message_queue.h:36
Message * operator->() const
Act on current message.
MessageIterator & operator+(unsigned int i)
Advance by a certain amount.
MessageIterator & operator++()
Increment iterator.
bool operator==(const MessageIterator &c) const
Check equality of two iterators.
bool operator!=(const MessageIterator &c) const
Check inequality of two iterators.
Message * operator*() const
Get memory pointer of chunk.
MessageIterator & operator+=(unsigned int i)
Advance by a certain amount.
MessageIterator & operator=(const MessageIterator &c)
Assign iterator.
unsigned int id() const
Get ID of current element or 0 if element is end.
MessageIterator end()
Get iterator to element beyond end of message queue list.
void append(Message *msg)
Append message to queue.
MessageQueue()
Constructor.
void unlock()
Unlock message queue.
void pop()
Erase first message from queue.
void flush()
Delete all messages from queue.
void lock()
Lock message queue.
void remove(const Message *msg)
Remove message from queue.
bool empty() const
Check if message queue is empty.
MessageIterator begin()
Get iterator to first element in message queue.
virtual ~MessageQueue()
Destructor.
bool try_lock()
Try to lock message queue.
void insert_after(const MessageIterator &it, Message *msg)
Enqueue message after given iterator.
unsigned int size() const
Get number of messages in queue.
Message * first()
Get first message from queue.
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:44
void mark_enqueued()
Mark message as being enqueued.
Definition: message.cpp:234
bool enqueued() const
Check is message has been enqueued.
Definition: message.cpp:249
unsigned int id() const
Get message ID.
Definition: message.cpp:181
Mutex mutual exclusion lock.
Definition: mutex.h:33
bool try_lock()
Tries to lock the mutex.
Definition: mutex.cpp:117
void lock()
Lock this mutex.
Definition: mutex.cpp:87
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
Operation on unlocked object.
Definition: software.h:62
A NULL pointer was supplied where not allowed.
Definition: software.h:32
Fawkes library namespace.