Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0dd0d294 authored by Mathias Agopian's avatar Mathias Agopian
Browse files

Simplify the MemoryDealer implementation

At some point the implementation became complicated because of
SurfaceFlinger's special needs, since we are now relying on gralloc
we can go back to much simpler MemoryDealer.

Removed HeapInterface and AllocatorInterface, since those don't need
to be paramterized anymore. Merged SimpleMemory and Allocation.
Made SimplisticAllocator non virtual.

Removed MemoryDealer flags (READ_ONLY, PAGE_ALIGNED)

Removed a lot of unneeded code.
parent 10e6d20f
Loading
Loading
Loading
Loading
+9 −206
Original line number Diff line number Diff line
@@ -22,232 +22,35 @@
#include <sys/types.h>

#include <binder/IMemory.h>
#include <utils/threads.h>
#include <binder/MemoryHeapBase.h>

namespace android {
// ----------------------------------------------------------------------------
class String8;

/*
 * interface for implementing a "heap". A heap basically provides
 * the IMemoryHeap interface for cross-process sharing and the
 * ability to map/unmap pages within the heap.
 */
class HeapInterface : public virtual BnMemoryHeap
{
public:
    // all values must be page-aligned
    virtual sp<IMemory> mapMemory(size_t offset, size_t size) = 0;

    HeapInterface();
protected:
    virtual ~HeapInterface();
};

// ----------------------------------------------------------------------------

/*
 * interface for implementing an allocator. An allocator provides
 * methods for allocating and freeing memory blocks and dumping
 * its state.
 */
class AllocatorInterface : public RefBase
{
public:
    enum {
        PAGE_ALIGNED = 0x00000001
    };

    virtual size_t      allocate(size_t size, uint32_t flags = 0) = 0;
    virtual status_t    deallocate(size_t offset) = 0;
    virtual size_t      size() const = 0;
    virtual void        dump(const char* what, uint32_t flags = 0) const = 0;
    virtual void        dump(String8& res,
            const char* what, uint32_t flags = 0) const = 0;

    AllocatorInterface();
protected:
    virtual ~AllocatorInterface();
};

// ----------------------------------------------------------------------------

/*
 * concrete implementation of HeapInterface on top of mmap() 
 */
class SharedHeap : public HeapInterface, public MemoryHeapBase
{
public:
                        SharedHeap();
                        SharedHeap(size_t size, uint32_t flags = 0, char const * name = NULL);
    virtual             ~SharedHeap();
    virtual sp<IMemory> mapMemory(size_t offset, size_t size);
};

// ----------------------------------------------------------------------------

/*
 * A simple templatized doubly linked-list implementation
 */

template <typename NODE>
class LinkedList
{
    NODE*  mFirst;
    NODE*  mLast;

public:
                LinkedList() : mFirst(0), mLast(0) { }
    bool        isEmpty() const { return mFirst == 0; }
    NODE const* head() const { return mFirst; }
    NODE*       head() { return mFirst; }
    NODE const* tail() const { return mLast; }
    NODE*       tail() { return mLast; }

    void insertAfter(NODE* node, NODE* newNode) {
        newNode->prev = node;
        newNode->next = node->next;
        if (node->next == 0) mLast = newNode;
        else                 node->next->prev = newNode;
        node->next = newNode;
    }

    void insertBefore(NODE* node, NODE* newNode) {
         newNode->prev = node->prev;
         newNode->next = node;
         if (node->prev == 0)   mFirst = newNode;
         else                   node->prev->next = newNode;
         node->prev = newNode;
    }

    void insertHead(NODE* newNode) {
        if (mFirst == 0) {
            mFirst = mLast = newNode;
            newNode->prev = newNode->next = 0;
        } else {
            newNode->prev = 0;
            newNode->next = mFirst;
            mFirst->prev = newNode;
            mFirst = newNode;
        }
    }
    
    void insertTail(NODE* newNode) {
        if (mLast == 0) {
            insertHead(newNode);
        } else {
            newNode->prev = mLast;
            newNode->next = 0;
            mLast->next = newNode;
            mLast = newNode;
        }
    }

    NODE* remove(NODE* node) {
        if (node->prev == 0)    mFirst = node->next;
        else                    node->prev->next = node->next;
        if (node->next == 0)    mLast = node->prev;
        else                    node->next->prev = node->prev;
        return node;
    }
};


/*
 * concrete implementation of AllocatorInterface using a simple
 * best-fit allocation scheme
 */
class SimpleBestFitAllocator : public AllocatorInterface
{
public:

