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 
32 namespace 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  */
73 void
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  */
95 void
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  */
129 void
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  */
156 void
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  */
177 void
178 MessageQueue::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  */
199 void
200 MessageQueue::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  */
219 unsigned 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  */
237 bool
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  */
252 void
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  */
265 bool
267 {
268  return mutex_->try_lock();
269 }
270 
271 /** Unlock message queue.
272  */
273 void
275 {
276  mutex_->unlock();
277 }
278 
279 /** Get first message from queue.
280  * @return first message from queue
281  */
282 Message *
284 {
285  if (list_) {
286  return list_->msg;
287  } else {
288  return NULL;
289  }
290 }
291 
292 /** Erase first message from queue.
293  */
294 void
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  */
442 bool
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  */
453 bool
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  */
464 Message *
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  */
474 Message *
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  */
495 unsigned int
497 {
498  if (cur == NULL)
499  return 0;
500  return cur->msg_id;
501 }
502 
503 } // end namespace fawkes
fawkes::Mutex::lock
void lock()
Lock this mutex.
Definition: mutex.cpp:87
fawkes::MessageQueue::empty
bool empty() const
Check if message queue is empty.
Definition: message_queue.cpp:238
fawkes::MessageQueue::MessageIterator::operator+=
MessageIterator & operator+=(unsigned int i)
Advance by a certain amount.
Definition: message_queue.cpp:429
fawkes::MessageQueue::MessageIterator::MessageIterator
MessageIterator()
Constructor.
Definition: message_queue.cpp:348
fawkes::Message::enqueued
bool enqueued() const
Check is message has been enqueued.
Definition: message.cpp:229
fawkes::MessageQueue::try_lock
bool try_lock()
Try to lock message queue.
Definition: message_queue.cpp:266
fawkes::MessageQueue::flush
void flush()
Delete all messages from queue.
Definition: message_queue.cpp:74
fawkes::Mutex
Mutex mutual exclusion lock.
Definition: mutex.h:33
fawkes::Message
Base class for all messages passed through interfaces in Fawkes BlackBoard.
Definition: message.h:45
fawkes::MessageAlreadyQueuedException::MessageAlreadyQueuedException
MessageAlreadyQueuedException()
Constructor.
Definition: message_queue.cpp:42
fawkes::Message::mark_enqueued
void mark_enqueued()
Mark message as being enqueued.
Definition: message.cpp:214
fawkes::MessageQueue::lock
void lock()
Lock message queue.
Definition: message_queue.cpp:253
fawkes::MessageQueue::pop
void pop()
Erase first message from queue.
Definition: message_queue.cpp:295
fawkes::MessageQueue::unlock
void unlock()
Unlock message queue.
Definition: message_queue.cpp:274
fawkes::NotLockedException
Operation on unlocked object.
Definition: software.h:62
fawkes::Mutex::unlock
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
fawkes::MessageQueue::MessageIterator::id
unsigned int id() const
Get ID of current element or 0 if element is end.
Definition: message_queue.cpp:496
fawkes::MessageQueue::size
unsigned int size() const
Get number of messages in queue.
Definition: message_queue.cpp:220
fawkes::MessageQueue::MessageIterator::operator->
Message * operator->() const
Act on current message.
Definition: message_queue.cpp:475
fawkes::MessageQueue::end
MessageIterator end()
Get iterator to element beyond end of message queue list.
Definition: message_queue.cpp:323
fawkes
Fawkes library namespace.
fawkes::MessageQueue::append
void append(Message *msg)
Append message to queue.
Definition: message_queue.cpp:96
fawkes::MessageQueue::MessageIterator
Message iterator.
Definition: message_queue.h:59
fawkes::MessageQueue::MessageIterator::operator++
MessageIterator & operator++()
Increment iterator.
Definition: message_queue.cpp:372
fawkes::MessageQueue::remove
void remove(const Message *msg)
Remove message from queue.
Definition: message_queue.cpp:157
fawkes::MessageQueue::first
Message * first()
Get first message from queue.
Definition: message_queue.cpp:283
fawkes::MessageQueue::insert_after
void insert_after(const MessageIterator &it, Message *msg)
Enqueue message after given iterator.
Definition: message_queue.cpp:130
fawkes::MessageQueue::MessageIterator::operator+
MessageIterator & operator+(unsigned int i)
Advance by a certain amount.
Definition: message_queue.cpp:414
fawkes::MessageQueue::~MessageQueue
virtual ~MessageQueue()
Destructor.
Definition: message_queue.cpp:64
fawkes::MessageQueue::MessageIterator::operator!=
bool operator!=(const MessageIterator &c) const
Check inequality of two iterators.
Definition: message_queue.cpp:454
fawkes::Mutex::try_lock
bool try_lock()
Tries to lock the mutex.
Definition: mutex.cpp:117
fawkes::MessageQueue::MessageQueue
MessageQueue()
Constructor.
Definition: message_queue.cpp:56
fawkes::MessageQueue::MessageIterator::operator=
MessageIterator & operator=(const MessageIterator &c)
Assign iterator.
Definition: message_queue.cpp:486
fawkes::Message::id
unsigned int id() const
Get message ID.
Definition: message.cpp:180
fawkes::NullPointerException
A NULL pointer was supplied where not allowed.
Definition: software.h:32
fawkes::MessageAlreadyQueuedException
Message already enqueued exception.
Definition: message_queue.h:36
fawkes::MessageQueue::begin
MessageIterator begin()
Get iterator to first element in message queue.
Definition: message_queue.cpp:309
fawkes::MessageQueue::MessageIterator::operator==
bool operator==(const MessageIterator &c) const
Check equality of two iterators.
Definition: message_queue.cpp:443
fawkes::MessageQueue::MessageIterator::operator*
Message * operator*() const
Get memory pointer of chunk.
Definition: message_queue.cpp:465
fawkes::Exception
Base class for exceptions in Fawkes.
Definition: exception.h:36