apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "MATHIHALLI,MADHUSUDAN (HP-Cupertino,ex1)" <madhusudan_mathiha...@hp.com>
Subject RE: [PATCH] shmem.c - 3rd try
Date Tue, 25 Sep 2001 05:58:45 GMT
Hi,
  Here's the patch including the MMAP change and the comments that Ryan had
put forth. The patch consists of 3 files :
1. shmem.c [PATCH format]
2. shmem_lib.c [NEW file]
3. shmem.h [NEW file].

 As regards the MMAP changes - I have verified it for MMAP_ANON.. I've also
tried to enable the MMAP logic for MMAP_SHM, MMAP_ZERO & MMAP_TMP -it'd be
great if somebody could review the change and let me know if it's okay.
  Pl. review the changes and commit it accordingly.

Thanks
-Madhu


Index: shmem.c
===================================================================
RCS file: /home/cvspublic/apr/shmem/unix/shmem.c,v
retrieving revision 1.33
diff -u -r1.33 shmem.c
--- shmem.c	2001/08/30 17:11:04	1.33
+++ shmem.c	2001/09/25 05:43:51
@@ -52,14 +52,6 @@
  * <http://www.apache.org/>.
  */
 
-#include "apr_general.h"
-#include "apr_shmem.h"
-#include "apr_lock.h"
-#include "apr_portable.h"
-#include "apr_errno.h"
-#define APR_WANT_MEMFUNC
-#include "apr_want.h"
-
 /*
  * This is the Unix implementation of shared memory.
  *
@@ -72,45 +64,15 @@
  * - shmget (SysV)
  * - create_area (BeOS)
  */
-
-#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM ||
APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON
-#include <sys/mman.h>
-#elif APR_USE_SHMEM_SHMGET
-#include <sys/ipc.h>
-#include <sys/shm.h>
-#if !defined(SHM_R)
-#define SHM_R 0400
-#endif
-#if !defined(SHM_W)
-#define SHM_W 0200
-#endif
-#include <sys/file.h>
-#elif APR_USE_SHMEM_BEOS
-#include <kernel/OS.h>
-#endif
 
