xref: /haiku/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.cpp (revision 68ea01249e1e2088933cb12f9c28d4e5c5d1c9ef)
1 /*
2  * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
3  *
4  * All rights reserved. Distributed under the terms of the MIT License.
5  *
6  */
7 
8 
9 #include "snet_buffer.h"
10 
11 #include <malloc.h>
12 #include <string.h>
13 #include <KernelExport.h>
14 
15 
16 struct snet_buffer {
17 	struct list_link	link;
18 
19 	uint8*				buffer;
20 
21 	uint16				allocatedSize;
22 	uint16				expectedSize;
23 	uint16				puttingSize;
24 	uint16				pullingSize;
25 
26 	void*				cookie;
27 };
28 
29 
30 snet_buffer*
31 snb_create(uint16 size)
32 {
33 	// TODO: pointer checking
34 
35 #ifdef SNB_BUFFER_ATTACHED
36 	// Allocating these 2 buffers together might prevent memory fragmentation
37 	snet_buffer* snb = (snet_buffer*) malloc(sizeof(snet_buffer) + size);
38 	snb->buffer = ((uint8*)snb) + sizeof(snet_buffer);
39 #else
40 	snet_buffer* snb = malloc(sizeof (snet_buffer));
41 	snb->buffer = malloc(size);
42 #endif
43 
44 	snb->pullingSize = snb->puttingSize = 0;
45 	snb->expectedSize = snb->allocatedSize = size;
46 
47 	return snb;
48 }
49 
50 
51 void
52 snb_put(snet_buffer* snb, void* data, uint16 size)
53 {
54 	// TODO: check overflow
55 	memcpy( &snb->buffer[snb->puttingSize], data, size);
56 	snb->puttingSize+=size;
57 }
58 
59 
60 void*
61 snb_pull(snet_buffer* snb, uint16 size)
62 {
63 	// TODO: check overflow
64 	snb->pullingSize+=size;
65 	return &snb->buffer[snb->pullingSize - size];
66 
67 }
68 
69 
70 void
71 snb_reset(snet_buffer* snb)
72 {
73 	snb->puttingSize = snb->pullingSize = 0;
74 }
75 
76 
77 void
78 snb_free(snet_buffer* snb)
79 {
80 	if (snb == NULL)
81 		return;
82 
83 #ifdef SNB_BUFFER_ATTACHED
84 	free(snb);
85 #else
86 	free(snb->buffer);
87 	free(snb);
88 #endif
89 
90 }
91 
92 
93 void*
94 snb_get(snet_buffer* snb)
95 {
96 	// TODO: pointer checking
97 	return snb->buffer;
98 }
99 
100 
101 uint16
102 snb_size(snet_buffer* snb)
103 {
104 	// TODO: pointer checking
105 	return snb->expectedSize;
106 }
107 
108 
109 void*
110 snb_cookie(snet_buffer* snb)
111 {
112 	// TODO: pointer checking
113 	return snb->cookie;
114 }
115 
116 
117 void
118 snb_set_cookie(snet_buffer* snb, void* cookie)
119 {
120 	// TODO: pointer checking
121 	snb->cookie = cookie;
122 }
123 
124 
125 // Return true if we canot "put" more data in the buffer
126 bool
127 snb_completed(snet_buffer* snb)
128 {
129 	return (snb->expectedSize == snb->puttingSize);
130 }
131 
132 
133 // Return true if we cannot pull more more data from the buffer
134 bool
135 snb_finished(snet_buffer* snb)
136 {
137 	return (snb->expectedSize == snb->pullingSize);
138 }
139 
140 
141 uint16
142 snb_remaining_to_put(snet_buffer* snb)
143 {
144 	return (snb->expectedSize - snb->puttingSize);
145 }
146 
147 
148 uint16
149 snb_remaining_to_pull(snet_buffer* snb)
150 {
151 	return (snb->expectedSize - snb->pullingSize);
152 }
153 
154 /*
155 	ISSUE1: Number of packets in the worst case(we always need a bigger
156 	buffer than before) increases, never decreases:
157 
158 	SOL1: Delete the smallest when the queue is bigger than X elements
159 	SOL2: ?
160 
161 	ISSUE2: If the queue is not gonna be used for long time. Memory c
162 	ould be freed
163 
164 	SOL1: Provide purge func.
165 	SOL2: ?
166 */
167 
168 
169 static snet_buffer*
170 snb_attempt_reuse(snet_buffer* snb, uint16 size)
171 {
172 	if (snb == NULL || (snb->allocatedSize < size)) {
173 
174 		// Impossible or not worth, Creating a new one
175 		snb_free(snb);
176 		return snb_create(size);
177 
178 	} else {
179 		snb_reset(snb);
180 		snb->expectedSize = size;
181 		return snb;
182 	}
183 
184 }
185 
186 
187 void
188 snb_park(struct list* l, snet_buffer* snb)
189 {
190 	snet_buffer* item = NULL;
191 
192 	// insert it by order
193 	while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL) {
194 		// This one has allocated more than us place us back
195 		if (item->allocatedSize > snb->allocatedSize) {
196 			list_insert_item_before(l, item, snb);
197 			return;
198 		}
199 	}
200 	// no buffer bigger than us(or empty).. then at the end
201 	list_add_item(l, snb);
202 }
203 
204 
205 snet_buffer*
206 snb_fetch(struct list* l, uint16 size)
207 {
208 	snet_buffer* item = NULL;
209 	snet_buffer* newitem = NULL;
210 
211 	if (!list_is_empty(l))
212 	while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL) {
213 		if (item->allocatedSize >= size) {
214 			// This one is for us
215 			break;
216 		}
217 	}
218 
219 	newitem = snb_attempt_reuse(item, size);
220 
221 	/* the resulting reused one is the same
222 	 * as we fetched? => remove it from list
223 	 */
224 	if (item == newitem) {
225 		list_remove_item(l, item);
226 	}
227 
228 	return newitem;
229 }
230 
231 
232 uint16
233 snb_packets(struct list* l)
234 {
235 	uint16 count = 0;
236 	snet_buffer* item = NULL;
237 
238 	while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL)
239 		count++;
240 
241 	return count;
242 }
243 
244 
245 void
246 snb_dump(snet_buffer* snb)
247 {
248 	kprintf("item=%p\tprev=%p\tnext=%p\tallocated=%d\n", snb, snb->link.prev,
249 		snb->link.next, snb->allocatedSize);
250 }
251