* Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com
*
* All rights reserved. Distributed under the terms of the MIT License.
*
*/
#include "snet_buffer.h"
#include <malloc.h>
#include <string.h>
#include <KernelExport.h>
struct snet_buffer {
struct list_link link;
uint8* buffer;
uint16 allocatedSize;
uint16 expectedSize;
uint16 puttingSize;
uint16 pullingSize;
void* cookie;
};
snet_buffer*
snb_create(uint16 size)
{
#ifdef SNB_BUFFER_ATTACHED
snet_buffer* snb = (snet_buffer*) malloc(sizeof(snet_buffer) + size);
snb->buffer = ((uint8*)snb) + sizeof(snet_buffer);
#else
snet_buffer* snb = malloc(sizeof (snet_buffer));
snb->buffer = malloc(size);
#endif
snb->pullingSize = snb->puttingSize = 0;
snb->expectedSize = snb->allocatedSize = size;
return snb;
}
void
snb_put(snet_buffer* snb, void* data, uint16 size)
{
memcpy( &snb->buffer[snb->puttingSize], data, size);
snb->puttingSize+=size;
}
void*
snb_pull(snet_buffer* snb, uint16 size)
{
snb->pullingSize+=size;
return &snb->buffer[snb->pullingSize - size];
}
void
snb_reset(snet_buffer* snb)
{
snb->puttingSize = snb->pullingSize = 0;
}
void
snb_free(snet_buffer* snb)
{
if (snb == NULL)
return;
#ifdef SNB_BUFFER_ATTACHED
free(snb);
#else
free(snb->buffer);
free(snb);
#endif
}
void*
snb_get(snet_buffer* snb)
{
return snb->buffer;
}
uint16
snb_size(snet_buffer* snb)
{
return snb->expectedSize;
}
void*
snb_cookie(snet_buffer* snb)
{
return snb->cookie;
}
void
snb_set_cookie(snet_buffer* snb, void* cookie)
{
snb->cookie = cookie;
}
bool
snb_completed(snet_buffer* snb)
{
return (snb->expectedSize == snb->puttingSize);
}
bool
snb_finished(snet_buffer* snb)
{
return (snb->expectedSize == snb->pullingSize);
}
uint16
snb_remaining_to_put(snet_buffer* snb)
{
return (snb->expectedSize - snb->puttingSize);
}
uint16
snb_remaining_to_pull(snet_buffer* snb)
{
return (snb->expectedSize - snb->pullingSize);
}
ISSUE1: Number of packets in the worst case(we always need a bigger
buffer than before) increases, never decreases:
SOL1: Delete the smallest when the queue is bigger than X elements
SOL2: ?
ISSUE2: If the queue is not gonna be used for long time. Memory c
ould be freed
SOL1: Provide purge func.
SOL2: ?
*/
static snet_buffer*
snb_attempt_reuse(snet_buffer* snb, uint16 size)
{
if (snb == NULL || (snb->allocatedSize < size)) {
snb_free(snb);
return snb_create(size);
} else {
snb_reset(snb);
snb->expectedSize = size;
return snb;
}
}
void
snb_park(struct list* l, snet_buffer* snb)
{
snet_buffer* item = NULL;
while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL) {
if (item->allocatedSize > snb->allocatedSize) {
list_insert_item_before(l, item, snb);
return;
}
}
list_add_item(l, snb);
}
snet_buffer*
snb_fetch(struct list* l, uint16 size)
{
snet_buffer* item = NULL;
snet_buffer* newitem = NULL;
if (!list_is_empty(l))
while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL) {
if (item->allocatedSize >= size) {
break;
}
}
newitem = snb_attempt_reuse(item, size);
* as we fetched? => remove it from list
*/
if (item == newitem) {
list_remove_item(l, item);
}
return newitem;
}
uint16
snb_packets(struct list* l)
{
uint16 count = 0;
snet_buffer* item = NULL;
while ((item = (snet_buffer*)list_get_next_item(l, item)) != NULL)
count++;
return count;
}
void
snb_dump(snet_buffer* snb)
{
kprintf("item=%p\tprev=%p\tnext=%p\tallocated=%d\n", snb, snb->link.prev,
snb->link.next, snb->allocatedSize);
}