-struct shmem_t {
-    void *mem;
-    void *curmem;
-    apr_size_t length;
-    apr_lock_t *lock;
-    char *filename;
-#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM ||
APR_USE_SHMEM_MMAP_ZERO
-    apr_file_t *file; 
-#elif APR_USE_SHMEM_MMAP_ANON
-    /* Nothing else. */
-#elif APR_USE_SHMEM_SHMGET
-    apr_os_file_t file;
-#elif APR_USE_SHMEM_BEOS
-    area_id areaid; 
-#endif
-};
+#include "shmem.h"
 
 APR_DECLARE(apr_status_t) apr_shm_init(apr_shmem_t **m, apr_size_t reqsize,

                                        const char *filename, apr_pool_t
*pool)
 {
     apr_shmem_t *new_m;
-    void *mem;
+    void *mem, *addr;
+    int i, listlen, listelem;
 #if APR_USE_SHMEM_SHMGET
     struct shmid_ds shmbuf;
     apr_uid_t uid;
@@ -128,6 +90,9 @@
     if (!new_m)
         return APR_ENOMEM;
 
+    listelem = (reqsize / MIN_BLK_SIZE) + 1;
+    listlen  = listelem * sizeof(memchunk_t) + sizeof(memoffsets_t);
+
 /* These implementations are very similar except for opening the file. */
 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM ||
APR_USE_SHMEM_MMAP_ZERO
     /* FIXME: Ignore error for now. *
@@ -168,10 +133,18 @@
     status = apr_os_file_get(&tmpfd, new_m->file);
 #endif
 
-    mem = mmap(NULL, reqsize, PROT_READ|PROT_WRITE, MAP_SHARED, tmpfd, 0);
+    /* Not yet tested */
+    addr = mmap(NULL, reqsize + listlen,
+                PROT_READ|PROT_WRITE, MAP_SHARED, tmpfd, 0);
+    new_m->listlen = listlen;
+    mem = addr + listlen;
 
 #elif APR_USE_SHMEM_MMAP_ANON
-    mem = mmap(NULL, reqsize, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED,
-1, 0);
+    mem = mmap(NULL, reqsize,
+               PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0);
+    addr = mmap(NULL, listlen,
+               PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0);
+    new_m->listlen = listlen;
 #elif APR_USE_SHMEM_SHMGET
     tmpfd = shmget(IPC_PRIVATE, reqsize, (SHM_R|SHM_W|IPC_CREAT));
     if (tmpfd == -1)
@@ -180,7 +153,16 @@
     new_m->file = tmpfd;
 
     mem = shmat(new_m->file, NULL, 0);
+    if (!mem)
+        return errno;
 
+    tmpfd = shmget(IPC_PRIVATE, listlen, (SHM_R|SHM_W|IPC_CREAT));
+    if (tmpfd == -1)
+        return errno;
+
+    new_m->listfd = tmpfd;
+    addr = shmat(new_m->listfd, NULL, 0);
+
     /* FIXME: Handle errors. */
     if (shmctl(new_m->file, IPC_STAT, &shmbuf) == -1)
         return errno;
@@ -192,8 +174,7 @@
     if (shmctl(new_m->file, IPC_SET, &shmbuf) == -1)
         return errno;
 
-    /* remove in future (once use count hits zero) */
-    if (shmctl(new_m->file, IPC_RMID, NULL) == -1)
+    if (shmctl(new_m->listfd, IPC_SET, &shmbuf) == -1)
         return errno;
 
 #elif APR_USE_SHMEM_BEOS
@@ -205,8 +186,36 @@
 
 #endif
 
+    if (!addr)
+        return errno;
+
+    new_m->offsets = addr;
+    new_m->list    = addr + (sizeof(memoffsets_t));
+
+    memset(new_m->list, 0, listlen);
+    for (i = 0; i < listelem; i++) {
+        new_m->list[i].prev = -1;
+        new_m->list[i].next = -1;
+    }
+
+    /*
+     * Initially, there's only one element c_free (=0, l_total = 1).
+     * The size of this free element is the total size requested.
+     * The c_used list is set to NULL (c_used = -1).
+     */
+    new_m->list[0].offset = 0;
+    new_m->list[0].size = reqsize;
+    new_m->list[0].next = 0;
+    new_m->list[0].prev = 0;
+
+    new_m->offsets->l_total = 1;
+    new_m->offsets->c_free  = 0;
+    new_m->offsets->c_used  = -1;
+    new_m->offsets->shm_offset = 0;
+    new_m->offsets->shm_length = reqsize;
+
+    new_m->p = pool;
     new_m->mem = mem;
-    new_m->curmem = mem;
     new_m->length = reqsize;
 
     apr_lock_create(&new_m->lock, APR_MUTEX, APR_CROSS_PROCESS, NULL,
pool);
@@ -219,48 +228,86 @@
 
 APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shmem_t *m)
 {
+#if APR_USE_SHMEM_SHMGET
+    struct shmid_ds shmbuf;
+    apr_uid_t uid;
+    apr_gid_t gid;
+#endif
+
+    if (!m)
+        return APR_SUCCESS;
+
 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM ||
APR_USE_SHMEM_MMAP_ZERO
-    munmap(m->mem, m->length);
+    munmap(m->offsets, (m->length + m->listlen));
     apr_file_close(m->file);
 #elif APR_USE_SHMEM_MMAP_ANON
     munmap(m->mem, m->length);
+    munmap(m->offsets,m->listlen);
 #elif APR_USE_SHMEM_SHMGET
     shmdt(m->mem);
+    apr_current_userid(&uid, &gid, m->p);
+    shmbuf.shm_perm.uid = uid;
+    shmbuf.shm_perm.gid = gid;
+
+    if (shmctl(m->file, IPC_RMID, &shmbuf) == -1)
+        return errno;
+
+    shmdt(m->list);
+    if (shmctl(m->listfd, IPC_RMID, &shmbuf) == -1)
+        return errno;
+
 #elif APR_USE_SHMEM_BEOS
-    delete_area(new_m->area_id);
+    delete_area(m->area_id);
 #endif
 
+    m->offsets  = NULL;
+    m->mem = NULL;
+
     return APR_SUCCESS;
 }
 
 APR_DECLARE(void *) apr_shm_malloc(apr_shmem_t *m, apr_size_t reqsize)
 {
-    void *new;
-    new = NULL;
+    memchunk_t *b = NULL;
 
     apr_lock_acquire(m->lock);
-    /* Do we have enough space? */
-    if (((char *)m->curmem - (char *)m->mem + reqsize) <= m->length)
-    {
-        new = m->curmem;
-        m->curmem = (char *)m->curmem + reqsize;
-    }
+    b = apr_shm_alloc_chunk(m, reqsize);
     apr_lock_release(m->lock);
-    return new;
+
+    return ((b) ? APR_SHM_ADDR(m, b->offset) : NULL);
 }
 
 APR_DECLARE(void *) apr_shm_calloc(apr_shmem_t *m, apr_size_t reqsize) 
