xref: /haiku/src/apps/installer/BlockingQueue.h (revision f7c507c3a6fbf3a44c59500543926a9088724968)
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 <vector>
32 
33 #include <Locker.h>
34 
35 #include "AutoLocker.h"
36 
37 using std::vector;
38 
39 typedef BLocker Locker;
40 
41 template<typename Element>
42 class BlockingQueue : public Locker {
43 public:
44 								BlockingQueue(const char* name = NULL);
45 								~BlockingQueue();
46 
47 			status_t			InitCheck() const;
48 
49 			status_t			Close(bool deleteElements,
50 									const vector<Element*>** elements = NULL);
51 
52 			status_t			Push(Element* element);
53 			status_t			Pop(Element** element,
54 									bigtime_t timeout = B_INFINITE_TIMEOUT);
55 			status_t			Peek(Element** element);
56 			status_t			Remove(Element* element);
57 
58 			int32				Size();
59 
60 private:
61 			vector<Element*>	fElements;
62 			sem_id				fElementSemaphore;
63 };
64 
65 // constructor
66 template<typename Element>
67 BlockingQueue<Element>::BlockingQueue(const char* name)
68 	: fElements(),
69 	  fElementSemaphore(-1)
70 {
71 	fElementSemaphore = create_sem(0, (name ? name : "blocking queue"));
72 }
73 
74 // destructor
75 template<typename Element>
76 BlockingQueue<Element>::~BlockingQueue()
77 {
78 	if (fElementSemaphore >= 0)
79 		delete_sem(fElementSemaphore);
80 }
81 
82 // InitCheck
83 template<typename Element>
84 status_t
85 BlockingQueue<Element>::InitCheck() const
86 {
87 	return (fElementSemaphore < 0 ? fElementSemaphore : B_OK);
88 }
89 
90 // Close
91 template<typename Element>
92 status_t
93 BlockingQueue<Element>::Close(bool deleteElements,
94 	const vector<Element*>** elements)
95 {
96 	AutoLocker<Locker> _(this);
97 	status_t error = delete_sem(fElementSemaphore);
98 	if (error != B_OK)
99 		return error;
100 	fElementSemaphore = -1;
101 	if (elements)
102 		*elements = &fElements;
103 	if (deleteElements) {
104 		int32 count = fElements.size();
105 		for (int32 i = 0; i < count; i++)
106 			delete fElements[i];
107 	}
108 	return error;
109 }
110 
111 // Push
112 template<typename Element>
113 status_t
114 BlockingQueue<Element>::Push(Element* element)
115 {
116 	AutoLocker<Locker> _(this);
117 	if (fElementSemaphore < 0)
118 		return B_NO_INIT;
119 	try {
120 		fElements.push_back(element);
121 	} catch (std::bad_alloc&) {
122 		return B_NO_MEMORY;
123 	}
124 	status_t error = release_sem(fElementSemaphore);
125 	if (error != B_OK)
126 		fElements.erase(fElements.begin() + fElements.size() - 1);
127 	return error;
128 }
129 
130 // Pop
131 template<typename Element>
132 status_t
133 BlockingQueue<Element>::Pop(Element** element, bigtime_t timeout)
134 {
135 	status_t error = acquire_sem_etc(fElementSemaphore, 1, B_RELATIVE_TIMEOUT,
136 		timeout);
137 	if (error != B_OK)
138 		return error;
139 	AutoLocker<Locker> _(this);
140 	if (fElementSemaphore < 0)
141 		return B_NO_INIT;
142 	int32 count = fElements.size();
143 	if (count == 0)
144 		return B_ERROR;
145 	*element = fElements[0];
146 	fElements.erase(fElements.begin());
147 	return B_OK;
148 }
149 
150 // Peek
151 template<typename Element>
152 status_t
153 BlockingQueue<Element>::Peek(Element** element)
154 {
155 	AutoLocker<Locker> _(this);
156 	if (fElementSemaphore < 0)
157 		return B_NO_INIT;
158 	int32 count = fElements.size();
159 	if (count == 0)
160 		return B_ENTRY_NOT_FOUND;
161 	*element = fElements[0];
162 	return B_OK;
163 }
164 
165 // Remove
166 template<typename Element>
167 status_t
168 BlockingQueue<Element>::Remove(Element* element)
169 {
170 	status_t error = acquire_sem_etc(fElementSemaphore, 1,
171 		B_RELATIVE_TIMEOUT, 0);
172 	if (error != B_OK)
173 		return error;
174 	AutoLocker<Locker> _(this);
175 	if (fElementSemaphore < 0)
176 		return B_NO_INIT;
177 
178 	int32 count = 0;
179 	for (int32 i = fElements.size() - 1; i >= 0; i--) {
180 		if (fElements[i] == element) {
181 			fElements.erase(fElements.begin() + i);
182 			count++;
183 		}
184 	}
185 	if (count == 0) {
186 		release_sem(fElementSemaphore);
187 		return B_ENTRY_NOT_FOUND;
188 	}
189 #if 0
190 	if (count > 1) {
191 		ERROR(("ERROR: BlockingQueue::Remove(): Removed %ld elements!\n",
192 			count));
193 	}
194 #endif
195 	return error;
196 }
197 
198 // Size
199 template<typename Element>
200 int32
201 BlockingQueue<Element>::Size()
202 {
203 	AutoLocker<Locker> _(this);
204 	return (fElements.size());
205 }
206 
207 #endif	// BLOCKING_QUEUE_H
208