Based on Cliff's suggestion, this patch introduces an apr_mmap_dup()
function that's used to setaside mmap buckets without having to
memcpy the content.

I gave up trying to do full reference counting semantics for
duplicates of apr_mmap_t, because I couldn't find a suitable
pool to own the locks that would be required in a threaded
implementation.  Instead, apr_mmap_dup() lets the caller
specify which of the two apr_mmap_t structs--the original one
or the new one--is the owner of the mmap (and is responsible
for destroying it).  The patch includes a change to mod_file_cache
to create a non-owner copy of the mmap for the bucket brigade to
use, so that the mmap can't get unmapped by any code other
than mod_file_cache itself

--Brian

Index: srclib/apr/include/apr_mmap.h
===================================================================
RCS file: /home/cvspublic/apr/include/apr_mmap.h,v
retrieving revision 1.25
diff -u -r1.25 apr_mmap.h
--- srclib/apr/include/apr_mmap.h       2001/08/18 15:15:46     1.25
+++ srclib/apr/include/apr_mmap.h       2001/11/15 05:45:58
@@ -111,6 +111,8 @@
     void *mm;
     /** The amount of data in the mmap */
     apr_size_t size;
+    /** Whether this object is reponsible for doing the munmap */
+    int is_owner;
 };
 
 #if APR_HAS_MMAP || defined(DOXYGEN)
@@ -134,6 +136,19 @@
                                           apr_file_t *file, apr_off_t offset,
                                           apr_size_t size, apr_int32_t flag,
                                           apr_pool_t *cntxt);
+
+/**
+ * Duplicate the specified MMAP.
+ * @param new_mmap The structure to duplicate into. 
+ * @param old_mmap The file to duplicate.
+ * @param p The pool to use for the new file.
+ * @param transfer_ownership  Whether responsibility for destroying
+ *  the memory-mapped segment is transferred from old_mmap to new_mmap
+ */         
+APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap,
+                                       apr_mmap_t *old_mmap,
+                                       apr_pool_t *p,
+                                       int transfer_ownership);
 
 /**
  * Remove a mmap'ed.
Index: srclib/apr/mmap/unix/mmap.c
===================================================================
RCS file: /home/cvspublic/apr/mmap/unix/mmap.c,v
retrieving revision 1.36
diff -u -r1.36 mmap.c
--- srclib/apr/mmap/unix/mmap.c 2001/08/02 04:26:53     1.36
+++ srclib/apr/mmap/unix/mmap.c 2001/11/15 05:45:58
@@ -83,6 +83,11 @@
 {
     apr_mmap_t *mm = themmap;
     int rv;
+
+    if (!mm->is_owner) {
+        return APR_SUCCESS;
+    }
+
 #ifdef BEOS
     rv = delete_area(mm->area);
 
@@ -159,10 +164,38 @@
     (*new)->mm = mm;
     (*new)->size = size;
     (*new)->cntxt = cont;
+    (*new)->is_owner = 1;
 
     /* register the cleanup... */
     apr_pool_cleanup_register((*new)->cntxt, (void*)(*new), mmap_cleanup,
              apr_pool_cleanup_null);
+    return APR_SUCCESS;
+}
+
+APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap,
+                                       apr_mmap_t *old_mmap,
+                                       apr_pool_t *p,
+                                       int transfer_ownership)
+{
+    *new_mmap = (apr_mmap_t *)apr_palloc(p, sizeof(apr_mmap_t));
+    memcpy(*new_mmap, old_mmap, sizeof(apr_mmap_t));
+    (*new_mmap)->cntxt = p;
+
+    /* The old_mmap can transfer ownership only if the old_mmap itself
+     * is an owner of the mmap'ed segment.
+     */
+    if (old_mmap->is_owner) {
+        if (transfer_ownership) {
+            (*new_mmap)->is_owner = 1;
+            old_mmap->is_owner = 0;
+            apr_pool_cleanup_kill(old_mmap->cntxt, old_mmap, mmap_cleanup);
+        }
+        else {
+            (*new_mmap)->is_owner = 0;
+        }
+        apr_pool_cleanup_register(p, *new_mmap, mmap_cleanup,
+                                  apr_pool_cleanup_null);
+    }
     return APR_SUCCESS;
 }
 
Index: srclib/apr/mmap/win32/mmap.c
===================================================================
RCS file: /home/cvspublic/apr/mmap/win32/mmap.c,v
retrieving revision 1.6
diff -u -r1.6 mmap.c
--- srclib/apr/mmap/win32/mmap.c        2001/06/27 22:07:24     1.6
+++ srclib/apr/mmap/win32/mmap.c        2001/11/15 05:45:58
@@ -62,10 +62,15 @@
 
 #if APR_HAS_MMAP
 