+{
+    memchunk_t *b = NULL;
+
+    apr_lock_acquire(m->lock);
+    b = apr_shm_alloc_chunk(m, reqsize);
+    if (b != NULL)
+        memset(APR_SHM_ADDR(m, b->offset), 0, reqsize);
+    apr_lock_release(m->lock);
+    return ((b) ? APR_SHM_ADDR(m, b->offset) : NULL);
+}
+
+APR_DECLARE(void *) apr_shm_realloc(apr_shmem_t *m, void *p, apr_size_t
reqsize)
 {
-    void *new = apr_shm_malloc(m, reqsize);
-    if (new)
-        memset(new, '\0', reqsize);
-    return new;
+    memchunk_t *b = NULL;
+    
+    apr_lock_acquire(m->lock);
+    if (p != NULL)
+        b = apr_shm_realloc_chunk(m, p, reqsize);
+    else 
+        b = apr_shm_alloc_chunk(m, reqsize);
+    apr_lock_release(m->lock);
+
+    return ((b) ? APR_SHM_ADDR(m, b->offset) : NULL);
 }
 
-APR_DECLARE(apr_status_t) apr_shm_free(apr_shmem_t *shared, void *entity)
+APR_DECLARE(apr_status_t) apr_shm_free(apr_shmem_t *m, void *entity)
 {
-    /* Without a memory management scheme within our shared memory, it
-     * is impossible to implement free. */
+    apr_lock_acquire(m->lock);
+    apr_shm_free_chunk(m, entity);
+    apr_lock_release(m->lock);
     return APR_SUCCESS;
 }
 
@@ -315,16 +362,16 @@
 
 APR_DECLARE(apr_status_t) apr_shm_avail(apr_shmem_t *m, apr_size_t *size)
 {
-    apr_status_t status;
+    apr_status_t status = APR_ENOSHMAVAIL;
 
-    status = APR_ENOSHMAVAIL;
-
-    apr_lock_acquire(m->lock);
+    if (m)
+    {
+        apr_lock_acquire(m->lock);
+        if ((*size = m->offsets->shm_length) > 0)
+            status = APR_SUCCESS;
 
-    *size = m->length - ((char *)m->curmem - (char *)m->mem);
-    if (*size)
-        status = APR_SUCCESS;
+        apr_lock_release(m->lock);
+    }
 
-    apr_lock_release(m->lock);
     return status;
 }



Index: shmem_lib.c
===================================================================
file: /home/cvspublic/apr/shmem/unix/shmem_lib.c,v

#include "shmem.h"

