diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.c b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.c new file mode 100644 index 0000000000..faa1da4f92 --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.c @@ -0,0 +1,215 @@ +/* + * 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" + + +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) +{ + /* TODO: pointer checking */ + +#ifdef SNB_BUFFER_ATTACHED + /* Allocating these 2 buffers together might prevent memory fragmentation? */ + 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) +{ + /* TODO: check overflow */ + memcpy( &snb->buffer[snb->puttingSize], data, size); + snb->puttingSize+=size; +} + + +void* +snb_pull(snet_buffer* snb, uint16 size) +{ + /* TODO: check overflow */ + snb->pullingSize+=size; + return &snb->buffer[snb->pullingSize-size]; + +} + + +inline 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 + +} + + +inline void* +snb_get(snet_buffer* snb) +{ + /* TODO: pointer checking */ + return snb->buffer; +} + + +inline uint16 +snb_size(snet_buffer* snb) +{ + /* TODO: pointer checking */ + return snb->expectedSize; +} + + +inline void* +snb_cookie(snet_buffer* snb) +{ + /* TODO: pointer checking */ + return snb->cookie; +} + + +inline void +snb_set_cookie(snet_buffer* snb, void* cookie) +{ + /* TODO: pointer checking */ + snb->cookie = cookie; +} + + +/* Return true if we canot "put" more data in the buffer */ +inline bool snb_completed(snet_buffer* snb) +{ + return (snb != NULL && (snb->expectedSize == snb->puttingSize)); +} + + +/* Return true if we cannot pull more more data from the buffer */ +inline bool snb_finished(snet_buffer* snb) +{ + return (snb != NULL && (snb->expectedSize == snb->pullingSize)); +} + + +inline bool snb_remaining_to_put(snet_buffer* snb) +{ + return (snb != NULL && (snb->expectedSize - snb->puttingSize)); +} + + +inline bool snb_remaining_to_pull(snet_buffer* snb) +{ + return (snb != NULL && (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 || + ((int16)snb->allocatedSize - (int16)size) < 0 ) { + + /* Impossible or not worth, Creating a new one */ + 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; + /* insert it by order */ + while ((item = list_get_next_item(l, item)) != NULL) { + if (item->allocatedSize > snb->allocatedSize) + list_insert_item_before(l, item, snb); + } +} + + +snet_buffer* +snb_fetch(struct list* l, uint16 size) +{ + + snet_buffer* item = NULL; + snet_buffer* previous = NULL; + + if (!list_is_empty(l)) + while ((item = list_get_next_item(l, item)) != NULL) { + if (item->allocatedSize == size) { + /* This one is for us*/ + break; + } + else if (item->allocatedSize > size) { + /* get the previous*/ + item = previous; + break; + } + previous = item; + } + + return snb_attempt_reuse(item, size); +} diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.h b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.h new file mode 100644 index 0000000000..75c69278c2 --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.h @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + + +#ifndef _SNET_BUFFER_H_ +#define _SNET_BUFFER_H_ + +#include + +/* + * This is a simple data structure to hold network buffers. + * It drops many functionality that the Haiku net_buffer provides. + * + * - Inspired by linux sk_buff/bsd mbuf (put/pull) + * - Contiguoussafe (no push operation) + * + * So snet_buffers are ONLY meant to be used when: + * 1) You know exactily the maximun/final size of the frame + * before allocating it, and you will never exceed it. + * 2) You are not supposed to prepend data, only append. + * + */ + +/* Configuration parameters */ +#define SNB_BUFFER_ATTACHED +//#define SNB_PERFORMS_OVERFLOW_CHECKS +//#define SNB_PERFORMS_POINTER_CHECKS + +struct snet_buffer; + +typedef struct snet_buffer snet_buffer; + +/* Creates a snb_buffer allocating size space for its full content */ +snet_buffer* snb_create(uint16 size); +/* Free the snb_buffer*/ +void snb_free(snet_buffer* snb); +/* Free the snb_buffer*/ +void* snb_get(snet_buffer* snb); +/* Size of the snb_buffer*/ +uint16 snb_size(snet_buffer* snb); + +/* Cookie of the snb_buffer*/ +void* snb_cookie(snet_buffer* snb); +/* Get Cookie of the snb_buffer*/ +void snb_set_cookie(snet_buffer* snb, void* cookie); + +/* Place the memory given by data to the "tail" of the snb */ +void snb_put(snet_buffer* snb, void* data, uint16 size); +/* Returns a header chunk of size data */ +void* snb_pull(snet_buffer* snb, uint16 size); +/* Discards all data put or pulled from the buffer */ +void snb_reset(snet_buffer* snb); + +/* Return true if we canot "put" more data in the buffer */ +bool snb_completed(snet_buffer* snb); +/* Return true if we cannot pull more more data from the buffer */ +bool snb_finished(snet_buffer* snb); +/* Return the amount of data we can still put in the buffer */ +bool snb_remaining_to_put(snet_buffer* snb); +/* Return the amount of data we can still pull in the buffer */ +bool snb_remaining_to_pull(snet_buffer* snb); + +/* These to functions are provided to avoid memory fragmentation + * allocating and freeing many snb_buffers and its possible overhead. + * Thypical scenario would be + * that you create a snb_buffer to send data, once you send you free it, + * and need another one to hold the response. The idea would be once you send + * that buffer, to snb_park the buffer, and whenever you need to allocate another + * one snb_fetch it. That funcion will reuse most appropiated previous used one + * snb_buff by its memory use. + */ +void snb_park(struct list* l, snet_buffer* snb); +snet_buffer* snb_fetch(struct list* l, uint16 size); + + + +#endif