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 14using std::vector; 15 16typedef BLocker Locker; 17 18template<typename Element> 19class BlockingQueue : public Locker { 20public: 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 37private: 38 vector<Element*> fElements; 39 sem_id fElementSemaphore; 40}; 41 42// constructor 43template<typename Element> 44BlockingQueue<Element>::BlockingQueue(const char* name) 45 : fElements(), 46 fElementSemaphore(-1) 47{ 48 fElementSemaphore = create_sem(0, (name ? name : "blocking queue")); 49} 50 51// destructor 52template<typename Element> 53BlockingQueue<Element>::~BlockingQueue() 54{ 55 if (fElementSemaphore >= 0) 56 delete_sem(fElementSemaphore); 57} 58 59// InitCheck 60template<typename Element> 61status_t 62BlockingQueue<Element>::InitCheck() const 63{ 64 return (fElementSemaphore < 0 ? fElementSemaphore : B_OK); 65} 66 67// Close 68template<typename Element> 69status_t 70BlockingQueue<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 89template<typename Element> 90status_t 91BlockingQueue<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 108template<typename Element> 109status_t 110BlockingQueue<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 128template<typename Element> 129status_t 130BlockingQueue<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 143template<typename Element> 144status_t 145BlockingQueue<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 176template<typename Element> 177int32 178BlockingQueue<Element>::Size() 179{ 180 AutoLocker<Locker> _(this); 181 return (fElements.size()); 182} 183 184#endif // BLOCKING_QUEUE_H 185