/*
 * Find the insert position in a sorted list of elements. The sorting is
 * based on the value of the list[idx].offset.
 * Input      : Begining index of the sorted list (*first), elem to be
inserted.
 * Return     : The index before which the elem is to be inserted.
 */
index_t apr_shm_pos_in_sorted_list(apr_shmem_t *m, index_t first, index_t
elem)
{
    index_t idx = first;

    if (idx < 0) return -1;

    do {
        if (m->list[idx].offset > m->list[elem].offset)
            break;
        idx = m->list[idx].next;
    } while ((idx >= 0) && (idx < APR_SHM_MAX_LIST_ELEM(m)) && (idx
!=
first));
    return idx;
}

/*
 * Adds a list element (elem) to the list pointed by *first. If *first
points
 * to a freelist, it finds the appropirate insert position else appends elem
 * to the end of the list.
 * Ex. Adds a listelement to the usedlist / freelist.
 */
void apr_shm_addlist(apr_shmem_t *m, index_t *first, index_t elem)
{
    index_t prev, idx;

    if (*first == m->offsets->c_free)
        idx = apr_shm_pos_in_sorted_list(m, *first, elem);
    else
        idx = *first;

    if (idx == -1) {
        idx = *first = elem;
        prev = elem;
    }
    else
        prev = m->list[idx].prev;

    m->list[idx].prev = elem;
    m->list[prev].next = elem;
    m->list[elem].prev = prev;
    m->list[elem].next = idx;

    if (idx == m->offsets->c_free)
        *first = elem;
}

/*
 * Removes the elem from the list pointed to by *first.
 * Ex. Removes a listelement from freelist so that it can be added to
usedlist.
 */
void apr_shm_removelist(apr_shmem_t *m, index_t *first, index_t elem)
{
    index_t prev, next;
  
    next = m->list[elem].next;
    prev = m->list[elem].prev;
    m->list[prev].next = next;
    m->list[next].prev = prev;
    if (next == elem)
        *first = -1;
}

/*
 * Frees a list element. This is useful during garbage collection. If 2 list
 * elements can be merged (to form a bigger chunk), the 2nd list element has
 * to be freed. The freed list element is made available at the end of the
 * list. (No need for maintaining a seperate list of available listelements)
 */
void apr_shm_freelist(apr_shmem_t *m, index_t elem)
{
    index_t idx;
    if (elem >= 0) {
        idx = m->offsets->l_total - 1;
        memcpy(&m->list[elem], &m->list[idx], sizeof(memchunk_t));
        m->list[m->list[idx].prev].next = idx; 
        m->list[m->list[idx].next].prev = idx;
        m->offsets->l_total--;
    }
}

/*
 * Splits a memory chunk into two. The second mem chunk is allocated a list
 * element, and filled with updated memory offsets / size.
 */
index_t apr_shm_split_chunk(apr_shmem_t *m, index_t elem, apr_size_t size)
{
    index_t nelem = m->offsets->l_total;
    if (nelem > APR_SHM_MAX_LIST_ELEM(m))
        return -1;

    m->list[nelem].size   = m->list[elem].size - size;
    m->list[elem].size    = size;
    m->list[nelem].offset = m->list[elem].offset + size;
    apr_shm_addlist(m, &m->offsets->c_free, nelem);
    m->offsets->l_total++;

    return nelem;
}

/*
 * Finds the list element for a givem memory chunk
 */
index_t apr_shm_find_by_addr(apr_shmem_t *m, index_t first, void *addr)
{
    index_t idx = first;

    if (idx < 0) return -1;

    do {
       if (APR_SHM_ADDR(m, m->list[idx].offset) == addr)
            return idx;
    } while ((idx >= 0) && ((idx = m->list[idx].next) != first));

    return -1;
}

/*
 * Finds a list element that best satisfies the memory requirement. If
there's
 * no best match available, it splits the memchunk into two.
 */
