Shared Heaps


Home Introduction Successes Examples Download Install Documentation Discussion Acknowledgments



Introduction

PUPS/P3 implements threadsafe shared heaps (see the code fragment below), which are a form of persistent object store. Objects may be created on these heaps using malloc semantics (in fact the PUPS/P3 shmheap library is based on GNU-malloc but uses mmap rather than brk to extend the heap and objects within it). PUPS/P3 processes may map multiple shared heaps into their address spaces. Objects created by one process (which is attached to the heap) will be seen by all other client processes which are attached to it. Exclusive access to objects in the shared heaps (by a given client) is provided using a combination of semaphores and NFS file locking.



Mechanism

PUPS/P3 shared heaps are based on Mike Haertel's GNU-malloc implementation. PUPS/P3 shared heaps are thread/process safe and may be simultaneously mapped into the address spaces of many processes. If backing store for the shared heap resides on a network filesytem (e.g. NFS or MFS), these processes may reside on any host which elects to mount that file system. Furthermore, it is possible to use 32 bit shared heaps on 64 bit architectures (e.g. Alpha or X86_64). This means that 32 and 64 bit hosts can share common persistent objects.

Schematic of a shared heap. Note the the processes mapping the heap objects may be resident on different physical hosts and that a given process may map multiple heap objects.

Because of the way that mmap works, the location of the shared heap (in the address space of a process which has attached it) is not known until it is mapped. Because of this, shared heaps maintain a table of the objects which they contain. When the heap is mapped into the process address space, the appropriate offsets are added to the addresses of objects in the heap, so they appear at the correct addresses in the address space of all the processes which have mapped them.

In addition to maintaining a list of addresses for heap objects PUPS/P3 shared heaps also maintain a list of names; Routines are provided in the shared heap library to translate between these names and the addresses of the objects on the (mapped) heap. An information table is also provided so the types of heap objects (and any other information which may be required by a process attaching a heap is available to it).

The code fragment below should give some insight into how shared heaps may be used within PUPS/P3 applications.




    /* Lets attach a shared heap */
    if((hdes = msm_heap_attach("heap1",
                           O_RDWR    | O_CREAT,
                           PROT_READ | PROT_WRITE,
                           MAP_SHARED,
                           LIVE)) == (-1))
        pups_exit(-1);

    /* And another */
    /*if(msm_heap_attach("heap2",
                       O_RDWR    | O_CREAT,
                       PROT_READ | PROT_WRITE,
                       MAP_SHARED,
                       LIVE) == (-1))
       pups_exit(-1);
    */


    /* And another */
    /*if(msm_heap_attach("heap3",
                       O_RDWR    | O_CREAT,
                       PROT_READ | PROT_WRITE,
                       MAP_SHARED,
                       LIVE) == (-1))
       pups_exit(-1);
    */


    /* Allocate some objects on the first shared heap */
    if(shmalloc(hdes,260000,"object1") == (void *)NULL)
    {  fprintf(stderr,"test: failed to allocated shared heap object (%s)\n","object1");
       fflush(stderr);

       /* If this object already exists - which is the reason that the  */
       /* attempt to allocate it failed, lets take a look at the shared */
       /* memory associated with it                                     */
       h_ptr_1 = msm_lockobjectname(hdes,F_LOCK,"object1",WRITE);
       fprintf(stderr,"INITIAL VALUE:  %s\n",h_ptr_1,h_ptr_1);
       msm_lockobjectname(hdes,F_ULOCK,"object1",READ);
    }

    if(shmalloc(hdes,55000,"object2") == (void *)NULL)
    {  fprintf(stderr,"test: failed to allocated shared heap object (%s)\n","object2");
       fflush(stderr);
    }

    /* Remove the object "object2" from the shared heap "heap1" */
    h_ptr_1 = msm_lockobjectname(hdes,F_LOCK,"object2",READWRITE);
    (void)shfree(hdes,h_ptr_1);

    /* And add another shared object */
    if(shmalloc(hdes,355000,"object3") == (void *)NULL)
    {  fprintf(stderr,"test: failed to allocated shared heap object (%s)\n","object3");
       fflush(stderr);
    }

    /* Display the current objects and clients */
    (void)map_show(hdes,stderr);
    (void)client_show(hdes,stderr);


    /* This loop repeatedly locks an object on the shared      */
    /* heap "heap1", updates it, and then unlcoks it (so other */
    /* clients of the heap can access it)                      */
    while(1)
    {    char strdum[256];
         unsigned long ldum;

         int i,
             idum;


         /* Update shared heap object "object1" on heap "heap1"      */
         /* Lock "object1" and return a (local) pointer to it        */
         h_ptr_1 = msm_lockobjectname(hdes,F_LOCK,"object1",READWRITE);

         /* Update "object1" */
         (void)sscanf(h_ptr_1,"%s %s %s %s %s %d",
                      strdum,strdum,strdum,strdum,strdum,&cnt);
         (void)sprintf(h_ptr_1,"[0x%x] %s [%d@%s] cnt is %d!",
                      (unsigned long)h_ptr_1,appl_name,appl_pid,appl_host,++cnt);
         fprintf(stderr,"%s\n",h_ptr_1);
         fflush(stderr);

         (void)usleep(100);

         /* Unlock "object1" so other clients can access it */
         (void)msm_lockobjectname(hdes,F_ULOCK,"object1",READWRITE);


         (void)usleep(10);
    }


PUPS/P3 (c) Mark A. O'Neill 2007