-static apr_status_t mmap_cleanup(void *themmap)
+APR_DECLARE(apr_status_t) apr_mmap_cleanup(void *themmap)
 {
     apr_mmap_t *mm = themmap;
     apr_status_t rv = 0;
+
+    if (!mm->is_owner) {
+        return APR_SUCCESS;
+    }
+
     if (mm->mv) {
         if (!UnmapViewOfFile(mm->mv))
         {
@@ -155,19 +160,47 @@
     (*new)->mm = (char*)((*new)->mv) + offset;
     (*new)->size = size;
     (*new)->cntxt = cont;
+    (*new)->is_owner = 1;
 
     /* register the cleanup... */
-    apr_pool_cleanup_register((*new)->cntxt, (void*)(*new), mmap_cleanup,
+    apr_pool_cleanup_register((*new)->cntxt, (void*)(*new), apr_mmap_cleanup,
                          apr_pool_cleanup_null);
     return APR_SUCCESS;
 }
 
+APR_DECLARE(apr_status_t) apr_mmap_dup(apr_mmap_t **new_mmap,
+                                       apr_mmap_t *old_mmap,
+                                       apr_pool_t *p,
+                                       int transfer_ownership)
+{
+    *new_mmap = (apr_mmap_t *)apr_palloc(p, sizeof(apr_mmap_t));
+    memcpy(*new_mmap, old_mmap, sizeof(apr_mmap_t));
+    (*new_mmap)->cntxt = p;
+
+    /* The old_mmap can transfer ownership only if the old_mmap itself
+     * is an owner of the mmap'ed segment.
+     */
+    if (old_mmap->is_owner) {
+        if (transfer_ownership) {
+            (*new_mmap)->is_owner = 1;
+            old_mmap->is_owner = 0;
+            apr_pool_cleanup_kill(old_mmap->cntxt, old_mmap, mmap_cleanup);
+        }
+        else {
+            (*new_mmap)->is_owner = 0;
+        }
+        apr_pool_cleanup_register(p, *new_mmap, mmap_cleanup,
+                                  apr_pool_cleanup_null);
+    }
+    return APR_SUCCESS;
+}
+
 APR_DECLARE(apr_status_t) apr_mmap_delete(apr_mmap_t *mmap)
 {
     apr_status_t rv;
 
-    if ((rv = mmap_cleanup(mmap)) == APR_SUCCESS) {
-        apr_pool_cleanup_kill(mmap->cntxt, mmap, mmap_cleanup);
+    if ((rv = apr_mmap_cleanup(mmap)) == APR_SUCCESS) {
+        apr_pool_cleanup_kill(mmap->cntxt, mmap, apr_mmap_cleanup);
         return APR_SUCCESS;
     }
     return rv;
Index: srclib/apr-util/buckets/apr_buckets_mmap.c
===================================================================
RCS file: /home/cvspublic/apr-util/buckets/apr_buckets_mmap.c,v
retrieving revision 1.43
diff -u -r1.43 apr_buckets_mmap.c
--- srclib/apr-util/buckets/apr_buckets_mmap.c  2001/09/22 22:36:07     1.43
+++ srclib/apr-util/buckets/apr_buckets_mmap.c  2001/11/15 05:45:58
@@ -121,24 +121,18 @@
 {
     apr_bucket_mmap *m = data->data;
     apr_mmap_t *mm = m->mmap;
-    char *base;
-    void *addr;
+    apr_mmap_t *new_mm;
     apr_status_t ok;
 
     if (apr_pool_is_ancestor(mm->cntxt, p)) {
         return APR_SUCCESS;
     }
 
-    ok = apr_mmap_offset(&addr, m->mmap, data->start);
+    ok = apr_mmap_dup(&new_mm, mm, p, 1);
     if (ok != APR_SUCCESS) {
         return ok;
     }
-
-    base = apr_palloc(p, data->length);
-    memcpy(base, addr, data->length);
-    data = apr_bucket_pool_make(data, base, data->length, p);
-    mmap_destroy(m);
-
+    m->mmap = new_mm;
     return APR_SUCCESS;
 }
 
Index: modules/cache/mod_file_cache.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/cache/mod_file_cache.c,v
retrieving revision 1.62
diff -u -r1.62 mod_file_cache.c
--- modules/cache/mod_file_cache.c      2001/08/11 04:04:12     1.62
+++ modules/cache/mod_file_cache.c      2001/11/15 05:45:58
@@ -333,8 +333,20 @@
 #if APR_HAS_MMAP
     apr_bucket *b;
     apr_bucket_brigade *bb = apr_brigade_create(r->pool);
+    apr_mmap_t *mm;
 
-    b = apr_bucket_mmap_create(file->mm, 0, (apr_size_t)file->finfo.size);
+    /* Create a copy of the apr_mmap_t that's marked as
+     * a "non-owner."  The reason for this is that the
+     * mmap bucket setaside function might later try to
+     * transfer ownership of the mmap from a request
+     * pool to a parent pool.  For this particular mmap,
+     * though, we want the cache to retain ownership so
+     * that it never gets munmapped.  Thus we give the
+     * bucket code a non-owner copy to work with.
+     */
+    apr_mmap_dup(&mm, file->mm, r->pool, 0);
+
+    b = apr_bucket_mmap_create(mm, 0, (apr_size_t)file->finfo.size);
     APR_BRIGADE_INSERT_TAIL(bb, b);
     b = apr_bucket_eos_create();
     APR_BRIGADE_INSERT_TAIL(bb, b);

Reply via email to