Source: qvmm.h


Annotated List
Files
Globals
Hierarchy
Index
// ColdStore Mmap manager
// Copyright (C) 1998,1999 Phillipe Hebrais,
// see LICENSE (MD5 f5220f8f599e5e926f37cf32efe3ab68) for terms
// $Id: qvmm_h.html,v 1.1.1.1 2000/04/09 01:07:51 skeptopotamus Exp $

#ifndef QVMM_H
#define QVMM_H
#include <sys/types.h>

// DEBUGLOG turns on traces
#ifdef DEBUGLOG
#define DEBLOG(x) (x);
#else
#define DEBLOG(x)
#endif

/** ColdStore Mmap manager
 * @author Phillipe Hebrais
 *
 * Mmap maintains the store, providing
 * @li store information,
 * @li new page allocation, and
 * @li @ref Latch services</ul> to the application.
 */
class Mmap
{
    // space for a store's magic number and Global region size
    /** actual size of store */
    static size_t size;

    /** store's persistent header */
    static int header[];

    /** end of header */
    static int end[];

    /** first byte of non-header store (R/O!!!) */
    static int store[];

public:
    /** store mmap'd base address (page aligned) */
    static const void *const base = (void*)0x50000000;

    /** maximum size of store (page aligned) */
    static const size_t max = 0x40000000;

    /** underlying page size of store (power of 2) */
    static const size_t page_size = 4096;

    /** flag: is Mmap initialized? */
    static bool initialized;
    
    // Initialize and uninit;

    /** Mmap the file as a store.
     * @param fd file descriptor of open store
     * @return current size of store
     */
    static size_t open( int fd);

    /** Open and Mmap the named file as a store.
     * @param file file name
     * @return file descriptor of open store
     */
    static int open(char *file);

    /** close the Mmap
     * @param fd file descriptor of open store
     */
    static void close( int fd);
    
    /** Allocate a range of pages in the store
     * @param size size of allocation
     * @return allocated region
     */
    static void* alloc( size_t size);

    // Munge pointers and sizes

    /** check the validity of a pointer
     * @param ptr pointer to be checked
     * @return true if the pointer is in the Mmap
     */
    static int check( void* ptr)
        { return ptr >= base && (char*)ptr < (char*)base + max; }

    /** align a value to a page boundary
     * @param size value to align
     * @return page-aligned value
     */
    static size_t align( size_t size)
        { return (size+page_size-1) & ~(page_size-1); }

    /** return the page which contains a pointer
     * @param ptr pointer to align
     * @return page-aligned pointer
     */
    static void* pageof( void* ptr)
        { return (void*)(((size_t)ptr) & ~(page_size-1)); }
    
    // Latch ops;
    static void* locked( void);
    static void lock( void* l);
    static void unlock( void);
};

/** cheap limited deadlock- & starvation-free interthread spinlock mutex
 * @author Phillipe Hebrais
 *
 * Latches provide simple mutual exclusion between forks.  Each fork
 * may hold at most one Latch at a time.  Page allocation uses
 * this latch, so it must be free or the allocation will fail.
 *
 * Use Latches only for very short term locking.
 *
 * The goal is to let as many forks as possible access concurrently the
 * database so that while one fork page faults, the others can continue
 * using the cpu.  To avoid excessive serialization, we must reduce to a
 * minimum the amount of global locking required.
 *
 * Latches are meant to be very cheap (but limited) mutex.
 *
 * It avoids global locking by not using a wait queue.
 * Instead, a global hash table is used as rendez-vous point for 
 * latch requests and forks wait by yielding and looping.
 *
 * The latching algorithm garantees deadlock and starvation freeness.
*/
class Latch
{
    /** prime number > 2*n_forks */
    static size_t const size    = 4079;

    /** uSec to sleep while busy waiting for the spinlock */
    static size_t const timeout = 1000;
    
    /** set of latches of given size
     */
    static char latch[size];

 public:
    /** lock a latch
     * @param target address to lock
     */
    static void lock( void* target);
    
    /** unlock a latch
     * @param target locked address
     */
    static void unlock( void* target);
};

/** Entity allocated relative to an @ref Mmap
 * @author Phillipe Hebrais
 *
 * Memory instances are the basic currency of ColdStore,
 * providing interfaces to the store's features
 * @li extent-based (de&re)allocation
 * @li interface to @ref Latch locking of addresses
 * @li per-allocation information: @ref Memory::mySize @ref Memory::myAllocator
 * @li atomic low-level inc/dec ops: @ref Memory::inc @ref Memory::dec
 */
class Memory
{
public:
    /** the `unallocated' allocator */
    static const void * const no_alloc = (void*)-1;

    /** lock this object
     */
    void lock(void);

    /** unlock this object
     */
    void unlock(void);

    /** Atomic counter increment
     */
    static void inc( size_t& val) {
        asm volatile ("incl (%0)" : : "r" (&val) : "cc", "memory");
    };

