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*
snb_create(uint16 size)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
snb_put(snet_buffer * snb,void * data,uint16 size)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*
snb_pull(snet_buffer * snb,uint16 size)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
snb_reset(snet_buffer * snb)71 snb_reset(snet_buffer* snb)
72 {
73 snb->puttingSize = snb->pullingSize = 0;
74 }
75
76
77 void
snb_free(snet_buffer * snb)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*
snb_get(snet_buffer * snb)94 snb_get(snet_buffer* snb)
95 {
96 // TODO: pointer checking
97 return snb->buffer;
98 }
99
100
101 uint16
snb_size(snet_buffer * snb)102 snb_size(snet_buffer* snb)
103 {
104 // TODO: pointer checking
105 return snb->expectedSize;
106 }
107
108
109 void*
snb_cookie(snet_buffer * snb)110 snb_cookie(snet_buffer* snb)
111 {
112 // TODO: pointer checking
113 return snb->cookie;
114 }
115
116
117 void
snb_set_cookie(snet_buffer * snb,void * cookie)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
snb_completed(snet_buffer * snb)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
snb_finished(snet_buffer * snb)135 snb_finished(snet_buffer* snb)
136 {
137 return (snb->expectedSize == snb->pullingSize);
138 }
139
140
141 uint16
snb_remaining_to_put(snet_buffer * snb)142 snb_remaining_to_put(snet_buffer* snb)
143 {
144 return (snb->expectedSize - snb->puttingSize);
145 }
146
147
148 uint16
snb_remaining_to_pull(snet_buffer * snb)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*
snb_attempt_reuse(snet_buffer * snb,uint16 size)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
snb_park(struct list * l,snet_buffer * snb)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*
snb_fetch(struct list * l,uint16 size)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
snb_packets(struct list * l)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
snb_dump(snet_buffer * snb)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