A helper datastructure for network buffers. Defines a fixed-size region of same-size data blocks, and maintains a reference count for each

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@18896 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Andrew Galante 2006-09-21 02:40:20 +00:00
parent 46564600a4
commit b425ce77ad
2 changed files with 211 additions and 0 deletions

View File

@ -0,0 +1,27 @@
/* General data region of fixed size data blocks
*
* Copyright 2006, Haiku, Inc. All Rights Reserved
* Distributed under the terms of the MIT liscence.
*
* Authors:
* Andrew Galante, haiku.galante@gmail.com
*/
struct datastore {
void *store; // ptr to data region
size_t blocksize; // size of the blocks in the datastore
size_t blockcount; // total number of blocks in the datastore
int32 *refcounts; // array containing refcounts for each block. a refcount of 0 is a free block
int lastfreed; // index of last freed block
int nextfree; // index of next free block
};
status_t init_datastore(struct datastore *store, size_t blocksize, int blockcount); // initializes the datastore
status_t uninit_datastore(struct datastore *store); // frees the memory used by the datastore
void *get_datablock(struct datastore *store); // returns a ptr to the first found free block, and increments its refcount
void *get_datablock(struct datastore *store, void *block); // increments the refcount of the specified block
status_t put_datablock(struct datastore *store, void *block); // decrements the refcount of the specified block
// not thread safe - for amusement purposes only:
int is_empty_datastore(struct datastore *store); // returns nonzero if all refcounts are zero
int is_full_datastore(struct datastore *store); // returns nonzero if all refcounts are greater than zero

View File

@ -0,0 +1,184 @@
/* General data region of fixed size data blocks
*
* Copyright 2006, Haiku, Inc. All Rights Reserved
* Distributed under the terms of the MIT liscence.
*
* Authors:
* Andrew Galante : haiku.galante@gmail.com
*/
#include <KernelExport.h>
#include <malloc.h>
#include <debug.h>
#include <Errors.h>
#include <string.h>
#include <util/datastore.h>
/*!
* Creates a new datastore with \a blockcount datablocks of \a blocksize size
* \return B_NO_MEMORY if there is not enough memory to allocate to the datastore
* \return B_BAD_VALUE if blockcount is negative
*/
status_t
init_datastore(struct datastore *store, size_t blocksize, int blockcount)
{
if (blockcount < 1)
return B_BAD_VALUE;
store->blocksize = blocksize;
store->blockcount = blockcount;
store->store = malloc(blocksize * blockcount);
if (store->store == NULL)
return B_NO_MEMORY;
store->refcounts = (int32 *)calloc(blockcount, sizeof(uint32));
if (store->refcounts == NULL)
return B_NO_MEMORY;
store->lastfreed = -1;
store->nextfree = 0;
return B_OK;
}
/*!
* Frees all memory occupied by the datastore, except for the datastore structure itself
*/
status_t
uninit_datastore(struct datastore *store)
{
store->blocksize = 0;
store->blockcount = 0;
free(store->store);
store->store = NULL;
free(store->refcounts);
store->refcounts = NULL;
store->lastfreed = -1;
store->nextfree = 0;
return B_OK;
}
/*!
* Searches the datastore for a free datablock. If none are free,
* continues search until one is freed.
* \return a pointer to the datablock
* \return NULL if the datastore has not been properly initialized
*/
void *
get_datablock(struct datastore *store)
{
void *block = NULL;
if (store->store == NULL)
return NULL;
int index = store->lastfreed;
// first check lastfreed index, as that's most likely to be free
if (index >= 0) {
if (atomic_add(&store->refcounts[index], 1) == 0) {
block = (void *)(index * store->blocksize + (uint8 *)store->store);
store->lastfreed = -1;
return block;
} else
atomic_add(&store->refcounts[index], -1);
}
// otherwise start at the "next free" block and search
index = store->nextfree;
while (1) {
if(atomic_add(&store->refcounts[index], 1) == 0) {
// found a free block
block = (void *)(index * store->blocksize + (uint8 *)store->store);
store->nextfree = (index + 1) % store->blockcount;
break;
} else
atomic_add(&store->refcounts[index], -1);
index = (index + 1) % store->blockcount;
}
return block;
}
/*!
* Increments the refcount of the specified block
* \return a reference to the block on success
* \return NULL if there was an error
*/
void *
get_datablock(struct datastore *store, void *block)
{
if (block == NULL
|| block < store->store
|| block > (uint8 *)store->store + (store->blocksize * store->blockcount))
return NULL;
size_t i = ((uint8 *)block - (uint8 *)store->store) / store->blocksize;
if (atomic_add(&store->refcounts[i], 1) < 0) {
atomic_add(&store->refcounts[i], -1);
return NULL;
}
return block;
}
/*!
* Decrements the refcount of the specified block
* \return B_OK on success
* \return B_BAD_VALUE if \a block is not in the datastore \a store
*/
status_t
put_datablock(struct datastore *store, void *block)
{
if (block == NULL
|| block < store->store
|| block > (uint8 *)store->store + (store->blocksize * store->blockcount))
return B_BAD_VALUE;
size_t i = ((uint8 *)block - (uint8 *)store->store) / store->blocksize;
if (store->refcounts[i] == 0)
return B_OK;
if (atomic_add(&store->refcounts[i], -1) == 1)
if ((store->nextfree - 1) % store->blockcount == i)
store->nextfree = i;
else
store->lastfreed = i;
return B_OK;
}
/*!
* Checks if the datastore is empty.
* Not guaranteed to be thread safe!
* \return nonzero if all blocks are free
* \return zero otherwise
*/
int
is_empty_datastore(struct datastore *store)
{
size_t i;
for (i = 0; i < store->blockcount; i++)
if (store->refcounts[i] != 0)
return 0;
return 1;
}
/*!
* Checks if the datastore is occupied
* Not guaranteed to be thread safe!
* \return nonzero if no blocks are free
* \return zero otherwise
*/
int is_full_datastore(struct datastore *store)
{
size_t i;
for (i = 0; i < store->blockcount; i++)
if (store->refcounts[i] == 0)
return 0;
return 1;
}