xref: /haiku/src/kits/app/MessageQueue.cpp (revision be3db2942c0e8dda63cdd226ec3c99309d3eab0c)
1 /*
2  * Copyright 2001-2007, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Unknown? Eric?
7  *		Axel Dörfler, axeld@pinc-software.de
8  */
9 
10 /**	Queue for holding BMessages */
11 
12 
13 #include <MessageQueue.h>
14 #include <Autolock.h>
15 #include <Message.h>
16 
17 
18 BMessageQueue::BMessageQueue()
19 	:
20 	fHead(NULL),
21  	fTail(NULL),
22  	fMessageCount(0),
23  	fLock("BMessageQueue Lock")
24 {
25 }
26 
27 
28 /*!
29 	\brief This is the desctructor for the BMessageQueue.  It iterates over
30 		any messages left on the queue and deletes them.
31 
32 	The implementation is careful not to release the lock when the
33 	BMessageQueue is deconstructed.  If the lock is released, it is
34 	possible another thread will start an AddMessage() operation before
35 	the BLocker is deleted.  The safe thing to do is not to unlock the
36 	BLocker from the destructor once it is acquired. That way, any thread
37 	waiting to do a AddMessage() will fail to acquire the lock since the
38 	BLocker will be deleted before they can acquire it.
39 */
40 BMessageQueue::~BMessageQueue()
41 {
42 	if (!Lock())
43 		return;
44 
45 	BMessage* message = fHead;
46 	while (message != NULL) {
47 		BMessage *next = message->fQueueLink;
48 
49 		delete message;
50 		message = next;
51 	}
52 }
53 
54 
55 /*!
56 	\brief This method adds a BMessage to the queue.
57 
58 	It makes a couple of assumptions:
59 		- The BMessage was allocated on the heap with new, since the
60 		  destructor delete's BMessages left on the queue.
61 		- The BMessage is not already on this or any other BMessageQueue.
62 		  If it is, the queue it is already on will be corrupted.
63 */
64 void
65 BMessageQueue::AddMessage(BMessage* message)
66 {
67 	if (message == NULL)
68 		return;
69 
70 	BAutolock _(fLock);
71 	if (!IsLocked())
72 		return;
73 
74 	// The message passed in will be the last message on the queue so its
75 	// link member should be set to null.
76 	message->fQueueLink = NULL;
77 
78 	fMessageCount++;
79 
80 	if (fTail == NULL) {
81 		// there are no messages in the queue yet
82 		fHead = fTail = message;
83 	} else {
84 		// just add it after the tail
85 		fTail->fQueueLink = message;
86 		fTail = message;
87 	}
88 }
89 
90 
91 /*!
92 	\brief This method searches the queue for a particular BMessage.
93  		If it is found, it is removed from the queue.
94 */
95 void
96 BMessageQueue::RemoveMessage(BMessage* message)
97 {
98 	if (message == NULL)
99 		return;
100 
101 	BAutolock _(fLock);
102 	if (!IsLocked())
103 		return;
104 
105 	BMessage* last = NULL;
106 	for (BMessage* entry = fHead; entry != NULL; entry = entry->fQueueLink) {
107 		if (entry == message) {
108 			// remove this one
109 			if (entry == fHead)
110 				fHead = entry->fQueueLink;
111 			else
112 				last->fQueueLink = entry->fQueueLink;
113 
114 			if (entry == fTail)
115 				fTail = last;
116 
117 			fMessageCount--;
118 			return;
119 		}
120 		last = entry;
121 	}
122 }
123 
124 
125 /*!
126 	\brief This method just returns the number of BMessages on the queue.
127 */
128 int32
129 BMessageQueue::CountMessages() const
130 {
131     return fMessageCount;
132 }
133 
134 
135 /*!
136 	\brief This method just returns true if there are no BMessages on the queue.
137 */
138 bool
139 BMessageQueue::IsEmpty() const
140 {
141     return fMessageCount == 0;
142 }
143 
144 
145 /*!
146 	\brief This method searches the queue for the index'th BMessage.
147 
148 	The first BMessage is at index 0, the second at index 1 etc.
149 	The BMessage is returned if it is found.  If no BMessage exists at that
150 	index (ie the queue is not that long or the index is invalid) NULL is
151 	returned.
152 */
153 BMessage *
154 BMessageQueue::FindMessage(int32 index) const
155 {
156 	BAutolock _(fLock);
157 	if (!IsLocked())
158 		return NULL;
159 
160 	if (index < 0 || index >= fMessageCount)
161 		return NULL;
162 
163 	for (BMessage* message = fHead; message != NULL; message = message->fQueueLink) {
164 		// If the index reaches zero, then we have found a match.
165 		if (index == 0)
166 			return message;
167 
168 		index--;
169 	}
170 
171     return NULL;
172 }
173 
174 
175 /*!
176 	\brief Searches the queue for the index'th BMessage that has a
177 		particular what code.
178 */
179 BMessage *
180 BMessageQueue::FindMessage(uint32 what, int32 index) const
181 {
182 	BAutolock _(fLock);
183 	if (!IsLocked())
184 		return NULL;
185 
186 	if (index < 0 || index >= fMessageCount)
187 		return NULL;
188 
189 	for (BMessage* message = fHead; message != NULL; message = message->fQueueLink) {
190 		if (message->what == what) {
191 			// If the index reaches zero, then we have found a match.
192 			if (index == 0)
193 				return message;
194 
195 			index--;
196 		}
197 	}
198 
199     return NULL;
200 }
201 
202 
203 /*!
204 	\brief Locks the BMessageQueue so no other thread can change
205 		or search the queue.
206 */
207 bool
208 BMessageQueue::Lock()
209 {
210     return fLock.Lock();
211 }
212 
213 
214 /*!
215 	\brief Releases the lock which was acquired by Lock().
216 */
217 void
218 BMessageQueue::Unlock()
219 {
220 	fLock.Unlock();
221 }
222 
223 
224 /*!
225 	\brief Returns whether or not the queue is locked
226 */
227 bool
228 BMessageQueue::IsLocked() const
229 {
230 	return fLock.IsLocked();
231 }
232 
233 
234 /*!
235 	\brief Removes the first BMessage on the queue and returns
236 		it to the caller.  If the queue is empty, NULL is returned.
237 */
238 BMessage *
239 BMessageQueue::NextMessage()
240 {
241 	BAutolock _(fLock);
242 	if (!IsLocked())
243 		return NULL;
244 
245 	// remove the head of the queue, if any, and return it
246 
247 	BMessage* head = fHead;
248 	if (head == NULL)
249 		return NULL;
250 
251 	fMessageCount--;
252 	fHead = head->fQueueLink;
253 
254 	if (fHead == NULL) {
255 		// If the queue is empty after removing the front element,
256 		// we need to set the tail of the queue to NULL since the queue
257 		// is now empty.
258 		fTail = NULL;
259 	}
260 
261     return head;
262 }
263 
264 
265 /*!
266 	\brief Checks wether or not the specified \a message is the message
267 		you would get when calling NextMessage().
268 */
269 bool
270 BMessageQueue::IsNextMessage(const BMessage* message) const
271 {
272 	BAutolock _(fLock);
273 	return fHead == message;
274 }
275 
276 
277 /*!
278 	\brief This method is only here for R5 binary compatibility!
279 		It should be dropped as soon as possible (it misses the const qualifier).
280 */
281 bool
282 BMessageQueue::IsLocked()
283 {
284 	return fLock.IsLocked();
285 }
286 
287 
288 void BMessageQueue::_ReservedMessageQueue1() {}
289 void BMessageQueue::_ReservedMessageQueue2() {}
290 void BMessageQueue::_ReservedMessageQueue3() {}
291 
292