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