                        SimpleBestFitAllocator(size_t size);
    virtual             ~SimpleBestFitAllocator();

    virtual size_t      allocate(size_t size, uint32_t flags = 0);
    virtual status_t    deallocate(size_t offset);
    virtual size_t      size() const;
    virtual void        dump(const char* what, uint32_t flags = 0) const;
    virtual void        dump(String8& res,
            const char* what, uint32_t flags = 0) const;

private:

    struct chunk_t {
        chunk_t(size_t start, size_t size) 
            : start(start), size(size), free(1), prev(0), next(0) {
        }
        size_t              start;
        size_t              size : 28;
        int                 free : 4;
        mutable chunk_t*    prev;
        mutable chunk_t*    next;
    };

    ssize_t  alloc(size_t size, uint32_t flags);
    chunk_t* dealloc(size_t start);
    void     dump_l(const char* what, uint32_t flags = 0) const;
    void     dump_l(String8& res, const char* what, uint32_t flags = 0) const;

    static const int    kMemoryAlign;
    mutable Mutex       mLock;
    LinkedList<chunk_t> mList;
    size_t              mHeapSize;
};
class SimpleBestFitAllocator;

// ----------------------------------------------------------------------------

class MemoryDealer : public RefBase
{
public:
    MemoryDealer(size_t size, const char* name = 0);

    enum {
        READ_ONLY = MemoryHeapBase::READ_ONLY,
        PAGE_ALIGNED = AllocatorInterface::PAGE_ALIGNED
    };

    // creates a memory dealer with the SharedHeap and SimpleBestFitAllocator
    MemoryDealer(size_t size, uint32_t flags = 0, const char* name = 0);

    // provide a custom heap but use the SimpleBestFitAllocator
    MemoryDealer(const sp<HeapInterface>& heap);

    // provide both custom heap and allocotar
    MemoryDealer(
            const sp<HeapInterface>& heap,
            const sp<AllocatorInterface>& allocator);

    virtual sp<IMemory> allocate(size_t size, uint32_t flags = 0);
    virtual sp<IMemory> allocate(size_t size);
    virtual void        deallocate(size_t offset);
    virtual void        dump(const char* what, uint32_t flags = 0) const;

    virtual void        dump(const char* what) const;

    sp<IMemoryHeap> getMemoryHeap() const { return heap(); }
    sp<AllocatorInterface> getAllocator() const { return allocator(); }

protected:
    virtual ~MemoryDealer();

private:
    const sp<HeapInterface>&        heap() const;
    const sp<AllocatorInterface>&   allocator() const;

    class Allocation : public BnMemory {
    public:
        Allocation(const sp<MemoryDealer>& dealer,
                ssize_t offset, size_t size, const sp<IMemory>& memory);
        virtual ~Allocation();
        virtual sp<IMemoryHeap> getMemory(ssize_t* offset, size_t* size) const;
    private:
        sp<MemoryDealer>        mDealer;
        ssize_t                 mOffset;
        size_t                  mSize;
        sp<IMemory>             mMemory;
    };
    const sp<IMemoryHeap>&      heap() const;
    SimpleBestFitAllocator*     allocator() const;

