xref: /haiku/src/apps/installer/BlockingQueue.h (revision d12bb8b14803d030b4a8fba91131e4bb96c4f406)
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