1 // BlockingQueue.h 2 // 3 // Copyright (c) 2004, Ingo Weinhold (bonefish@cs.tu-berlin.de) 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a 6 // copy of this software and associated documentation files (the "Software"), 7 // to deal in the Software without restriction, including without limitation 8 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 // and/or sell copies of the Software, and to permit persons to whom the 10 // Software is furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 // DEALINGS IN THE SOFTWARE. 22 // 23 // Except as contained in this notice, the name of a copyright holder shall 24 // not be used in advertising or otherwise to promote the sale, use or other 25 // dealings in this Software without prior written authorization of the 26 // copyright holder. 27 28 #ifndef BLOCKING_QUEUE_H 29 #define BLOCKING_QUEUE_H 30 31 #include <AutoLocker.h> 32 #include <OS.h> 33 34 #include "DebugSupport.h" 35 #include "Locker.h" 36 #include "Vector.h" 37 38 template<typename Element> 39 class BlockingQueue : public Locker { 40 public: 41 BlockingQueue(const char* name = NULL); 42 ~BlockingQueue(); 43 44 status_t InitCheck() const; 45 46 status_t Close(bool deleteElements, 47 const Vector<Element*>** elements = NULL); 48 49 status_t Push(Element* element); 50 status_t Pop(Element** element, 51 bigtime_t timeout = B_INFINITE_TIMEOUT); 52 status_t Peek(Element** element); 53 status_t Remove(Element* element); 54 55 int32 Size() const; 56 57 private: 58 Vector<Element*> fElements; 59 sem_id fElementSemaphore; 60 }; 61 62 // constructor 63 template<typename Element> 64 BlockingQueue<Element>::BlockingQueue(const char* name) 65 : fElements(), 66 fElementSemaphore(-1) 67 { 68 fElementSemaphore = create_sem(0, (name ? name : "blocking queue")); 69 } 70 71 // destructor 72 template<typename Element> 73 BlockingQueue<Element>::~BlockingQueue() 74 { 75 if (fElementSemaphore >= 0) 76 delete_sem(fElementSemaphore); 77 } 78 79 // InitCheck 80 template<typename Element> 81 status_t 82 BlockingQueue<Element>::InitCheck() const 83 { 84 return (fElementSemaphore < 0 ? fElementSemaphore : B_OK); 85 } 86 87 // Close 88 template<typename Element> 89 status_t 90 BlockingQueue<Element>::Close(bool deleteElements, 91 const Vector<Element*>** elements) 92 { 93 AutoLocker<Locker> _(this); 94 status_t error = delete_sem(fElementSemaphore); 95 if (error != B_OK) 96 return error; 97 fElementSemaphore = -1; 98 if (elements) 99 *elements = &fElements; 100 if (deleteElements) { 101 int32 count = fElements.Count(); 102 for (int32 i = 0; i < count; i++) 103 delete fElements.ElementAt(i); 104 } 105 return error; 106 } 107 108 // Push 109 template<typename Element> 110 status_t 111 BlockingQueue<Element>::Push(Element* element) 112 { 113 AutoLocker<Locker> _(this); 114 if (fElementSemaphore < 0) 115 return B_NO_INIT; 116 status_t error = fElements.PushBack(element); 117 if (error != B_OK) 118 return error; 119 error = release_sem(fElementSemaphore); 120 if (error != B_OK) 121 fElements.Erase(fElements.Count() - 1); 122 return error; 123 } 124 125 // Pop 126 template<typename Element> 127 status_t 128 BlockingQueue<Element>::Pop(Element** element, bigtime_t timeout) 129 { 130 status_t error = acquire_sem_etc(fElementSemaphore, 1, B_RELATIVE_TIMEOUT, 131 timeout); 132 if (error != B_OK) 133 return error; 134 AutoLocker<Locker> _(this); 135 if (fElementSemaphore < 0) 136 return B_NO_INIT; 137 int32 count = fElements.Count(); 138 if (count == 0) 139 return B_ERROR; 140 *element = fElements.ElementAt(0); 141 fElements.Erase(0); 142 return B_OK; 143 } 144 145 // Peek 146 template<typename Element> 147 status_t 148 BlockingQueue<Element>::Peek(Element** element) 149 { 150 AutoLocker<Locker> _(this); 151 if (fElementSemaphore < 0) 152 return B_NO_INIT; 153 int32 count = fElements.Count(); 154 if (count == 0) 155 return B_ENTRY_NOT_FOUND; 156 *element = fElements.ElementAt(0); 157 return B_OK; 158 } 159 160 // Remove 161 template<typename Element> 162 status_t 163 BlockingQueue<Element>::Remove(Element* element) 164 { 165 status_t error = acquire_sem_etc(fElementSemaphore, 1, 166 B_RELATIVE_TIMEOUT, 0); 167 if (error != B_OK) 168 return error; 169 AutoLocker<Locker> _(this); 170 if (fElementSemaphore < 0) 171 return B_NO_INIT; 172 int32 count = fElements.Remove(element); 173 if (count == 0) { 174 release_sem(fElementSemaphore); 175 return B_ENTRY_NOT_FOUND; 176 } 177 if (count > 1) { 178 ERROR("ERROR: BlockingQueue::Remove(): Removed %ld elements!\n", 179 count); 180 } 181 return error; 182 } 183 184 // Size 185 template<typename Element> 186 int32 187 BlockingQueue<Element>::Size() const 188 { 189 AutoLocker<Locker> _(this); 190 return (fElements.Count()); 191 } 192 193 #endif // BLOCKING_QUEUE_H 194