index_t apr_shm_find_by_size(apr_shmem_t *m, index_t first, apr_size_t size)
{
    apr_size_t  diff = -1;
    index_t idx = first, found = -1;

    if (idx < 0) return -1;

    do {
        if (m->list[idx].size == size)
            return idx;
        if (m->list[idx].size > size) {
            if ((diff == -1) || ((m->list[idx].size - size) < diff)) {
                diff = m->list[idx].size - size;
                found = idx;
            }
        }
    } while ((idx >= 0) && (idx = m->list[idx].next) != first);

    if (diff > MIN_BLK_SIZE)
        m->offsets->c_free = apr_shm_split_chunk(m, found, size);

    return found;
}

/*
 * Allocates a memory chunk. This also requires a list element to be
allocated.
 * It first checks the freelist to see if any match is available. If none
are
 * available, it allocates a new listelement. It adds the new listelement
 * to the c_used list.
 */
memchunk_t *apr_shm_alloc_chunk(apr_shmem_t *m, apr_size_t size)
{
    index_t idx;

    size = ROUND_UP(size);

    if (m->offsets->shm_length < size)
        return NULL;

    idx = apr_shm_find_by_size(m, m->offsets->c_free, size);
    if (idx != -1)
        apr_shm_removelist(m, &m->offsets->c_free, idx);
    else {
        idx = m->offsets->l_total;
        if (idx >= APR_SHM_MAX_LIST_ELEM(m))
            return NULL;

        m->list[idx].offset = m->offsets->shm_offset;
        m->list[idx].size   = size;
        m->offsets->shm_offset += m->list[idx].size;
        m->offsets->l_total++;
    }

    m->offsets->shm_length -= m->list[idx].size;
    apr_shm_addlist(m, &m->offsets->c_used, idx);

    return (&m->list[idx]);
}

/*
 * Frees a memory chunk pointed by entity. It removes the corresponding 
 * listelement from the c_used list and appends it to the c_free list
 */
void apr_shm_free_chunk(apr_shmem_t *m, void *entity)
{
    index_t idx;

    if (entity == NULL)
        return;

    idx = apr_shm_find_by_addr(m, m->offsets->c_used, entity);
    if (idx != -1) {
        m->offsets->shm_length += m->list[idx].size;
        apr_shm_removelist(m, &m->offsets->c_used, idx);
        apr_shm_addlist(m, &m->offsets->c_free, idx);
    }
}

/*
 * Reallocates (resize) the memory pointed to by entity. It's not a true
 * replacement of the realloc() - in the sense if the entity is not found
 * in the used_list, it doesn't allocate a new memory of the requested size
 */
memchunk_t *apr_shm_realloc_chunk(apr_shmem_t *m, void *entity, apr_size_t
size)
{
    index_t idx;
    memchunk_t *new_b;

    size = ROUND_UP(size);

    idx = apr_shm_find_by_addr(m, m->offsets->c_used, entity);
    if (idx != -1) {
        if (m->list[idx].size > size)
            m->offsets->c_free = apr_shm_split_chunk(m, idx, size);
        else if ((m->list[idx].size < size) && 
                 (size < m->offsets->shm_length)) {
            new_b = apr_shm_alloc_chunk(m, size);
            memcpy(APR_SHM_ADDR(m, new_b->offset),
                   APR_SHM_ADDR(m, m->list[idx].offset), m->list[idx].size);
            apr_shm_free_chunk(m, entity);
            idx = APR_SHM_LIST_INDEX(m,new_b);
        }
    }
    return ((idx >= 0) ? &m->list[idx] : NULL);
}

Index: shmem.h
===================================================================
file: /home/cvspublic/apr/shmem/unix/shmem.h,v

#ifndef SHMEM_H
#define SHMEM_H

