1/* BufferPool - a buffer pool for uncached file access
2**
3** Initial version by Axel Dörfler, axeld@pinc-software.de
4** This file may be used under the terms of the OpenBeOS License.
5*/
6
7
8#include "BufferPool.h"
9#include "Debug.h"
10
11#include <util/kernel_cpp.h>
12
13
14const uint32 kNumBuffers = 8;
15
16
17BufferPool::BufferPool()
18	:
19	fFirstFree(NULL)
20{
21	fLock = create_sem(1, "buffer lock");
22	fFreeBuffers = create_sem(0, "free buffers");
23
24#ifndef USER
25	set_sem_owner(fLock, B_SYSTEM_TEAM);
26	set_sem_owner(fFreeBuffers, B_SYSTEM_TEAM);
27#endif
28}
29
30
31BufferPool::~BufferPool()
32{
33	delete_sem(fFreeBuffers);
34
35	acquire_sem(fLock);
36		// the return value doesn't interest us anymore
37
38	void **buffer = fFirstFree;
39	while (buffer != NULL) {
40		void **nextBuffer = (void **)*buffer;
41		free(buffer);
42		buffer = nextBuffer;
43	}
44
45	delete_sem(fLock);
46}
47
48
49status_t
50BufferPool::InitCheck()
51{
52	if (fLock < B_OK
53		|| fFreeBuffers < B_OK)
54		return B_ERROR;
55
56	return B_OK;
57}
58
59
60status_t
61BufferPool::RequestBuffers(uint32 blockSize)
62{
63	void **buffers[kNumBuffers];
64
65	// allocate and connect buffers
66
67	for (uint32 i = 0; i < kNumBuffers; i++) {
68		buffers[i] = (void **)malloc(blockSize);
69		if (buffers[i] == NULL) {
70			// free already allocated buffers
71			for (;i-- > 0; i++)
72				free(buffers[i]);
73			RETURN_ERROR(B_NO_MEMORY);
74		}
75		if (i > 0)
76			*(buffers[i]) = buffers[i - 1];
77	}
78
79	// add the buffers to the free buffers queue
80
81	status_t status = acquire_sem(fLock);
82	if (status == B_OK) {
83		*(buffers[0]) = fFirstFree;
84		fFirstFree = buffers[kNumBuffers - 1];
85		release_sem(fLock);
86		release_sem_etc(fFreeBuffers, kNumBuffers, B_DO_NOT_RESCHEDULE);
87	} else {
88		for (uint32 i = 0; i < kNumBuffers; i++)
89			free(buffers[i]);
90	}
91
92	RETURN_ERROR(status);
93}
94
95
96status_t
97BufferPool::ReleaseBuffers()
98{
99	status_t status = acquire_sem_etc(fFreeBuffers, kNumBuffers, 0, 0);
100	if (status < B_OK)
101		return status;
102
103	status = acquire_sem(fLock);
104	if (status < B_OK)
105		return status;
106
107	void **buffer = fFirstFree;
108	for (uint32 i = 0; i < kNumBuffers && buffer; i++) {
109		void **nextBuffer = (void **)*buffer;
110
111		free(buffer);
112		buffer = nextBuffer;
113	}
114	fFirstFree = buffer;
115
116	release_sem(fLock);
117	return B_OK;
118}
119
120
121status_t
122BufferPool::GetBuffer(void **_buffer)
123{
124	status_t status = acquire_sem(fFreeBuffers);
125	if (status < B_OK)
126		return status;
127
128	if ((status = acquire_sem(fLock)) < B_OK) {
129		release_sem(fFreeBuffers);
130		return status;
131	}
132
133	void **buffer = fFirstFree;
134	fFirstFree = (void **)*buffer;
135
136	release_sem(fLock);
137
138	*_buffer = (void *)buffer;
139	return B_OK;
140}
141
142
143status_t
144BufferPool::PutBuffer(void *_buffer)
145{
146	void **buffer = (void **)_buffer;
147	if (buffer == NULL)
148		return B_BAD_VALUE;
149
150	status_t status = acquire_sem(fLock);
151	if (status < B_OK)
152		return status;
153
154	*buffer = fFirstFree;
155	fFirstFree = buffer;
156
157	release_sem(fLock);
158	release_sem(fFreeBuffers);
159
160	return B_OK;
161}
162
163