root/src/system/libroot/posix/malloc/hoard2/threadheap.cpp
///-*-C++-*-//////////////////////////////////////////////////////////////////
//
// Hoard: A Fast, Scalable, and Memory-Efficient Allocator
//        for Shared-Memory Multiprocessors
// Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery
//
// Copyright (c) 1998-2000, The University of Texas at Austin.
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Library General Public License as
// published by the Free Software Foundation, http://www.fsf.org.
//
// This library 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
// Library General Public License for more details.
//
//////////////////////////////////////////////////////////////////////////////

//#include <limits.h>
#include <string.h>

#include "config.h"

#include "heap.h"
#include "threadheap.h"
#include "processheap.h"

using namespace BPrivate;


threadHeap::threadHeap(void)
        :_pHeap(0)
{
}


// malloc (sz):
//   inputs: the size of the object to be allocated.
//   returns: a pointer to an object of the appropriate size.
//   side effects: allocates a block from a superblock;
//                 may call sbrk() (via makeSuperblock).

void *
threadHeap::malloc(const size_t size)
{
#if MAX_INTERNAL_FRAGMENTATION == 2
        if (size > 1063315264UL) {
                debug_printf("malloc() of %lu bytes asked\n", size);
                return NULL;
        }
#endif

        const int sizeclass = sizeClass(size);
        block *b = NULL;

        lock();

        // Look for a free block.
        // We usually have memory locally so we first look for space in the
        // superblock list.

        superblock *sb = findAvailableSuperblock(sizeclass, b, _pHeap);
        if (sb == NULL) {
                // We don't have memory locally.
                // Try to get more from the process heap.

                assert(_pHeap);
                sb = _pHeap->acquire((int)sizeclass, this);

                // If we didn't get any memory from the process heap,
                // we'll have to allocate our own superblock.
                if (sb == NULL) {
                        sb = superblock::makeSuperblock(sizeclass, _pHeap);
                        if (sb == NULL) {
                                // We're out of memory!
                                unlock();
                                return NULL;
                        }
#if HEAP_LOG
                        // Record the memory allocation.
                        MemoryRequest m;
                        m.allocate((int)sb->getNumBlocks() *
                                (int)sizeFromClass(sb->getBlockSizeClass()));
                        _pHeap->getLog(getIndex()).append(m);
#endif
#if HEAP_FRAG_STATS
                        _pHeap->setAllocated(0,
                                sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
#endif
                }
                // Get a block from the superblock.
                b = sb->getBlock();
                assert(b != NULL);

                // Insert the superblock into our list.
                insertSuperblock(sizeclass, sb, _pHeap);
        }

        assert(b != NULL);
        assert(b->isValid());
        assert(sb->isValid());

        b->markAllocated();

#if HEAP_LOG
        MemoryRequest m;
        m.malloc((void *)(b + 1), align(size));
        _pHeap->getLog(getIndex()).append(m);
#endif
#if HEAP_FRAG_STATS
        b->setRequestedSize(align(size));
        _pHeap->setAllocated(align(size), 0);
#endif

        unlock();

        // Skip past the block header and return the pointer.
        return (void *)(b + 1);
}