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 <AutoLocker.h> 9 #include <OS.h> 10 11 #include "DebugSupport.h" 12 #include "Locker.h" 13 #include "Vector.h" 14 15 template<typename Element> 16 class BlockingQueue : public Locker { 17 public: 18 BlockingQueue(const char* name = NULL); 19 ~BlockingQueue(); 20 21 status_t InitCheck() const; 22 23 status_t Close(bool deleteElements, 24 const Vector<Element*>** elements = NULL); 25 26 status_t Push(Element* element); 27 status_t Pop(Element** element, 28 bigtime_t timeout = B_INFINITE_TIMEOUT); 29 status_t Peek(Element** element); 30 status_t Remove(Element* element); 31 32 int32 Size() const; 33 34 private: 35 Vector<Element*> fElements; 36 sem_id fElementSemaphore; 37 }; 38 39 // constructor 40 template<typename Element> 41 BlockingQueue<Element>::BlockingQueue(const char* name) 42 : fElements(), 43 fElementSemaphore(-1) 44 { 45 fElementSemaphore = create_sem(0, (name ? name : "blocking queue")); 46 } 47 48 // destructor 49 template<typename Element> 50 BlockingQueue<Element>::~BlockingQueue() 51 { 52 if (fElementSemaphore >= 0) 53 delete_sem(fElementSemaphore); 54 } 55 56 // InitCheck 57 template<typename Element> 58 status_t 59 BlockingQueue<Element>::InitCheck() const 60 { 61 return (fElementSemaphore < 0 ? fElementSemaphore : B_OK); 62 } 63 64 // Close 65 template<typename Element> 66 status_t 67 BlockingQueue<Element>::Close(bool deleteElements, 68 const Vector<Element*>** elements) 69 { 70 AutoLocker<Locker> _(this); 71 status_t error = delete_sem(fElementSemaphore); 72 if (error != B_OK) 73 return error; 74 fElementSemaphore = -1; 75 if (elements) 76 *elements = &fElements; 77 if (deleteElements) { 78 int32 count = fElements.Count(); 79 for (int32 i = 0; i < count; i++) 80 delete fElements.ElementAt(i); 81 } 82 return error; 83 } 84 85 // Push 86 template<typename Element> 87 status_t 88 BlockingQueue<Element>::Push(Element* element) 89 { 90 AutoLocker<Locker> _(this); 91 if (fElementSemaphore < 0) 92 return B_NO_INIT; 93 status_t error = fElements.PushBack(element); 94 if (error != B_OK) 95 return error; 96 error = release_sem(fElementSemaphore); 97 if (error != B_OK) 98 fElements.Erase(fElements.Count() - 1); 99 return error; 100 } 101 102 // Pop 103 template<typename Element> 104 status_t 105 BlockingQueue<Element>::Pop(Element** element, bigtime_t timeout) 106 { 107 status_t error = acquire_sem_etc(fElementSemaphore, 1, B_RELATIVE_TIMEOUT, 108 timeout); 109 if (error != B_OK) 110 return error; 111 AutoLocker<Locker> _(this); 112 if (fElementSemaphore < 0) 113 return B_NO_INIT; 114 int32 count = fElements.Count(); 115 if (count == 0) 116 return B_ERROR; 117 *element = fElements.ElementAt(0); 118 fElements.Erase(0); 119 return B_OK; 120 } 121 122 // Peek 123 template<typename Element> 124 status_t 125 BlockingQueue<Element>::Peek(Element** element) 126 { 127 AutoLocker<Locker> _(this); 128 if (fElementSemaphore < 0) 129 return B_NO_INIT; 130 int32 count = fElements.Count(); 131 if (count == 0) 132 return B_ENTRY_NOT_FOUND; 133 *element = fElements.ElementAt(0); 134 return B_OK; 135 } 136 137 // Remove 138 template<typename Element> 139 status_t 140 BlockingQueue<Element>::Remove(Element* element) 141 { 142 status_t error = acquire_sem_etc(fElementSemaphore, 1, 143 B_RELATIVE_TIMEOUT, 0); 144 if (error != B_OK) 145 return error; 146 AutoLocker<Locker> _(this); 147 if (fElementSemaphore < 0) 148 return B_NO_INIT; 149 int32 count = fElements.Remove(element); 150 if (count == 0) { 151 release_sem(fElementSemaphore); 152 return B_ENTRY_NOT_FOUND; 153 } 154 if (count > 1) { 155 ERROR("ERROR: BlockingQueue::Remove(): Removed %ld elements!\n", 156 count); 157 } 158 return error; 159 } 160 161 // Size 162 template<typename Element> 163 int32 164 BlockingQueue<Element>::Size() const 165 { 166 AutoLocker<Locker> _(this); 167 return (fElements.Count()); 168 } 169 170 #endif // BLOCKING_QUEUE_H 171