xref: /haiku/src/kits/app/MessageQueue.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 /*
2  * Copyright 2001-2005, 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 			if (entry == fTail)
112 				fTail = last;
113 
114 			fMessageCount--;
115 			return;
116 		}
117 		last = entry;
118 	}
119 }
120 
121 
122 /*!
123 	\brief This method just returns the number of BMessages on the queue.
124 */
125 int32
126 BMessageQueue::CountMessages() const
127 {
128     return fMessageCount;
129 }
130 
131 
132 /*!
133 	\brief This method just returns true if there are no BMessages on the queue.
134 */
135 bool
136 BMessageQueue::IsEmpty() const
137 {
138     return fMessageCount == 0;
139 }
140 
141 
142 /*!
143 	\brief This method searches the queue for the index'th BMessage.
144 
145 	The first BMessage is at index 0, the second at index 1 etc.
146 	The BMessage is returned if it is found.  If no BMessage exists at that
147 	index (ie the queue is not that long or the index is invalid) NULL is
148 	returned.
149 */
150 BMessage *
151 BMessageQueue::FindMessage(int32 index) const
152 {
153 	BAutolock _(fLock);
154 	if (!IsLocked())
155 		return NULL;
156 
157 	if (index < 0 || index >= fMessageCount)
158 		return NULL;
159 
160 	for (BMessage* message = fHead; message != NULL; message = message->fQueueLink) {
161 		// If the index reaches zero, then we have found a match.
162 		if (index == 0)
163 			return message;
164 
165 		index--;
166 	}
167 
168     return NULL;
169 }
170 
171 
172 /*!
173 	\brief Searches the queue for the index'th BMessage that has a
174 		particular what code.
175 */
176 BMessage *
177 BMessageQueue::FindMessage(uint32 what, int32 index) const
178 {
179 	BAutolock _(fLock);
180 	if (!IsLocked())
181 		return NULL;
182 
183 	if (index < 0 || index >= fMessageCount)
184 		return NULL;
185 
186 	for (BMessage* message = fHead; message != NULL; message = message->fQueueLink) {
187 		if (message->what == what) {
188 			// If the index reaches zero, then we have found a match.
189 			if (index == 0)
190 				return message;
191 
192 			index--;
193 		}
194 	}
195 
196     return NULL;
197 }
198 
199 
200 /*!
201 	\brief Locks the BMessageQueue so no other thread can change
202 		or search the queue.
203 */
204 bool
205 BMessageQueue::Lock()
206 {
207     return fLock.Lock();
208 }
209 
210 
211 /*!
212 	\brief Releases the lock which was acquired by Lock().
213 */
214 void
215 BMessageQueue::Unlock()
216 {
217 	fLock.Unlock();
218 }
219 
220 
221 /*!
222 	\brief Returns whether or not the queue is locked
223 */
224 bool
225 BMessageQueue::IsLocked() const
226 {
227 	return fLock.IsLocked();
228 }
229 
230 
231 /*!
232 	\brief Removes the first BMessage on the queue and returns
233 		it to the caller.  If the queue is empty, NULL is returned.
234 */
235 BMessage *
236 BMessageQueue::NextMessage()
237 {
238 	BAutolock _(fLock);
239 	if (!IsLocked())
240 		return NULL;
241 
242 	// remove the head of the queue, if any, and return it
243 
244 	BMessage* head = fHead;
245 	if (head == NULL)
246 		return NULL;
247 
248 	fMessageCount--;
249 	fHead = head->fQueueLink;
250 
251 	if (fHead == NULL) {
252 		// If the queue is empty after removing the front element,
253 		// we need to set the tail of the queue to NULL since the queue
254 		// is now empty.
255 		fTail = NULL;
256 	}
257 
258     return head;
259 }
260 
261 
262 /*!
263 	\brief This method is only here for R5 binary compatibility!
264 		It should be dropped as soon as possible (it misses the const qualifier).
265 */
266 bool
267 BMessageQueue::IsLocked()
268 {
269 	return fLock.IsLocked();
270 }
271 
272 
273 void BMessageQueue::_ReservedMessageQueue1() {}
274 void BMessageQueue::_ReservedMessageQueue2() {}
275 void BMessageQueue::_ReservedMessageQueue3() {}
276 
277