xref: /haiku/src/add-ons/kernel/file_systems/netfs/headers/shared/BlockingQueue.h (revision 372b901dfeada686207d00bbcce456f748bbda12)
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