1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
|
/* Copyright (c) 2001, Stanford University
* All rights reserved
*
* See the file LICENSE.txt for information on redistributing this software.
*/
#include "cr_mem.h"
#include "cr_error.h"
#include "cr_bufpool.h"
#include <limits.h>
/*
* New (version 1.4) buffer pool implementation.
*
* Now, each buffer in the pool can be a different size.
* We only return a buffer from crBufferPoolPop() if we have exactly
* the right size buffer.
*
* Note: the old implementation had a 'max buffers' parameter but it
* really wasn't good for anything since we always grew the buffer pool
* if we pushed a new buffer that would cause use to exceed the limit.
* That's gone now.
*
* We're just using a simple linked list here. Since we seldom have
* more than about 10-15 buffers in the pool, that's OK. A binary tree
* would be nicer though.
*
* MCH: BufferPoolPop will now return the smallest buffer in the pool that
* is >= to the size required. This fixes BufferPool overruns with lots
* of MTUs.
*/
#ifndef NULL
#define NULL ((void *) 0)
#endif
typedef struct buffer
{
void *address;
unsigned int size;
struct buffer *next;
} Buffer;
struct CRBufferPool_t
{
unsigned int maxBuffers;
int numBuffers;
struct buffer *head;
};
int
crBufferPoolGetNumBuffers( CRBufferPool *pool )
{
if ( pool )
return pool->numBuffers;
return 0;
}
int
crBufferPoolGetMaxBuffers( CRBufferPool *pool )
{
if ( pool )
return pool->maxBuffers;
return 0;
}
CRBufferPool *
crBufferPoolInit( unsigned int maxBuffers )
{
CRBufferPool *pool = crCalloc(sizeof(CRBufferPool));
if (pool) {
pool->head = NULL;
pool->maxBuffers = maxBuffers;
pool->numBuffers = 0;
}
return pool;
}
void
crBufferPoolFree( CRBufferPool *pool )
{
Buffer *b, *next;
for (b = pool->head; b; b = next) {
next = b->next;
crFree(b->address);
crFree(b);
}
}
void
crBufferPoolCallbackFree(CRBufferPool *pool, CRBufferPoolDeleteCallback pfnDelete)
{
Buffer *b, *next;
CRASSERT(pfnDelete);
for (b = pool->head; b; b = next) {
next = b->next;
(*pfnDelete)(b->address);
crFree(b);
}
}
void
crBufferPoolPush( CRBufferPool *pool, void *buf, unsigned int bytes )
{
Buffer *b = crCalloc(sizeof(Buffer));
if (b) {
#ifdef DEBUG
/* check that the buffer to push isn't already in the pool! */
{
const Buffer *bd;
for (bd = pool->head; bd; bd = bd->next) {
CRASSERT(bd->address != buf);
}
}
#endif
b->address = buf;
b->size = bytes;
b->next = pool->head;
pool->head = b;
pool->numBuffers++;
}
}
void *
crBufferPoolPop( CRBufferPool *pool, unsigned int bytes )
{
Buffer *b, *prev, *prev_smallest;
unsigned int smallest = UINT_MAX; /* size of smallest buffer >= bytes */
int i;
prev = NULL;
prev_smallest = NULL;
for (b = pool->head, i=0; i<pool->numBuffers; b = b->next, i++) {
if (b->size == bytes) {
/* we found an exact size match! */
void *p = b->address;
if (prev) {
prev->next = b->next;
}
else {
pool->head = b->next;
}
crFree(b);
pool->numBuffers--;
CRASSERT(pool->numBuffers >= 0);
return p;
}
else if (b->size >= bytes){
/* We found a buffer that's large enough, but keep looking
* for a smaller one that's large enough.
*/
if (b->size < smallest) {
prev_smallest = prev; /* save ptr to previous! */
smallest = b->size;
}
}
prev = b;
}
if (smallest < UINT_MAX) {
/* we found the smallest buffer whose size is > bytes */
void *p;
if (prev_smallest) {
b = prev_smallest->next;
}
else {
b = pool->head;
}
CRASSERT(b->size == smallest);
CRASSERT(b->size >= bytes);
p = b->address;
if (prev_smallest) {
prev_smallest->next = b->next;
}
else {
pool->head = b->next;
}
crFree(b);
pool->numBuffers--;
CRASSERT(pool->numBuffers >= 0);
return p;
}
/* found no buffer large enough */
return NULL;
}
|