#include "apr_general.h"
#include "apr_shmem.h"
#include "apr_lock.h"
#include "apr_portable.h"
#include "apr_errno.h"
#define APR_WANT_MEMFUNC
#include "apr_want.h"

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Currently, this code supports the following shared memory techniques:
 *
 * - mmap on a temporary file
 * - mmap/shm_open on a temporary file (POSIX.1)
 * - mmap with MAP_ANON (4.4BSD)
 * - mmap /dev/zero (SVR4)
 * - shmget (SysV)
 * - create_area (BeOS)
 */

#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM ||
APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON
#include <sys/mman.h>
#elif APR_USE_SHMEM_SHMGET
#include <sys/ipc.h>
#include <sys/shm.h>
#if !defined(SHM_R)
#define SHM_R 0400
#endif
#if !defined(SHM_W)
#define SHM_W 0200
#endif
#include <sys/file.h>
#elif APR_USE_SHMEM_BEOS
#include <kernel/OS.h>
#endif

#define MIN_BLK_SIZE 256

typedef apr_int32_t index_t;
typedef struct memoffsets_t {
    index_t    l_total;    /* Index to start of Free list elements */
    index_t    c_used;     /* Index to start of the used chunk list */
    index_t    c_free;     /* Index to start of the freed chunk list */
    apr_off_t  shm_offset; /* The current offset of the shared memory */
    apr_size_t shm_length; /* Total length of shared memory available */
} memoffsets_t;

typedef struct memchunk_t {
    apr_off_t  offset;     /* Offset of the memory - from m->mem */
    apr_size_t size;       /* Size of the chunk */
    index_t    next;       /* Index of Next chunk in the list */
    index_t    prev;       /* Index of Previous chunk in the list*/
} memchunk_t;

struct shmem_t {
    apr_pool_t *p;
    void *mem;             /* Starting address of the shared memory */
    memoffsets_t *offsets; /* Begining of the set of offsets */
    memchunk_t *list;      /* Begining of the list elements */
    apr_size_t length;
    apr_size_t listlen;
    apr_lock_t *lock;
    char *filename;
#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM ||
APR_USE_SHMEM_MMAP_ZERO
    apr_file_t *file; 
#elif APR_USE_SHMEM_SHMGET
    apr_os_file_t file;
    apr_os_file_t listfd;
#elif APR_USE_SHMEM_BEOS
    area_id areaid; 
#endif
};


#define APR_SHM_ADDR(m,offset)    ((offset < 0) ? (void *)NULL :  \
    (void *)((unsigned char *)m->mem + offset))

#define APR_SHM_LIST_INDEX(m,ptr)     ((ptr == NULL) ? -1 :       \
    (((unsigned char *)ptr - (unsigned char *)m->list)/sizeof(memchunk_t)))

#define APR_SHM_MAX_LIST_ELEM(m) ((m->length / MIN_BLK_SIZE) + 1)

#define ROUND_UP(size) ((size < MIN_BLK_SIZE) ? MIN_BLK_SIZE :     \
                    ((1 + ((size - 1) / sizeof (void *))) * sizeof (void
*)))


memchunk_t *apr_shm_alloc_chunk(apr_shmem_t *m, apr_size_t size);
memchunk_t *apr_shm_realloc_chunk(apr_shmem_t *m,
                                  void *entity, apr_size_t size);
void    apr_shm_free_chunk(apr_shmem_t *m, void *entity);
index_t apr_shm_split_chunk(apr_shmem_t *m, index_t elem, apr_size_t size);

index_t apr_shm_pos_in_sorted_list(apr_shmem_t *m, index_t first, index_t
elem);
index_t apr_shm_find_by_addr(apr_shmem_t *m, index_t first, void *addr);
index_t apr_shm_find_by_size(apr_shmem_t *m, index_t first, apr_size_t
size);

void    apr_shm_addlist(apr_shmem_t *m, index_t *first, index_t elem);
void    apr_shm_removelist(apr_shmem_t *m, index_t *first, index_t elem);
void    apr_shm_freelist(apr_shmem_t *m, index_t elem);

#ifdef __cplusplus
}
#endif
#endif /* !SHMEM_H */


Mime
View raw message