    /** Atomic counter decrement
     */
    static int dec( size_t& val) {
        int ret = 0;
        asm volatile ("decl (%2);jz 1f;incl %0;1:"
                      : "=r" (ret) : "0" (ret), "r" (&val) : "cc", "memory");
        return ret;
    }

    // C++ interface - new with optional allocator
    /** C++ extent placement new
        @arg size size of allocation in bytes
        @arg where neighborhood into which to allocate
        @returns storage allocated as requested
     */
    void* operator new( size_t size, void* where=(void*)0);

    /** C++ extent additional placement new
        @arg size size of allocation in bytes
        @arg extra extra allocation in bytes
        @arg where neighborhood into which to allocate
        @returns storage allocated as requested
     */
    void* operator new( size_t size, size_t extra, void* where=(void*)0);

    /** C++ object deletion
        @arg ptr a pointer returned by @ref operator new()
        @arg extra extra allocation in bytes
        @arg where neighborhood into which to allocate
        @returns storage allocated as requested
     */
    void  operator delete( void* ptr);

    /** C++ extent placement array new
        @arg size size of allocation in bytes
        @arg where neighborhood into which to allocate
     */
    void* operator new[] (size_t size, void* where=(void*)0);

    /** C++ array object deletion
        @arg ptr a pointer returned by @ref operator new[]()
        @arg extra extra allocation in bytes
        @arg where neighborhood into which to allocate
     */
    void  operator delete[] ( void* ptr);
    
    // C interface
    /** C storage reallocation
        @arg addr a pointer to previously alloc'd storage
        @arg size size of new allocation in bytes
        @arg allocator neighborhood into which to allocate
        @returns storage allocated as requested
     */
    static void*  realloc( void* addr, size_t size,
                           void* allocator=(void*)no_alloc);

    /** C storage allocation
        @arg size size of new allocation in bytes
        @arg allocator neighborhood into which to allocate
        @returns storage allocated as requested
     */
    static void*  alloc( size_t size, void* allocator);

    /** C storage deletion
        @arg ptr a pointer returned by @ref alloc()
     */
    static void   free( void* ptr);

    // utility accessors
    /** external size of allocation
        @arg ptr a pointer returned by @ref alloc()
        @returns size occupied by the allocation of ptr
     */
    static size_t size(const void* ptr);

    /** internal size of some allocation
     */
    size_t itsSize(const void* ptr) const;

    /** internal size of allocation surrounding this
     */
    size_t mySize() const;

    /** allocator of given region
        @arg ptr a pointer to allocated storage
        @returns the neighborhood with which ptr is associated
     */
    static void*  allocator( void* ptr);

    /** allocator of instance
        @returns the neighborhood with which this is associated
     */
    void *myAllocator() {
        return allocator(this);
    }

    // Health checks
    /** predicate: BTree is healthy
     */
    static int check(void);

    /** Assert health of BTree
     */
    static void Assert( void);

#ifdef GUARD_ALLOC
    /** Check Guards' health 
     */
    static void *checkGuard(void *ptr, bool damage=false);

 protected:
    /** construct a pair of Guards around the allocation to
     * detect overwriting and double-deletion.
     */
    static void *guard(void *ptr, void *alloc, size_t size);
    
    /** Non-destructively Validate Guards of this Memory instance
     */
    void validGuard() const {
        Memory::Assert();
        checkGuard((void*)this);
    }
#else
    // no Guarding - hopefully these will be optimised out
    static void *checkGuard(void *ptr, bool damage=false) {return ptr;}
 protected:
    static void *guard(void *ptr, void *alloc, size_t size) {return ptr;}
    void validGuard() const {}
#endif
};
namespace qvmm {
    class RefCount
        : public Memory
        {
        protected:
            /** number of references to this Memory
             */
            mutable size_t _refcount;
            
        public:
            /** Construct RefCount Memory
                note: Memory starts with 0 refcount
            */
            RefCount(void)
                : _refcount(0)
                {}
            
            /** add a reference to this
             */
            RefCount *upcount( void) const;
            
            /** remove a reference to this (possibly delete)
             */
            void dncount( void);
            
            /** return the refcount of this
             */
            size_t refcount( void) const { return _refcount; }
        };
}

// Global new[] and delete[] with Allocator placement
/** extent placement default array new operator using store
 */
void* operator new[] (size_t size, Memory* where);

/** extent placement default new operator using store
 */
void* operator new (size_t size, Memory* where);

#ifdef WRAP_MALLOC
// This permits use to wrap the standard allocation functions
// -wrap malloc -wrap free must appear in the ld linker command
extern "C"
{
    void *__wrap_malloc (size_t size);
    void __wrap_free (void *allocation);
    void *__wrap_realloc(void *ptr, size_t size);
}
#endif

#endif // QVMM_H

Generated by: colin@sharedtech.dhis.org on Sat Nov 6 11:59:21 199.