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
15template<typename Element>
16class BlockingQueue : public Locker {
17public:
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
34private:
35			Vector<Element*>	fElements;
36			sem_id				fElementSemaphore;
37};
38
39// constructor
40template<typename Element>
41BlockingQueue<Element>::BlockingQueue(const char* name)
42	: fElements(),
43	  fElementSemaphore(-1)
44{
45	fElementSemaphore = create_sem(0, (name ? name : "blocking queue"));
46}
47
48// destructor
49template<typename Element>
50BlockingQueue<Element>::~BlockingQueue()
51{
52	if (fElementSemaphore >= 0)
53		delete_sem(fElementSemaphore);
54}
55
56// InitCheck
57template<typename Element>
58status_t
59BlockingQueue<Element>::InitCheck() const
60{
61	return (fElementSemaphore < 0 ? fElementSemaphore : B_OK);
62}
63
64// Close
65template<typename Element>
66status_t
67BlockingQueue<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
86template<typename Element>
87status_t
88BlockingQueue<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
103template<typename Element>
104status_t
105BlockingQueue<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
123template<typename Element>
124status_t
125BlockingQueue<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
138template<typename Element>
139status_t
140BlockingQueue<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
162template<typename Element>
163int32
164BlockingQueue<Element>::Size() const
165{
166	AutoLocker<Locker> _(this);
167	return (fElements.Count());
168}
169
170#endif	// BLOCKING_QUEUE_H
171