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