1 /* 2 * Copyright 2004, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * All rights reserved. Distributed under the terms of the MIT license. 4 */ 5 #ifndef BLOCKING_QUEUE_H 6 #define BLOCKING_QUEUE_H 7 8 #include <vector> 9 10 #include <Locker.h> 11 12 #include "AutoLocker.h" 13 14 using std::vector; 15 16 typedef BLocker Locker; 17 18 template<typename Element> 19 class BlockingQueue : public Locker { 20 public: 21 BlockingQueue(const char* name = NULL); 22 ~BlockingQueue(); 23 24 status_t InitCheck() const; 25 26 status_t Close(bool deleteElements, 27 const vector<Element*>** elements = NULL); 28 29 status_t Push(Element* element); 30 status_t Pop(Element** element, 31 bigtime_t timeout = B_INFINITE_TIMEOUT); 32 status_t Peek(Element** element); 33 status_t Remove(Element* element); 34 35 int32 Size(); 36 37 private: 38 vector<Element*> fElements; 39 sem_id fElementSemaphore; 40 }; 41 42 // constructor 43 template<typename Element> 44 BlockingQueue<Element>::BlockingQueue(const char* name) 45 : fElements(), 46 fElementSemaphore(-1) 47 { 48 fElementSemaphore = create_sem(0, (name ? name : "blocking queue")); 49 } 50 51 // destructor 52 template<typename Element> 53 BlockingQueue<Element>::~BlockingQueue() 54 { 55 if (fElementSemaphore >= 0) 56 delete_sem(fElementSemaphore); 57 } 58 59 // InitCheck 60 template<typename Element> 61 status_t 62 BlockingQueue<Element>::InitCheck() const 63 { 64 return (fElementSemaphore < 0 ? fElementSemaphore : B_OK); 65 } 66 67 // Close 68 template<typename Element> 69 status_t 70 BlockingQueue<Element>::Close(bool deleteElements, 71 const vector<Element*>** elements) 72 { 73 AutoLocker<Locker> _(this); 74 status_t error = delete_sem(fElementSemaphore); 75 if (error != B_OK) 76 return error; 77 fElementSemaphore = -1; 78 if (elements) 79 *elements = &fElements; 80 if (deleteElements) { 81 int32 count = fElements.size(); 82 for (int32 i = 0; i < count; i++) 83 delete fElements[i]; 84 } 85 return error; 86 } 87 88 // Push 89 template<typename Element> 90 status_t 91 BlockingQueue<Element>::Push(Element* element) 92 { 93 AutoLocker<Locker> _(this); 94 if (fElementSemaphore < 0) 95 return B_NO_INIT; 96 try { 97 fElements.push_back(element); 98 } catch (std::bad_alloc&) { 99 return B_NO_MEMORY; 100 } 101 status_t error = release_sem(fElementSemaphore); 102 if (error != B_OK) 103 fElements.erase(fElements.begin() + fElements.size() - 1); 104 return error; 105 } 106 107 // Pop 108 template<typename Element> 109 status_t 110 BlockingQueue<Element>::Pop(Element** element, bigtime_t timeout) 111 { 112 status_t error = acquire_sem_etc(fElementSemaphore, 1, B_RELATIVE_TIMEOUT, 113 timeout); 114 if (error != B_OK) 115 return error; 116 AutoLocker<Locker> _(this); 117 if (fElementSemaphore < 0) 118 return B_NO_INIT; 119 int32 count = fElements.size(); 120 if (count == 0) 121 return B_ERROR; 122 *element = fElements[0]; 123 fElements.erase(fElements.begin()); 124 return B_OK; 125 } 126 127 // Peek 128 template<typename Element> 129 status_t 130 BlockingQueue<Element>::Peek(Element** element) 131 { 132 AutoLocker<Locker> _(this); 133 if (fElementSemaphore < 0) 134 return B_NO_INIT; 135 int32 count = fElements.size(); 136 if (count == 0) 137 return B_ENTRY_NOT_FOUND; 138 *element = fElements[0]; 139 return B_OK; 140 } 141 142 // Remove 143 template<typename Element> 144 status_t 145 BlockingQueue<Element>::Remove(Element* element) 146 { 147 status_t error = acquire_sem_etc(fElementSemaphore, 1, 148 B_RELATIVE_TIMEOUT, 0); 149 if (error != B_OK) 150 return error; 151 AutoLocker<Locker> _(this); 152 if (fElementSemaphore < 0) 153 return B_NO_INIT; 154 155 int32 count = 0; 156 for (int32 i = fElements.size() - 1; i >= 0; i--) { 157 if (fElements[i] == element) { 158 fElements.erase(fElements.begin() + i); 159 count++; 160 } 161 } 162 if (count == 0) { 163 release_sem(fElementSemaphore); 164 return B_ENTRY_NOT_FOUND; 165 } 166 #if 0 167 if (count > 1) { 168 ERROR(("ERROR: BlockingQueue::Remove(): Removed %ld elements!\n", 169 count)); 170 } 171 #endif 172 return error; 173 } 174 175 // Size 176 template<typename Element> 177 int32 178 BlockingQueue<Element>::Size() 179 { 180 AutoLocker<Locker> _(this); 181 return (fElements.size()); 182 } 183 184 #endif // BLOCKING_QUEUE_H 185