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