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