Files
haiku-beta6/src/kits/app/MessageQueue.cpp
T
Axel Dörfler 6338e9da5d Fixed RemoveMessage() I broke before.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15085 a95241bf-73f2-0310-859d-f6bbb57e9c96
2005-11-23 14:42:33 +00:00

280 lines
5.4 KiB
C++

/*
* Copyright 2001-2005, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Unknown? Eric?
* Axel Dörfler, [email protected]
*/
/** Queue for holding BMessages */
#include <MessageQueue.h>
#include <Autolock.h>
#include <Message.h>
BMessageQueue::BMessageQueue()
:
fHead(NULL),
fTail(NULL),
fMessageCount(0),
fLock("BMessageQueue Lock")
{
}
/*!
\brief This is the desctructor for the BMessageQueue. It iterates over
any messages left on the queue and deletes them.
The implementation is careful not to release the lock when the
BMessageQueue is deconstructed. If the lock is released, it is
possible another thread will start an AddMessage() operation before
the BLocker is deleted. The safe thing to do is not to unlock the
BLocker from the destructor once it is acquired. That way, any thread
waiting to do a AddMessage() will fail to acquire the lock since the
BLocker will be deleted before they can acquire it.
*/
BMessageQueue::~BMessageQueue()
{
if (!Lock())
return;
BMessage* message = fHead;
while (message != NULL) {
BMessage *next = message->fQueueLink;
delete message;
message = next;
}
}
/*!
\brief This method adds a BMessage to the queue.
It makes a couple of assumptions:
- The BMessage was allocated on the heap with new, since the
destructor delete's BMessages left on the queue.
- The BMessage is not already on this or any other BMessageQueue.
If it is, the queue it is already on will be corrupted.
*/
void
BMessageQueue::AddMessage(BMessage* message)
{
if (message == NULL)
return;
BAutolock _(fLock);
if (!IsLocked())
return;
// The message passed in will be the last message on the queue so its
// link member should be set to null.
message->fQueueLink = NULL;
fMessageCount++;
if (fTail == NULL) {
// there are no messages in the queue yet
fHead = fTail = message;
} else {
// just add it after the tail
fTail->fQueueLink = message;
fTail = message;
}
}
/*!
\brief This method searches the queue for a particular BMessage.
If it is found, it is removed from the queue.
*/
void
BMessageQueue::RemoveMessage(BMessage* message)
{
if (message == NULL)
return;
BAutolock _(fLock);
if (!IsLocked())
return;
BMessage* last = NULL;
for (BMessage* entry = fHead; entry != NULL; entry = entry->fQueueLink) {
if (entry == message) {
// remove this one
if (entry == fHead)
fHead = entry->fQueueLink;
else
last->fQueueLink = entry->fQueueLink;
if (entry == fTail)
fTail = last;
fMessageCount--;
return;
}
last = entry;
}
}
/*!
\brief This method just returns the number of BMessages on the queue.
*/
int32
BMessageQueue::CountMessages() const
{
return fMessageCount;
}
/*!
\brief This method just returns true if there are no BMessages on the queue.
*/
bool
BMessageQueue::IsEmpty() const
{
return fMessageCount == 0;
}
/*!
\brief This method searches the queue for the index'th BMessage.
The first BMessage is at index 0, the second at index 1 etc.
The BMessage is returned if it is found. If no BMessage exists at that
index (ie the queue is not that long or the index is invalid) NULL is
returned.
*/
BMessage *
BMessageQueue::FindMessage(int32 index) const
{
BAutolock _(fLock);
if (!IsLocked())
return NULL;
if (index < 0 || index >= fMessageCount)
return NULL;
for (BMessage* message = fHead; message != NULL; message = message->fQueueLink) {
// If the index reaches zero, then we have found a match.
if (index == 0)
return message;
index--;
}
return NULL;
}
/*!
\brief Searches the queue for the index'th BMessage that has a
particular what code.
*/
BMessage *
BMessageQueue::FindMessage(uint32 what, int32 index) const
{
BAutolock _(fLock);
if (!IsLocked())
return NULL;
if (index < 0 || index >= fMessageCount)
return NULL;
for (BMessage* message = fHead; message != NULL; message = message->fQueueLink) {
if (message->what == what) {
// If the index reaches zero, then we have found a match.
if (index == 0)
return message;
index--;
}
}
return NULL;
}
/*!
\brief Locks the BMessageQueue so no other thread can change
or search the queue.
*/
bool
BMessageQueue::Lock()
{
return fLock.Lock();
}
/*!
\brief Releases the lock which was acquired by Lock().
*/
void
BMessageQueue::Unlock()
{
fLock.Unlock();
}
/*!
\brief Returns whether or not the queue is locked
*/
bool
BMessageQueue::IsLocked() const
{
return fLock.IsLocked();
}
/*!
\brief Removes the first BMessage on the queue and returns
it to the caller. If the queue is empty, NULL is returned.
*/
BMessage *
BMessageQueue::NextMessage()
{
BAutolock _(fLock);
if (!IsLocked())
return NULL;
// remove the head of the queue, if any, and return it
BMessage* head = fHead;
if (head == NULL)
return NULL;
fMessageCount--;
fHead = head->fQueueLink;
if (fHead == NULL) {
// If the queue is empty after removing the front element,
// we need to set the tail of the queue to NULL since the queue
// is now empty.
fTail = NULL;
}
return head;
}
/*!
\brief This method is only here for R5 binary compatibility!
It should be dropped as soon as possible (it misses the const qualifier).
*/
bool
BMessageQueue::IsLocked()
{
return fLock.IsLocked();
}
void BMessageQueue::_ReservedMessageQueue1() {}
void BMessageQueue::_ReservedMessageQueue2() {}
void BMessageQueue::_ReservedMessageQueue3() {}