    sp<HeapInterface>           mHeap;
    sp<AllocatorInterface>      mAllocator;
    sp<IMemoryHeap>             mHeap;
    SimpleBestFitAllocator*     mAllocator;
};


+2 −2
Original line number Diff line number Diff line
@@ -20,10 +20,10 @@
#include <stdlib.h>
#include <stdint.h>

#include <binder/MemoryDealer.h>
#include <binder/MemoryHeapBase.h>
#include <binder/IMemory.h>
#include <utils/SortedVector.h>
#include <utils/threads.h>

namespace android {

@@ -31,7 +31,7 @@ class MemoryHeapBase;

// ---------------------------------------------------------------------------

class MemoryHeapPmem : public HeapInterface, public MemoryHeapBase
class MemoryHeapPmem : public MemoryHeapBase
{
public:
    class MemoryPmem : public BnMemory {
+1 −1
Original line number Diff line number Diff line
@@ -2929,7 +2929,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue()
AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
    :   RefBase(),
        mAudioFlinger(audioFlinger),
        mMemoryDealer(new MemoryDealer(1024*1024)),
        mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")),
        mPid(pid)
{
    // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
+179 −136
Original line number Diff line number Diff line
@@ -17,12 +17,13 @@
#define LOG_TAG "MemoryDealer"

#include <binder/MemoryDealer.h>
#include <binder/IPCThreadState.h>
#include <binder/MemoryBase.h>

#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <utils/SortedVector.h>
#include <utils/String8.h>
#include <binder/MemoryBase.h>
#include <utils/threads.h>

#include <stdint.h>
#include <stdio.h>
@@ -40,90 +41,203 @@
namespace android {
// ----------------------------------------------------------------------------

HeapInterface::HeapInterface() { }
HeapInterface::~HeapInterface() { }
/*
 * A simple templatized doubly linked-list implementation
 */

template <typename NODE>
class LinkedList
{
    NODE*  mFirst;
    NODE*  mLast;

public:
                LinkedList() : mFirst(0), mLast(0) { }
    bool        isEmpty() const { return mFirst == 0; }
    NODE const* head() const { return mFirst; }
    NODE*       head() { return mFirst; }
    NODE const* tail() const { return mLast; }
    NODE*       tail() { return mLast; }

    void insertAfter(NODE* node, NODE* newNode) {
        newNode->prev = node;
        newNode->next = node->next;
        if (node->next == 0) mLast = newNode;
        else                 node->next->prev = newNode;
        node->next = newNode;
    }

    void insertBefore(NODE* node, NODE* newNode) {
         newNode->prev = node->prev;
         newNode->next = node;
         if (node->prev == 0)   mFirst = newNode;
         else                   node->prev->next = newNode;
         node->prev = newNode;
    }

    void insertHead(NODE* newNode) {
        if (mFirst == 0) {
            mFirst = mLast = newNode;
            newNode->prev = newNode->next = 0;
        } else {
            newNode->prev = 0;
            newNode->next = mFirst;
            mFirst->prev = newNode;
            mFirst = newNode;
        }
    }

    void insertTail(NODE* newNode) {
        if (mLast == 0) {
            insertHead(newNode);
        } else {
            newNode->prev = mLast;
            newNode->next = 0;
            mLast->next = newNode;
            mLast = newNode;
        }
    }

    NODE* remove(NODE* node) {
        if (node->prev == 0)    mFirst = node->next;
        else                    node->prev->next = node->next;
        if (node->next == 0)    mLast = node->prev;
        else                    node->next->prev = node->prev;
        return node;
    }
};

// ----------------------------------------------------------------------------

AllocatorInterface::AllocatorInterface() { }
AllocatorInterface::~AllocatorInterface() { }
class Allocation : public MemoryBase {
public:
    Allocation(const sp<MemoryDealer>& dealer,
            const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
    virtual ~Allocation();
private:
    sp<MemoryDealer> mDealer;
};

// ----------------------------------------------------------------------------

class SimpleMemory : public MemoryBase {
class SimpleBestFitAllocator
{
    enum {
        PAGE_ALIGNED = 0x00000001
    };
public:
    SimpleMemory(const sp<IMemoryHeap>& heap, ssize_t offset, size_t size);
    virtual ~SimpleMemory();
    SimpleBestFitAllocator(size_t size);
    ~SimpleBestFitAllocator();

    size_t      allocate(size_t size, uint32_t flags = 0);
    status_t    deallocate(size_t offset);
    size_t      size() const;
    void        dump(const char* what) const;
    void        dump(String8& res, const char* what) const;

private:

    struct chunk_t {
        chunk_t(size_t start, size_t size)
        : start(start), size(size), free(1), prev(0), next(0) {
        }
        size_t              start;
        size_t              size : 28;
        int                 free : 4;
        mutable chunk_t*    prev;
        mutable chunk_t*    next;
    };

    ssize_t  alloc(size_t size, uint32_t flags);
    chunk_t* dealloc(size_t start);
    void     dump_l(const char* what) const;
    void     dump_l(String8& res, const char* what) const;

    static const int    kMemoryAlign;
    mutable Mutex       mLock;
    LinkedList<chunk_t> mList;
    size_t              mHeapSize;
};

// ----------------------------------------------------------------------------

MemoryDealer::Allocation::Allocation(
        const sp<MemoryDealer>& dealer, ssize_t offset, size_t size,
        const sp<IMemory>& memory)
    : mDealer(dealer), mOffset(offset), mSize(size), mMemory(memory) 
Allocation::Allocation(
        const sp<MemoryDealer>& dealer,
        const sp<IMemoryHeap>& heap, ssize_t offset, size_t size)
    : MemoryBase(heap, offset, size), mDealer(dealer)
{
#ifndef NDEBUG
    void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
    memset(start_ptr, 0xda, size);
#endif
}

MemoryDealer::Allocation::~Allocation()
Allocation::~Allocation()
{
    if (mSize) {
    size_t freedOffset = getOffset();
    size_t freedSize   = getSize();
    if (freedSize) {
        /* NOTE: it's VERY important to not free allocations of size 0 because
         * they're special as they don't have any record in the allocator
         * and could alias some real allocation (their offset is zero). */
        mDealer->deallocate(mOffset);
        mDealer->deallocate(freedOffset);

        // keep the size to unmap in excess
        size_t pagesize = getpagesize();
        size_t start = freedOffset;
        size_t end = start + freedSize;
        start &= ~(pagesize-1);
        end = (end + pagesize-1) & ~(pagesize-1);

        // give back to the kernel the pages we don't need
        size_t free_start = freedOffset;
        size_t free_end = free_start + freedSize;
        if (start < free_start)
            start = free_start;
        if (end > free_end)
            end = free_end;
        start = (start + pagesize-1) & ~(pagesize-1);
        end &= ~(pagesize-1);

        if (start < end) {
            void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
            size_t size = end-start;

#ifndef NDEBUG
            memset(start_ptr, 0xdf, size);
#endif

            // MADV_REMOVE is not defined on Dapper based Goobuntu
#ifdef MADV_REMOVE
            if (size) {
                int err = madvise(start_ptr, size, MADV_REMOVE);
                LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
                        start_ptr, size, err<0 ? strerror(errno) : "Ok");
            }
#endif
        }
    }

sp<IMemoryHeap> MemoryDealer::Allocation::getMemory(
    ssize_t* offset, size_t* size) const
{
    return mMemory->getMemory(offset, size);
}

// ----------------------------------------------------------------------------

MemoryDealer::MemoryDealer(size_t size, uint32_t flags, const char* name)
    : mHeap(new SharedHeap(size, flags, name)),
MemoryDealer::MemoryDealer(size_t size, const char* name)
    : mHeap(new MemoryHeapBase(size, 0, name)),
    mAllocator(new SimpleBestFitAllocator(size))
{    
}

MemoryDealer::MemoryDealer(const sp<HeapInterface>& heap)
    : mHeap(heap),
    mAllocator(new SimpleBestFitAllocator(heap->virtualSize()))
{
}

MemoryDealer::MemoryDealer( const sp<HeapInterface>& heap,
        const sp<AllocatorInterface>& allocator)
    : mHeap(heap), mAllocator(allocator)
{
}

MemoryDealer::~MemoryDealer()
{
    delete mAllocator;
}

sp<IMemory> MemoryDealer::allocate(size_t size, uint32_t flags)
sp<IMemory> MemoryDealer::allocate(size_t size)
{
    sp<IMemory> memory;
    const ssize_t offset = allocator()->allocate(size, flags);
    const ssize_t offset = allocator()->allocate(size);
    if (offset >= 0) {
        sp<IMemory> new_memory = heap()->mapMemory(offset, size);
        if (new_memory != 0) {
            memory = new Allocation(this, offset, size, new_memory);
        } else {
            LOGE("couldn't map [%8lx, %u]", offset, size);
            if (size) {
                /* NOTE: it's VERY important to not free allocations of size 0
                 * because they're special as they don't have any record in the 
                 * allocator and could alias some real allocation 
                 * (their offset is zero). */
                allocator()->deallocate(offset);
            }
        }        
        memory = new Allocation(this, heap(), offset, size);
    }
    return memory;
}
@@ -133,16 +247,16 @@ void MemoryDealer::deallocate(size_t offset)
    allocator()->deallocate(offset);
}

void MemoryDealer::dump(const char* what, uint32_t flags) const
void MemoryDealer::dump(const char* what) const
{
    allocator()->dump(what, flags);
    allocator()->dump(what);
}

const sp<HeapInterface>& MemoryDealer::heap() const {
const sp<IMemoryHeap>& MemoryDealer::heap() const {
    return mHeap;
}

const sp<AllocatorInterface>& MemoryDealer::allocator() const {
SimpleBestFitAllocator* MemoryDealer::allocator() const {
    return mAllocator;
}

@@ -287,28 +401,28 @@ SimpleBestFitAllocator::chunk_t* SimpleBestFitAllocator::dealloc(size_t start)
    return 0;
}

void SimpleBestFitAllocator::dump(const char* what, uint32_t flags) const
void SimpleBestFitAllocator::dump(const char* what) const
{
    Mutex::Autolock _l(mLock);
    dump_l(what, flags);
    dump_l(what);
}

void SimpleBestFitAllocator::dump_l(const char* what, uint32_t flags) const
void SimpleBestFitAllocator::dump_l(const char* what) const
{
    String8 result;
    dump_l(result, what, flags);
    dump_l(result, what);
    LOGD("%s", result.string());
}

void SimpleBestFitAllocator::dump(String8& result,
        const char* what, uint32_t flags) const
        const char* what) const
{
    Mutex::Autolock _l(mLock);
    dump_l(result, what, flags);
    dump_l(result, what);
}

void SimpleBestFitAllocator::dump_l(String8& result,
        const char* what, uint32_t flags) const
        const char* what) const
{
    size_t size = 0;
    int32_t i = 0;
@@ -341,81 +455,10 @@ void SimpleBestFitAllocator::dump_l(String8& result,
        i++;
        cur = cur->next;
    }
    snprintf(buffer, SIZE, "  size allocated: %u (%u KB)\n", int(size), int(size/1024));
    snprintf(buffer, SIZE,
            "  size allocated: %u (%u KB)\n", int(size), int(size/1024));
    result.append(buffer);
}

// ----------------------------------------------------------------------------

SharedHeap::SharedHeap() 
    : HeapInterface(), MemoryHeapBase() 
{ 
}

SharedHeap::SharedHeap(size_t size, uint32_t flags, char const * name)
    : MemoryHeapBase(size, flags, name)
{
}

SharedHeap::~SharedHeap()
{
}

sp<IMemory> SharedHeap::mapMemory(size_t offset, size_t size)
{
    return new SimpleMemory(this, offset, size);
}
 

SimpleMemory::SimpleMemory(const sp<IMemoryHeap>& heap,
        ssize_t offset, size_t size)
    : MemoryBase(heap, offset, size)
{
#ifndef NDEBUG
    void* const start_ptr = (void*)(intptr_t(heap->base()) + offset);
    memset(start_ptr, 0xda, size);
#endif
}

SimpleMemory::~SimpleMemory()
{
    size_t freedOffset = getOffset();
    size_t freedSize   = getSize();

    // keep the size to unmap in excess
    size_t pagesize = getpagesize();
    size_t start = freedOffset;
    size_t end = start + freedSize;
    start &= ~(pagesize-1);
    end = (end + pagesize-1) & ~(pagesize-1);

    // give back to the kernel the pages we don't need
    size_t free_start = freedOffset;
    size_t free_end = free_start + freedSize;
    if (start < free_start)
        start = free_start;
    if (end > free_end)
        end = free_end;
    start = (start + pagesize-1) & ~(pagesize-1);
    end &= ~(pagesize-1);    

    if (start < end) {
        void* const start_ptr = (void*)(intptr_t(getHeap()->base()) + start);
        size_t size = end-start;

#ifndef NDEBUG
        memset(start_ptr, 0xdf, size);
#endif

        // MADV_REMOVE is not defined on Dapper based Goobuntu 
#ifdef MADV_REMOVE 
        if (size) {
            int err = madvise(start_ptr, size, MADV_REMOVE);
            LOGW_IF(err, "madvise(%p, %u, MADV_REMOVE) returned %s",
                    start_ptr, size, err<0 ? strerror(errno) : "Ok");
        }
#endif
    }
}

}; // namespace android
+1 −1
Original line number Diff line number Diff line
@@ -127,7 +127,7 @@ void SubRegionMemory::revoke()

MemoryHeapPmem::MemoryHeapPmem(const sp<MemoryHeapBase>& pmemHeap,
        uint32_t flags)
    : HeapInterface(), MemoryHeapBase()
    : MemoryHeapBase()
{
    char const * const device = pmemHeap->getDevice();
#if HAVE_ANDROID_OS