You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
897 lines
23 KiB
897 lines
23 KiB
/**
|
|
* \file This holds all stufff related our memory managent.
|
|
* I try the best as far as I can to reduce memory fragmentation
|
|
* and unneccessary calls to alloc and free.
|
|
*
|
|
* To achive this I try an approach described here as "Quick Fit".
|
|
* http://www.flounder.com/memory_allocation.htm
|
|
*
|
|
* The basic idea is to keep allocated memory segments and don't free
|
|
* them again. Instead I will put them in a tree indexed by their size.
|
|
* To get new memory I first have a look in the tree if there is
|
|
* a fitting memory segment. Fitting mean, larger or exactly the size
|
|
* I need. If there is one, use it. If not create a new one using
|
|
* usual malloc approach.
|
|
* I won't split the reagions at all because most likely they will be
|
|
* free soon again. This way I might waste some memory, so I have to
|
|
* keep an eye on this.
|
|
*
|
|
* Right now I don't build an upper limit for allocation. The limit
|
|
* still is the system memory itself.
|
|
*
|
|
* This is not implemented as a class because it will be used in the
|
|
* process of object creation.
|
|
*
|
|
* The data structure is a balanced tree with size as key.
|
|
* Under the size key is a list of elements of the same size.
|
|
*
|
|
* \author Georg Hopp
|
|
*
|
|
* \copyright
|
|
* Copyright © 2012 Georg Hopp
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <search.h>
|
|
#include <unistd.h>
|
|
|
|
#include "utils/memory.h"
|
|
#include "tree.h"
|
|
|
|
|
|
struct memSegment
|
|
{
|
|
size_t size;
|
|
void * ptr;
|
|
|
|
enum rbColor color;
|
|
|
|
struct memSegment * next;
|
|
struct memSegment * last;
|
|
|
|
struct memSegment * parent;
|
|
struct memSegment * left;
|
|
struct memSegment * right;
|
|
};
|
|
|
|
struct memSegment *
|
|
newElement(size_t size)
|
|
{
|
|
long psize = sysconf(_SC_PAGESIZE);
|
|
|
|
/* allocate only blocks of a multiple of pagesize, similar to cbuf */
|
|
size = (0 >= size)? 1 : (0 != size%psize)? (size/psize)+1 : size/psize;
|
|
size *= psize;
|
|
|
|
struct memSegment * element = malloc(size + sizeof(struct memSegment));
|
|
|
|
element->size = size;
|
|
element->ptr = (void*)element + sizeof(struct memSegment);
|
|
|
|
element->next = NULL;
|
|
element->last = NULL;
|
|
|
|
element->color = rbRed;
|
|
element->parent = NULL;
|
|
element->left = NULL;
|
|
element->right = NULL;
|
|
|
|
return element;
|
|
}
|
|
|
|
/**
|
|
* find element in tree
|
|
*/
|
|
struct memSegment *
|
|
findElement(struct memSegment * tree, size_t size)
|
|
{
|
|
struct memSegment * fitting = NULL;
|
|
|
|
while (NULL != tree) {
|
|
if (tree->size == size) {
|
|
fitting = tree;
|
|
break;
|
|
}
|
|
|
|
if (size > tree->size) {
|
|
tree = tree->right;
|
|
} else {
|
|
fitting = tree;
|
|
tree = tree->left;
|
|
}
|
|
}
|
|
|
|
return fitting;
|
|
}
|
|
|
|
/*
|
|
* function to get specific elements needed for
|
|
* rb handling, grandparent, uncle and sibbling
|
|
*/
|
|
struct memSegment *
|
|
grandparent(struct memSegment * node)
|
|
{
|
|
if (NULL != node && NULL != node->parent) {
|
|
return node->parent->parent;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
struct memSegment *
|
|
uncle(struct memSegment * node)
|
|
{
|
|
struct memSegment * gp = grandparent(node);
|
|
|
|
if (NULL == gp) {
|
|
return NULL;
|
|
}
|
|
|
|
if (node->parent == gp->left) {
|
|
return gp->right;
|
|
}
|
|
|
|
return gp->left;
|
|
}
|
|
|
|
struct memSegment *
|
|
sibling(struct memSegment * node)
|
|
{
|
|
if (NULL == node) {
|
|
return NULL;
|
|
}
|
|
|
|
if (NULL == node->parent->left || node == node->parent->left) {
|
|
return node->parent->right;
|
|
} else {
|
|
return node->parent->left;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* tree modifications...needed for rb handling.
|
|
*/
|
|
void
|
|
rotateLeft(struct memSegment ** tree, struct memSegment * node)
|
|
{
|
|
struct memSegment * rightChild = node->right;
|
|
struct memSegment * rcLeftSub = node->right->left;
|
|
|
|
rightChild->left = node;
|
|
rightChild->parent = node->parent;
|
|
node->right = rcLeftSub;
|
|
if (NULL != rcLeftSub) {
|
|
rcLeftSub->parent = node;
|
|
}
|
|
|
|
if (node->parent) {
|
|
if (node->parent->left == node) {
|
|
node->parent->left = rightChild;
|
|
} else {
|
|
node->parent->right = rightChild;
|
|
}
|
|
} else {
|
|
*tree = rightChild;
|
|
}
|
|
|
|
node->parent = rightChild;
|
|
}
|
|
|
|
void
|
|
rotateRight(struct memSegment ** tree, struct memSegment * node)
|
|
{
|
|
struct memSegment * leftChild = node->left;
|
|
struct memSegment * lcRightSub = node->left->right;
|
|
|
|
leftChild->right = node;
|
|
leftChild->parent = node->parent;
|
|
node->left = lcRightSub;
|
|
if (NULL != lcRightSub) {
|
|
lcRightSub->parent = node;
|
|
}
|
|
|
|
if (node->parent) {
|
|
if (node->parent->left == node) {
|
|
node->parent->left = leftChild;
|
|
} else {
|
|
node->parent->right = leftChild;
|
|
}
|
|
} else {
|
|
*tree = leftChild;
|
|
}
|
|
|
|
node->parent = leftChild;
|
|
}
|
|
|
|
void
|
|
replaceNode(
|
|
struct memSegment ** tree,
|
|
struct memSegment * node1,
|
|
struct memSegment * node2)
|
|
{
|
|
if (NULL != node1->parent) {
|
|
if (node1 == node1->parent->left) {
|
|
node1->parent->left = node2;
|
|
} else {
|
|
node1->parent->right = node2;
|
|
}
|
|
} else {
|
|
*tree = node2;
|
|
}
|
|
|
|
if (NULL != node2) {
|
|
node2->parent = node1->parent;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* insert element in tree
|
|
*/
|
|
struct memSegment *
|
|
insertElement(struct memSegment ** tree, struct memSegment * element)
|
|
{
|
|
struct memSegment * node = *tree;
|
|
struct memSegment * new_node = NULL;
|
|
struct memSegment * u;
|
|
struct memSegment * g;
|
|
|
|
element->next = NULL;
|
|
element->last = NULL;
|
|
|
|
element->color = rbRed;
|
|
element->parent = NULL;
|
|
element->left = NULL;
|
|
element->right = NULL;
|
|
|
|
// if tree is empty it's simple... :)
|
|
if (NULL == node) {
|
|
*tree = node = new_node = element;
|
|
} else {
|
|
// normal binary tree add....
|
|
while (NULL != node) {
|
|
if (element->size < node->size) {
|
|
if (NULL == node->left) {
|
|
node->left = element;
|
|
node->left->parent = node;
|
|
new_node = node = node->left;
|
|
break;
|
|
} else {
|
|
node = node->left;
|
|
}
|
|
} else if (element->size > node->size) {
|
|
if (NULL == node->right) {
|
|
node->right = element;
|
|
node->right->parent = node;
|
|
new_node = node = node->right;
|
|
break;
|
|
} else {
|
|
node = node->right;
|
|
}
|
|
} else {
|
|
if (NULL == node->next) {
|
|
node->next = element;
|
|
node->last = element;
|
|
} else {
|
|
node->last->next = element;
|
|
node->last = element;
|
|
}
|
|
return node;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (NULL != new_node) {
|
|
/*
|
|
* handle reballancing rb style
|
|
*/
|
|
while (1) {
|
|
// case 1
|
|
if (node->parent == NULL) {
|
|
node->color = rbBlack;
|
|
// we're done.... :)
|
|
break;
|
|
}
|
|
|
|
// case 2
|
|
if (node->parent->color == rbBlack) {
|
|
// Tree is still valid ... wow, again we're done... :)
|
|
break;
|
|
}
|
|
|
|
// case 3
|
|
u = uncle(node);
|
|
g = grandparent(node);
|
|
|
|
if (u != NULL && u->color == rbRed) {
|
|
node->parent->color = rbBlack;
|
|
u->color = rbBlack;
|
|
g->color = rbRed;
|
|
|
|
node = g;
|
|
continue;
|
|
}
|
|
|
|
// case 4
|
|
if (node == node->parent->right && node->parent == g->left) {
|
|
rotateLeft(tree, node->parent);
|
|
node = node->left;
|
|
} else if (node == node->parent->left && node->parent == g->right) {
|
|
|
|
rotateRight(tree, node->parent);
|
|
node = node->right;
|
|
}
|
|
|
|
// case 5
|
|
g = grandparent(node);
|
|
|
|
node->parent->color = rbBlack;
|
|
g->color = rbRed;
|
|
|
|
if (node == node->parent->left) {
|
|
rotateRight(tree, g);
|
|
} else {
|
|
rotateLeft(tree, g);
|
|
}
|
|
|
|
// we're done..
|
|
break;
|
|
}
|
|
}
|
|
|
|
return new_node;
|
|
}
|
|
|
|
/**
|
|
* delete element from tree
|
|
* here multiple functions are involved....
|
|
* =======================================================================
|
|
*/
|
|
/**
|
|
* find minimum of the right subtree aka leftmost leaf of right subtree
|
|
* aka left in-order successor.
|
|
* We return the parent of the element in the out argument parent.
|
|
* This can be NULL wenn calling.
|
|
*
|
|
* 2: *successor = {size = 80, ptr = 0x603ae0, color = rbRed, parent = 0x603160,
|
|
* left = 0x0, right = 0x0}
|
|
* 1: *node = {size = 70, ptr = 0x603a60, color = rbBlack, parent = 0x603070,
|
|
* left = 0x6030e0, right = 0x6031e0}
|
|
*
|
|
*/
|
|
struct memSegment *
|
|
findInOrderSuccessor(struct memSegment * tree)
|
|
{
|
|
struct memSegment * node = tree->right;
|
|
|
|
while (NULL != node->left) {
|
|
node = node->left;
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
struct memSegment *
|
|
deleteElement(struct memSegment ** tree, struct memSegment * element)
|
|
{
|
|
struct memSegment * node = *tree;
|
|
struct memSegment * del_node;
|
|
struct memSegment * child;
|
|
struct memSegment * s;
|
|
|
|
// find the relevant node and it's parent
|
|
while (NULL != node) {
|
|
|
|
if (element->size < node->size) {
|
|
node = node->left;
|
|
} else if (element->size > node->size) {
|
|
node = node->right;
|
|
} else {
|
|
if (NULL != node->next) {
|
|
if (NULL != node->parent) {
|
|
if (node == node->parent->left) {
|
|
node->parent->left = node->next;
|
|
} else {
|
|
node->parent->right = node->next;
|
|
}
|
|
} else {
|
|
*tree = node->next;
|
|
}
|
|
|
|
if (NULL != node->left) {
|
|
node->left->parent = node->next;
|
|
}
|
|
|
|
if (NULL != node->right) {
|
|
node->right->parent = node->next;
|
|
}
|
|
|
|
node->next->last = node->last;
|
|
node->next->color = node->color;
|
|
node->next->parent = node->parent;
|
|
node->next->left = node->left;
|
|
node->next->right = node->right;
|
|
|
|
return node;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// element not found
|
|
if (NULL == node) {
|
|
return node;
|
|
}
|
|
|
|
del_node = node;
|
|
|
|
// now our cases follows...the first one is the same as with
|
|
// simple binary search trees. Two non null children.
|
|
|
|
// case 1: two children
|
|
if (NULL != node->left && NULL != node->right) {
|
|
struct memSegment * successor = findInOrderSuccessor(node);
|
|
|
|
enum rbColor tmpcolor = successor->color;
|
|
struct memSegment * tmpparent = successor->parent;
|
|
struct memSegment * tmpleft = successor->left;
|
|
struct memSegment * tmpright = successor->right;
|
|
|
|
replaceNode(tree, node, successor);
|
|
|
|
successor->color = node->color;
|
|
successor->left = node->left;
|
|
successor->left->parent = successor;
|
|
// the right one might be successor...
|
|
if (node->right == successor) {
|
|
successor->right = node;
|
|
node->parent = successor;
|
|
} else {
|
|
successor->right = node->right;
|
|
node->right->parent = successor;
|
|
node->parent = tmpparent;
|
|
tmpparent->left = node;
|
|
}
|
|
|
|
node->color = tmpcolor;
|
|
node->left = tmpleft;
|
|
node->right = tmpright;
|
|
}
|
|
|
|
// Precondition: n has at most one non-null child.
|
|
child = (NULL == node->right) ? node->left : node->right;
|
|
replaceNode(tree, node, child);
|
|
|
|
// delete one child case
|
|
// TODO this is overly complex as simply derived from the function...
|
|
// maybe this can be simplified. Maybe not...check.
|
|
if (node->color == rbBlack) {
|
|
if (NULL != child && child->color == rbRed) {
|
|
child->color = rbBlack;
|
|
// done despite modifying tree itself if neccessary..
|
|
return del_node;
|
|
} else {
|
|
if (NULL != child) {
|
|
node = child;
|
|
} else {
|
|
node->color = rbBlack;
|
|
node->left = NULL;
|
|
node->right = NULL;
|
|
}
|
|
}
|
|
} else {
|
|
return del_node;
|
|
}
|
|
|
|
// delete and rb rebalance...
|
|
while(1) {
|
|
// case 1
|
|
if (NULL == node->parent) {
|
|
// done again
|
|
break;
|
|
}
|
|
|
|
// case 2
|
|
s = sibling(node);
|
|
|
|
if (NULL != s && s->color == rbRed) {
|
|
node->parent->color = rbRed;
|
|
s->color = rbBlack;
|
|
|
|
/*
|
|
* detect which child we are...assumption
|
|
* if we are not parent->right and parent->right is not
|
|
* null we must be left, even if its set to NULL previously
|
|
*/
|
|
if (NULL != node->parent->right && node != node->parent->right) {
|
|
rotateLeft(tree, node->parent);
|
|
} else {
|
|
rotateRight(tree, node->parent);
|
|
}
|
|
}
|
|
|
|
s = sibling(node);
|
|
// case 3 / 4
|
|
if (NULL == s || ((s->color == rbBlack) &&
|
|
(NULL == s->left || s->left->color == rbBlack) &&
|
|
(NULL == s->right || s->right->color == rbBlack))) {
|
|
|
|
if (NULL != s) {
|
|
s->color = rbRed;
|
|
}
|
|
|
|
if (node->parent->color == rbBlack) {
|
|
// case 3
|
|
node = node->parent;
|
|
continue;
|
|
} else {
|
|
// case 4
|
|
node->parent->color = rbBlack;
|
|
// and done again...
|
|
break;
|
|
}
|
|
}
|
|
|
|
// case 5
|
|
if (NULL != s && s->color == rbBlack) {
|
|
// this if statement is trivial,
|
|
// due to case 2 (even though case 2 changed the sibling to a
|
|
// sibling's child,
|
|
// the sibling's child can't be red, since no red parent can
|
|
// have a red child).
|
|
//
|
|
// the following statements just force the red to be on the
|
|
// left of the left of the parent,
|
|
// or right of the right, so case 6 will rotate correctly.
|
|
if ((node == node->parent->left) &&
|
|
(NULL == s->right || s->right->color == rbBlack) &&
|
|
(NULL != s->left && s->left->color == rbRed)) {
|
|
|
|
// this last test is trivial too due to cases 2-4.
|
|
s->color = rbRed;
|
|
s->left->color = rbBlack;
|
|
|
|
rotateRight(tree, s);
|
|
} else if ((node == node->parent->right) &&
|
|
(NULL == s->left || s->left->color == rbBlack) &&
|
|
(NULL != s->right && s->right->color == rbRed)) {
|
|
// this last test is trivial too due to cases 2-4.
|
|
s->color = rbRed;
|
|
s->right->color = rbBlack;
|
|
|
|
rotateLeft(tree, s);
|
|
}
|
|
}
|
|
|
|
s = sibling(node);
|
|
// case 6
|
|
if (NULL != s) {
|
|
s->color = node->parent->color;
|
|
}
|
|
|
|
if (NULL != node && NULL != node->parent) {
|
|
node->parent->color = rbBlack;
|
|
|
|
/*
|
|
* detect which child we are...assumption
|
|
* if we are not parent->right and parent->right is not
|
|
* null we must be left, even if its set to NULL previously
|
|
*/
|
|
if (NULL != node->parent->right && node != node->parent->right) {
|
|
if (NULL != s->right) {
|
|
s->right->color = rbBlack;
|
|
}
|
|
rotateLeft(tree, node->parent);
|
|
} else {
|
|
if (NULL != s->left) {
|
|
s->left->color = rbBlack;
|
|
}
|
|
rotateRight(tree, node->parent);
|
|
}
|
|
}
|
|
|
|
// done...
|
|
break;
|
|
}
|
|
|
|
return del_node;
|
|
}
|
|
|
|
|
|
void
|
|
traverse(struct memSegment * tree, void (*cb)(struct memSegment *, int))
|
|
{
|
|
struct memSegment * previous = tree;
|
|
struct memSegment * node = tree;
|
|
int depth = 1;
|
|
|
|
/*
|
|
* I think this has something like O(n+log(n)) on a ballanced
|
|
* tree because I have to traverse back the rightmost leaf to
|
|
* the root to get a break condition.
|
|
*/
|
|
while (node) {
|
|
/*
|
|
* If we come from the right so nothing and go to our
|
|
* next parent.
|
|
*/
|
|
if (previous == node->right) {
|
|
previous = node;
|
|
node = node->parent;
|
|
depth--;
|
|
continue;
|
|
}
|
|
|
|
if ((NULL == node->left || previous == node->left)) {
|
|
/*
|
|
* If there are no more elements to the left or we
|
|
* came from the left, process data.
|
|
*/
|
|
cb(node, depth);
|
|
previous = node;
|
|
|
|
if (NULL != node->right) {
|
|
node = node->right;
|
|
depth++;
|
|
} else {
|
|
node = node->parent;
|
|
depth--;
|
|
}
|
|
} else {
|
|
/*
|
|
* if there are more elements to the left go there.
|
|
*/
|
|
previous = node;
|
|
node = node->left;
|
|
depth++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
post(struct memSegment * tree, void (*cb)(struct memSegment *, int))
|
|
{
|
|
struct memSegment * previous = tree;
|
|
struct memSegment * node = tree;
|
|
int depth = 1;
|
|
|
|
/*
|
|
* I think this has something like O(n+log(n)) on a ballanced
|
|
* tree because I have to traverse back the rightmost leaf to
|
|
* the root to get a break condition.
|
|
*/
|
|
while (node) {
|
|
/*
|
|
* If we come from the right so nothing and go to our
|
|
* next parent.
|
|
*/
|
|
if ((NULL == node->left && NULL == node->right)
|
|
|| previous == node->right) {
|
|
|
|
struct memSegment * parent = node->parent;
|
|
|
|
cb(node, depth);
|
|
|
|
previous = node;
|
|
node = parent;
|
|
depth--;
|
|
continue;
|
|
}
|
|
|
|
if ((NULL == node->left || previous == node->left)) {
|
|
/*
|
|
* If there are no more elements to the left or we
|
|
* came from the left, process data.
|
|
*/
|
|
previous = node;
|
|
|
|
if (NULL != node->right) {
|
|
node = node->right;
|
|
depth++;
|
|
} else {
|
|
node = node->parent;
|
|
depth--;
|
|
}
|
|
} else {
|
|
/*
|
|
* if there are more elements to the left go there.
|
|
*/
|
|
previous = node;
|
|
node = node->left;
|
|
depth++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void printElement(struct memSegment * node, int depth)
|
|
{
|
|
int i;
|
|
|
|
printf("%s %010zu:%p(%02d)",
|
|
(node->color==rbRed)?"R":"B",
|
|
node->size,
|
|
node->ptr,
|
|
depth);
|
|
for (i=0; i<depth; i++) printf("-");
|
|
puts("");
|
|
|
|
node = node->next;
|
|
while (NULL != node) {
|
|
printf(" %s %010zu:%p(%02d)",
|
|
(node->color==rbRed)?"R":"B",
|
|
node->size,
|
|
node->ptr,
|
|
depth);
|
|
for (i=0; i<depth; i++) printf("-");
|
|
puts("");
|
|
node = node->next;
|
|
}
|
|
}
|
|
|
|
void
|
|
cleanup(struct memSegment * node, int depth)
|
|
{
|
|
while (NULL != node) {
|
|
struct memSegment * next = node->next;
|
|
free(node);
|
|
node = next;
|
|
}
|
|
}
|
|
|
|
struct memSegment * segments = NULL;
|
|
|
|
// /**
|
|
// * this will interpret any memory segment that is not smaller
|
|
// * than the expected size as fitting.
|
|
// *
|
|
// * @param void * size_ptr a pointer to a size_t value searched for
|
|
// * @param void * subject a pointer to the currently analysed tree element
|
|
// */
|
|
// static
|
|
// int
|
|
// segmentFindCmp(const void * size_ptr, const void * subject)
|
|
// {
|
|
// if (*(size_t *)size_ptr > ((struct memSegment *)subject)->size)
|
|
// return 1;
|
|
//
|
|
// return 0;
|
|
// }
|
|
//
|
|
// /**
|
|
// * this returns exact fits....uhh.....I can't relate solely on
|
|
// * the size argument as then same sized segments will never
|
|
// * be stored.
|
|
// * Maybe a tree is not the best data structure to use to store
|
|
// * these.
|
|
// * Anyway, right now take the ptr into account if size if equal.
|
|
// */
|
|
// static
|
|
// int
|
|
// segmentSearchCmp(const void * search, const void * subject)
|
|
// {
|
|
// size_t idx =
|
|
// ((struct memSegment *)search)->size -
|
|
// ((struct memSegment *)subject)->size;
|
|
//
|
|
// if (0 == idx) {
|
|
// return
|
|
// ((struct memSegment *)search)->ptr -
|
|
// ((struct memSegment *)subject)->ptr;
|
|
// }
|
|
//
|
|
// return idx;
|
|
// }
|
|
|
|
static
|
|
void
|
|
segmentFree(struct memSegment * segment, int depth)
|
|
{
|
|
while (NULL != segment) {
|
|
struct memSegment * next = segment->next;
|
|
free(segment);
|
|
segment = next;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* This will always allocate a multiple of PAGESIZE
|
|
*/
|
|
void *
|
|
memMalloc(size_t size)
|
|
{
|
|
struct memSegment * seg;
|
|
long psize = sysconf(_SC_PAGESIZE);
|
|
|
|
size = (0 >= size)? 1 : (0 != size%psize)? (size/psize)+1 : size/psize;
|
|
size *= psize;
|
|
|
|
seg = findElement(segments, size);
|
|
|
|
if (NULL == seg) {
|
|
seg = newElement(size);
|
|
} else {
|
|
// remove the found one from the tree as we use it now.
|
|
seg = deleteElement(&segments, seg);
|
|
}
|
|
|
|
|
|
return seg->ptr;
|
|
}
|
|
|
|
/**
|
|
* this is a really memory wasting solution....just to be able to
|
|
* use calloc, which might be faster then malloc/memset solution.
|
|
*
|
|
* Maybe this is a bad idea, as we need to memset the buffer anyway
|
|
* if it comes from our tree, which hopefully should be the majority
|
|
* of cases.
|
|
*/
|
|
void *
|
|
memCalloc(size_t nmemb, size_t size)
|
|
{
|
|
size_t _size = nmemb * size;
|
|
void * mem = memMalloc(_size);
|
|
|
|
memset(mem, 0, _size);
|
|
|
|
return mem;
|
|
}
|
|
|
|
void
|
|
memFree(void ** mem)
|
|
{
|
|
if (NULL != *mem) {
|
|
insertElement(&segments, (struct memSegment *)(*mem - sizeof(struct memSegment)));
|
|
|
|
*mem = NULL;
|
|
}
|
|
}
|
|
|
|
size_t
|
|
memGetSize(void * mem)
|
|
{
|
|
struct memSegment * segment;
|
|
|
|
if (NULL == mem) {
|
|
return 0;
|
|
}
|
|
|
|
segment = (struct memSegment *)(mem - sizeof(struct memSegment));
|
|
return segment->size;
|
|
}
|
|
|
|
void
|
|
memCleanup()
|
|
{
|
|
post(segments, segmentFree);
|
|
}
|
|
|
|
void
|
|
ffree(void ** data)
|
|
{
|
|
if (NULL != *data) {
|
|
free(*data);
|
|
*data = NULL;
|
|
}
|
|
}
|
|
|
|
// vim: set ts=4 sw=4:
|