Date: 01/24/99
- Next message: Egon Schmid: "Re: [PHP-DEV] [PATCH] Shared Memory Pools ;-) (fwd)"
- Previous message: ryan <email protected>: "[PHP-DEV] Bug #1090: Sybase persistent connections can't handle server restart"
- Next in thread: Egon Schmid: "Re: [PHP-DEV] [PATCH] Shared Memory Pools ;-) (fwd)"
- Reply: Egon Schmid: "Re: [PHP-DEV] [PATCH] Shared Memory Pools ;-) (fwd)"
- Maybe reply: Zeev Suraski: "Re: [PHP-DEV] [PATCH] Shared Memory Pools ;-) (fwd)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
---------- Forwarded message ----------
Date: Sun, 24 Jan 1999 13:49:12 +0100
From: Ralf S. Engelschall <rse <email protected>>
Reply-To: new-httpd <email protected>
To: Apache Group Developer ML <new-httpd <email protected>>
Subject: [PHP-DEV] [PATCH] Shared Memory Pools ;-)
Shared Memory Pools
===================
This is a patch against 1.3.5-dev (should also apply cleanly against 1.3.4)
which adds support for shared memory based sub-pools to allow module authors
easily shared data across httpd processes.
Background
----------
Since years I was annoyed of the fact that our pre-forked process model
basically means that every server lives it's own life (= address space) and
this way module authors cannot easily spread module configuration or other
data accross the processes. For most of the modules that's no real problem.
But it gets nasty when you want to write for instance a mod_traffic which
counts in real-time the traffic of Apache. Or a mod_bandwidth which thottles
the total used bandwidth of Apache.
Or as in my case for mod_ssl 2.2: You just want to have a fast inter-process
session cache without the need for an external cache process or filesystem
database. Additionally I want to display global SSL engine statistics in
mod_status' HTML page. For all these things you either give up yourself, hack
your code into the scoreboard or fiddle around yourself with the gory details
of portable shared memory handling. All three things are nasty: giving up is
not acceptable, hacking the scoreboard is ugly and un-flexible (you have to
reserve a fixed size of memory space) and fiddling around with shared memory
details is horrible when you've to do it for every module.
Idea and Proposed Solution
--------------------------
My idea now was this:
1. Abstract the shared memory and memory mutex fiddling into a low-level API.
Internally the shared memory and mutex functionality is implemented in
various platform-depended ways: 4.4BSD or POSIX.1 anonymous memory mapping,
/dev/zero-based memory mapping, temporary file memory mapping, or SysV IPC
shared memory for allocating the shared memory areas and POSIX.1 fcntl(2),
BSD flock(2) or SysV IPC semaphores for implementing mutual exclusion
capabilities.
2. Write a high-level malloc()-style API based on this abstracted
shared memory low-level API. The idea is just to allocate the requested
memory chunks from shared memory segments instead of the heap.
3. Use the high-level malloc()-style API in our Apache pool
mechanism in addition to the heap-based malloc(). Because this way the
module authors can also use all the ap_pxxx() functions, even when they now
work with shared memory.
The first cut for achieving these three points is this patch. It implements
all three things. (APIs 1 and 2 are staying inside an ap/ap_mm.c because they
are Apache independent and API 3 is patched into main/alloc.c).
What new functionality do we gain?
----------------------------------
At the module author level we now just have three additional functions:
ap_make_shared_sub_pool()
ap_acquire_pool()
ap_release_pool()
The ap_make_shared_sub_pool() is similar to ap_make_sub_pool() but instead of
allocating the pool inside a heap-area it's allocated inside a larger shared
memory segment. Anything else remains the same, i.e. the returned `pool *' can
be used as usual. The ap_acquire_pool() and ap_release_pool() can be used for
mutual exclusion operations on the pool.
Example
-------
Here is an example mod_test.c which does nothing more than writing out a page
on every request containing a silly access counter.
| /*
| ** mod_test.c -- Apache sample module for shared pools
| */
|
| #include "httpd.h"
| #include "http_config.h"
| #include "http_protocol.h"
|
| typedef struct {
| int counter;
| } SharedRec;
|
| static pool *sp = NULL; /* The shared pool */
| static SharedRec *sr = NULL; /* The shared record in the pool */
|
| static void init(server_rec *s, pool *p)
| {
| sp = ap_make_shared_sub_pool(p);
| sr = ap_palloc(sp, sizeof(SharedRec));
| sr->counter = 1;
| }
|
| static int handler(request_rec *r)
| {
| r->content_type = "text/html";
| ap_send_http_header(r);
| if (!r->header_only) {
| ap_rputs("The sample page from mod_test\n", r);
| ap_acquire_pool(sp);
| ap_rprintf(r, "We were called %d times up to now.\n", sr->counter++);
| ap_release_pool(sp);
| }
| return OK;
| }
|
| static const handler_rec handlers[] = {
| { "test", handler },
| { NULL, NULL }
| };
|
| module MODULE_VAR_EXPORT test_module = {
| STANDARD_MODULE_STUFF,
| init, NULL, NULL, NULL, NULL, NULL,
| handlers, NULL, NULL, NULL, NULL, NULL,
| NULL, NULL, NULL, NULL, NULL, NULL
| };
Feedback?
Ralf S. Engelschall
rse <email protected>
www.engelschall.com
Index: src/ap/Makefile.tmpl
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/ap/Makefile.tmpl,v
retrieving revision 1.31
diff -u -r1.31 Makefile.tmpl
--- src/ap/Makefile.tmpl 1999/01/12 15:47:04 1.31
+++ src/ap/Makefile.tmpl 1999/01/24 12:16:47
@@ -6,7 +6,7 @@
LIB=libap.a
OBJS=ap_execve.o ap_cpystrn.o ap_signal.o \
- ap_slack.o ap_snprintf.o ap_fnmatch.o ap_md5c.o
+ ap_slack.o ap_snprintf.o ap_fnmatch.o ap_md5c.o ap_mm.o
.c.o:
$(CC) -c $(INCLUDES) $(CFLAGS) $<
Index: src/ap/ap_mm.c
===================================================================
RCS file: ap_mm.c
diff -N ap_mm.c
--- /dev/null Sun Jan 24 13:23:07 1999
+++ ap_mm.c Sun Jan 24 13:03:54 1999
@@ -0,0 +1,915 @@
+/* ====================================================================
+ * Copyright (c) 1999 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse <email protected>>."
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse <email protected>>."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/*
+**
+** ap_mm.c -- Shared Memory Library
+**
+*/
+
+#define MM_PRIVATE
+#include "ap_mm.h"
+
+#if !defined(MM_NA)
+
+/*
+**
+** Low-Level Shared Memory API
+**
+*/
+
+/*
+ * Some global variables
+ */
+
+#if defined(MM_SEMT_FCNTL)
+/* lock/unlock structures for fcntl() */
+static struct flock mm_core_dolock;
+static struct flock mm_core_dounlock;
+#endif
+
+#if defined(MM_SEMT_IPCSEM)
+/* lock/unlock structures for semop() */
+static struct sembuf mm_core_dolock[] = {
+ { 0, 0, 0 }, /* wait for semaphore */
+ { 0, 1, SEM_UNDO } /* increment semaphore */
+};
+static struct sembuf mm_core_dounlock[] = {
+ { 0, -1, SEM_UNDO } /* derements semaphore */
+};
+#endif
+
+#if defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE)
+/* mapping offset for mmap() */
+static int mm_core_mmap_offset = 0;
+#endif
+
+static void mm_core_init(void)
+{
+ static int initialized = FALSE;
+ if (!initialized) {
+#if defined(MM_SEMT_FCNTL)
+ mm_core_dolock.l_whence = SEEK_SET; /* from current point */
+ mm_core_dolock.l_start = 0; /* -"- */
+ mm_core_dolock.l_len = 0; /* until end of file */
+ mm_core_dolock.l_type = F_WRLCK; /* set exclusive/write lock */
+ mm_core_dolock.l_pid = 0; /* pid not actually interesting */
+ mm_core_dounlock.l_whence = SEEK_SET; /* from current point */
+ mm_core_dounlock.l_start = 0; /* -"- */
+ mm_core_dounlock.l_len = 0; /* until end of file */
+ mm_core_dounlock.l_type = F_UNLCK; /* unlock */
+ mm_core_dounlock.l_pid = 0; /* pid not actually interesting */
+#endif
+ initialized = TRUE;
+ }
+ return;
+}
+
+#if defined(MM_SEMT_FLOCK)
+/*
+ * Determine per-process fd for semaphore
+ * (needed only for flock() based semaphore)
+ */
+static int mm_core_getfdsem(mem_core *mc)
+{
+ int fd = -1;
+ pid_t pid;
+ int i;
+
+ pid = getpid();
+ for (i = 0; i < MM_MAXCHILD &&
+ mc->mc_fdsem[i].pid != 0 &&
+ mc->mc_fdsem[i].fd != -1; i++) {
+ if (mc->mc_fdsem[i].pid == pid) {
+ fd = mc->mc_fdsem[i].fd;
+ break;
+ }
+ }
+ if (fd == -1 && i < MM_MAXCHILD) {
+ fd = open(mc->mc_fnsem, O_WRONLY, MM_CORE_FILEMODE);
+ mc->mc_fdsem[i].pid = getpid();
+ mc->mc_fdsem[i].fd = fd;
+ }
+ return fd;
+}
+#endif /* MM_SEMT_FLOCK */
+
+/*
+ * Determine memory page size of OS
+ */
+
+static size_t mm_core_pagesize(void)
+{
+ static int pagesize = 0;
+ if (pagesize == 0)
+#if defined(MM_VMPS_GETPAGESIZE)
+ pagesize = getpagesize();
+#elif defined(MM_VMPS_SYSCONF)
+ pagesize = sysconf(_SC_PAGESIZE);
+#else
+ pagesize = MM_DEFAULT_PAGESIZE;
+#endif
+ return pagesize;
+}
+
+/*
+ * Align a size to the next page or word boundary
+ */
+
+size_t mm_core_align2page(size_t size)
+{
+ int psize = mm_core_pagesize();
+ return ((size)%(psize) > 0 ? ((size)/(psize)+1)*(psize) : (size));
+}
+
+size_t mm_core_align2word(size_t size)
+{
+ return ((1+((size-1) / SIZEOF_mem_word)) * SIZEOF_mem_word);
+}
+
+/*
+ * Create a shared memory area
+ */
+
+void *mm_core_create(size_t usersize, char *file)
+{
+ mem_core *mc;
+ void *area = ((void *)-1);
+ int fdmem = 0;
+ int fdsem = 0;
+#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
+ char *fnmem;
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ char *fnsem;
+#endif
+ size_t size;
+#if defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMPOSIX) || defined(MM_SHMT_MMFILE)
+ int zero = 0;
+#endif
+#if defined(MM_SHMT_IPCSHM)
+ struct shmid_ds shmbuf;
+#endif
+#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
+ char shmfilename[MM_MAXPATH];
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ char semfilename[MM_MAXPATH];
+#endif
+ char filename[MM_MAXPATH];
+
+ mm_core_init();
+ if (usersize == 0)
+ usersize = MM_DEFAULT_SIZE;
+ if (file == NULL) {
+ sprintf(filename, MM_DEFAULT_FILE, (int)getpid());
+ file = filename;
+ }
+ size = mm_core_align2page(usersize+SIZEOF_mem_core);
+
+#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
+ sprintf(shmfilename, "%s.mem", file);
+ fnmem = shmfilename;
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ sprintf(semfilename, "%s.sem", file);
+ fnsem = semfilename;
+#endif
+
+#if defined(MM_SHMT_MMANON)
+ if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_SHARED, -1, 0)) == ((void *)-1))
+ FAIL;
+#endif /* MM_SHMT_MMANON */
+
+#if defined(MM_SHMT_MMPOSX)
+ shm_unlink(fnmem); /* Ok when it fails */
+ if ((fdmem = shm_open(fnmem, O_RDWR, MM_CORE_FILEMODE)) == -1)
+ FAIL;
+ if (ftruncate(fdmem, sizeof(mem_core)) == -1)
+ FAIL;
+ write(fdmem, &zero, sizeof(zero));
+ if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, fdmem, 0)) == ((void *)-1))
+ FAIL;
+ shm_unlink(fnmem);
+#endif /* MM_SHMT_MMPOSX */
+
+#if defined(MM_SHMT_MMZERO)
+ if ((fdmem = open("/dev/zero", O_RDWR, MM_CORE_FILEMODE)) == -1)
+ FAIL;
+ if (ftruncate(fdmem, mm_core_mmap_offset+sizeof(mem_core)) == -1)
+ FAIL;
+ write(fdmem, &zero, sizeof(zero));
+ if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, fdmem, mm_core_mmap_offset)) == ((void *)-1))
+ FAIL;
+ mm_core_mmap_offset += size;
+#endif /* MM_SHMT_MMZERO */
+
+#if defined(MM_SHMT_MMFILE)
+ unlink(fnmem);
+ if ((fdmem = open(fnmem, O_RDWR|O_CREAT, MM_CORE_FILEMODE)) == -1)
+ FAIL;
+ if (ftruncate(fdmem, mm_core_mmap_offset+sizeof(mem_core)) == -1)
+ FAIL;
+ write(fdmem, &zero, sizeof(zero));
+ if ((area = (void *)mmap(NULL, size, PROT_READ|PROT_WRITE,
+ MAP_SHARED, fdmem, mm_core_mmap_offset)) == ((void *)-1))
+ FAIL;
+ mm_core_mmap_offset += size;
+#endif /* MM_SHMT_MMFILE */
+
+#if defined(MM_SHMT_IPCSHM)
+ if ((fdmem = shmget(IPC_PRIVATE, size, (SHM_R|SHM_W|IPC_CREAT))) == -1)
+ FAIL;
+ if ((area = (void *)shmat(fdmem, NULL, 0)) == ((void *)-1))
+ FAIL;
+ if (shmctl(fdmem, IPC_STAT, &shmbuf) == -1)
+ FAIL;
+ shmbuf.shm_perm.uid = getuid();
+ shmbuf.shm_perm.gid = getgid();
+ if (shmctl(fdmem, IPC_SET, &shmbuf) == -1)
+ FAIL;
+ if (shmctl(fdmem, IPC_RMID, NULL) == -1)
+ FAIL;
+#endif /* MM_SHMT_IPCSHM */
+
+#if defined(MM_SEMT_FLOCK)
+ unlink(fnsem);
+ if ((fdsem = open(fnsem, O_WRONLY|O_CREAT, MM_CORE_FILEMODE)) == -1)
+ return NULL;
+#endif /* MM_SEMT_FLOCK */
+
+#if defined(MM_SEMT_FCNTL)
+ unlink(fnsem);
+ if ((fdsem = open(fnsem, O_WRONLY|O_CREAT, MM_CORE_FILEMODE)) == -1)
+ return NULL;
+#endif /* MM_SEMT_FCNTL */
+
+#if defined(MM_SEMT_IPCSEM)
+ fdsem = semget(IPC_PRIVATE, 1, (IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR));
+ if (fdsem == -1 && errno == EEXIST)
+ fdsem = semget(IPC_PRIVATE, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
+ if (fdsem == -1)
+ FAIL;
+#endif /* MM_SEMT_IPCSEM */
+
+ /*
+ * Configure the memory core parameters
+ */
+ mc = (mem_core *)area;
+ mc->mc_size = size;
+ mc->mc_usize = usersize;
+ mc->mc_pid = getpid();
+ mc->mc_fdmem = fdmem;
+#if defined(MM_SEMT_FLOCK)
+ mc->mc_fdsem[0].pid = getpid();
+ mc->mc_fdsem[0].fd = fdsem;
+ mc->mc_fdsem[1].pid = 0;
+ mc->mc_fdsem[1].fd = -1;
+#else
+ mc->mc_fdsem = fdsem;
+#endif
+#if defined(MM_SHMT_MMFILE)
+ memcpy(mc->mc_fnmem, fnmem, MM_MAXPATH);
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ memcpy(mc->mc_fnsem, fnsem, MM_MAXPATH);
+#endif
+
+ /*
+ * Return successfully established core
+ */
+ return ((void *)&(mc->mc_base.mw_cp));
+
+ /*
+ * clean-up sequence (CUS) for error situation
+ */
+ BEGIN_FAILURE
+#if defined(MM_SHMT_MMANON) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMPOSIX) || defined(MM_SHMT_MMFILE)
+ if (area != ((void *)-1))
+ munmap((caddr_t)area, size);
+#endif
+#if defined(MM_SHMT_IPCSHM)
+ if (area != ((void *)-1))
+ shmdt(area);
+#endif
+#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMFILE)
+ if (fdmem != -1)
+ close(fdmem);
+#endif
+#if defined(MM_SHMT_IPCSHM)
+ if (fdmem != -1)
+ shmctl(fdmem, IPC_RMID, NULL);
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ if (fdsem != -1)
+ close(fdsem);
+#endif
+#if defined(MM_SEMT_IPCSEM)
+ if (fdsem != -1)
+ semctl(fdsem, 0, IPC_RMID, 0);
+#endif
+#if defined(MM_SHMT_MMFILE)
+ unlink(fnmem);
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ unlink(fnsem);
+#endif
+ return NULL;
+ END_FAILURE
+}
+
+void mm_core_delete(void *core)
+{
+ mem_core *mc;
+ int fdmem;
+ int fdsem;
+ size_t size;
+#if defined(MM_SHMT_MMFILE)
+ char fnmem[MM_MAXPATH];
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ char fnsem[MM_MAXPATH];
+#endif
+
+ if (core == NULL)
+ return;
+ mc = (mem_core *)((char *)core-SIZEOF_mem_core);
+ size = mc->mc_size;
+ fdmem = mc->mc_fdmem;
+#if !defined(MM_SEMT_FLOCK)
+ fdsem = mc->mc_fdsem;
+#endif
+#if defined(MM_SEMT_FLOCK)
+ fdsem = mm_core_getfdsem(mc);
+#endif
+#if defined(MM_SHMT_MMFILE)
+ memcpy(fnmem, mc->mc_fnmem, MM_MAXPATH);
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ memcpy(fnsem, mc->mc_fnsem, MM_MAXPATH);
+#endif
+
+#if defined(MM_SHMT_MMANON) || defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE)
+ munmap((caddr_t)mc, size);
+#endif
+#if defined(MM_SHMT_IPCSHM)
+ shmdt((void *)mc);
+ shmctl(fdmem, IPC_RMID, NULL);
+#endif
+#if defined(MM_SHMT_MMPOSX) || defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE)
+ close(fdmem);
+#endif
+#if defined(MM_SHMT_MMFILE)
+ unlink(fnmem);
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ close(fdsem);
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ unlink(fnsem);
+#endif
+#if defined(MM_SEMT_IPCSEM)
+ semctl(fdsem, 0, IPC_RMID, 0);
+#endif
+ return;
+}
+
+size_t mm_core_size(void *core)
+{
+ mem_core *mc;
+
+ if (core == NULL)
+ return 0;
+ mc = (mem_core *)((char *)core-SIZEOF_mem_core);
+ return (mc->mc_usize);
+}
+
+int mm_core_lock(void *core)
+{
+ mem_core *mc;
+ int rc;
+ int fdsem;
+
+ if (core == NULL)
+ return FALSE;
+ mc = (mem_core *)((char *)core-SIZEOF_mem_core);
+#if !defined(MM_SEMT_FLOCK)
+ fdsem = mc->mc_fdsem;
+#endif
+#if defined(MM_SEMT_FLOCK)
+ fdsem = mm_core_getfdsem(mc);
+#endif
+
+#if defined(MM_SEMT_FCNTL)
+ errno = 0;
+ while (((rc = fcntl(fdsem, F_SETLKW, &mm_core_dolock)) < 0) && (errno == EINTR)) ;
+#endif
+#if defined(MM_SEMT_FLOCK)
+ errno = 0;
+ while (((rc = flock(fdsem, LOCK_EX)) < 0) && (errno == EINTR)) ;
+#endif
+#if defined(MM_SEMT_IPCSEM)
+ errno = 0;
+ while (((rc = semop(fdsem, mm_core_dolock, 2) < 0) && (errno == EINTR)) ;
+#endif
+ if (rc < 0)
+ rc = FALSE;
+ else
+ rc = TRUE;
+ return rc;
+}
+
+int mm_core_unlock(void *core)
+{
+ mem_core *mc;
+ int rc;
+ int fdsem;
+
+ if (core == NULL)
+ return FALSE;
+ mc = (mem_core *)((char *)core-SIZEOF_mem_core);
+#if !defined(MM_SEMT_FLOCK)
+ fdsem = mc->mc_fdsem;
+#endif
+#if defined(MM_SEMT_FLOCK)
+ fdsem = mm_core_getfdsem(mc);
+#endif
+
+#if defined(MM_SEMT_FCNTL)
+ errno = 0;
+ while (((rc = fcntl(fdsem, F_SETLKW, &mm_core_dounlock)) < 0) && (errno == EINTR)) ;
+#endif
+#if defined(MM_SEMT_FLOCK)
+ errno = 0;
+ while (((rc = flock(fdsem, LOCK_UN)) < 0) && (errno == EINTR)) ;
+#endif
+#if defined(MM_SEMT_IPCSEM)
+ errno = 0;
+ while (((rc = semop(fdsem, mm_core_dounlock, 1) < 0) && (errno == EINTR)) ;
+#endif
+ if (rc < 0)
+ rc = FALSE;
+ else
+ rc = TRUE;
+ return rc;
+}
+
+
+/*
+**
+** Standard Malloc-Style API
+**
+*/
+
+/*
+ * Create a memory pool
+ */
+MM *mm_create(size_t usize, char *file)
+{
+ MM *mm = NULL;
+ void *core;
+ size_t size;
+
+ /* defaults */
+ if (usize < 0)
+ return NULL;
+ if (usize == 0)
+ usize = MM_DEFAULT_SIZE;
+ if (usize <= MM_CORE_MINSIZE)
+ usize = MM_CORE_MINSIZE;
+
+ /* determine size */
+ size = mm_core_align2page(usize+SIZEOF_mem_pool);
+
+ /* get a shared memory area */
+ if ((core = mm_core_create(size, file)) == NULL)
+ return NULL;
+
+ /* fill in the memory pool structure */
+ mm = (MM *)core;
+ mm->mp_size = size;
+ mm->mp_offset = SIZEOF_mem_pool;
+
+ /* first element of list of free chunks counts existing chunks */
+ mm->mp_freechunks.mc_size = 0;
+ mm->mp_freechunks.mc_usize = 0;
+ mm->mp_freechunks.mc_u.mc_next = NULL;
+
+ return mm;
+}
+
+/*
+ * Destroy a memory pool
+ */
+void mm_destroy(MM *mm)
+{
+ if (mm == NULL)
+ return;
+ /* wipe out the whole area to be safe */
+ memset(mm, 0, mm->mp_size);
+ /* and delete the core area */
+ (void)mm_core_delete((void *)mm);
+ return;
+}
+
+int mm_lock(MM *mm)
+{
+ if (mm == NULL);
+ return NULL;
+ return mm_core_lock((void *)mm);
+}
+
+int mm_unlock(MM *mm)
+{
+ if (mm == NULL);
+ return NULL;
+ return mm_core_unlock((void *)mm);
+}
+
+
+/*
+ * Display debugging information
+ */
+#if defined(MM_DEBUG)
+void mm_display_info(MM *mm)
+{
+ mem_chunk *mc;
+ int nFree;
+ int nAlloc;
+ int i;
+
+ mm_core_lock((void *)mm);
+ mc = &(mm->mp_freechunks);
+ nFree = 0;
+ while (mc->mc_u.mc_next != NULL) {
+ mc = mc->mc_u.mc_next;
+ nFree += mc->mc_size;
+ }
+ nAlloc = mm->mp_offset-SIZEOF_mem_pool-nFree;
+
+ fprintf(stderr, "Information for MM\n");
+ fprintf(stderr, " memory area = 0x%x - 0x%x\n", (unsigned int)mm, (unsigned int)mm+mm->mp_size);
+ fprintf(stderr, " memory size = %d\n", mm->mp_size);
+ fprintf(stderr, " memory offset = %d\n", mm->mp_offset);
+ fprintf(stderr, " bytes spare = %d\n", mm->mp_size-mm->mp_offset);
+ fprintf(stderr, " bytes free = %d (%d chunk%s)\n",
+ nFree, mm->mp_freechunks.mc_usize,
+ mm->mp_freechunks.mc_usize == 1 ? "" : "s");
+ fprintf(stderr, " bytes allocated = %d\n", nAlloc);
+
+ fprintf(stderr, " List of free chunks:\n");
+ if (mm->mp_freechunks.mc_usize > 0) {
+ mc = &(mm->mp_freechunks);
+ i = 0;
+ while (mc->mc_u.mc_next != NULL) {
+ mc = mc->mc_u.mc_next;
+ fprintf(stderr, " chunk #%03d: 0x%x-0x%x (%d bytes)\n",
+ i, (unsigned int)mc, (unsigned int)mc+mc->mc_size, mc->mc_size);
+ }
+ }
+ else
+ fprintf(stderr, " <empty-list>\n"),
+ mm_core_unlock((void *)mm);
+ return;
+}
+#endif
+
+/*
+ * Insert a chunk to the list of free chunks. Algorithm used is:
+ * Insert in sorted manner to the list and merge with previous
+ * and/or next chunk when possible to form larger chunks out of
+ * smaller ones.
+ */
+static void mm_insert_chunk(MM *mm, mem_chunk *mcInsert)
+{
+ mem_chunk *mc;
+ mem_chunk *mcPrev;
+ mem_chunk *mcNext;
+
+ mm_core_lock((void *)mm);
+ mc = &(mm->mp_freechunks);
+ while (mc->mc_u.mc_next != NULL && (char *)(mc->mc_u.mc_next) < (char *)mcInsert)
+ mc = mc->mc_u.mc_next;
+ mcPrev = mc;
+ mcNext = mc->mc_u.mc_next;
+ if ((char *)mcPrev+mcPrev->mc_size == (char *)mcInsert &&
+ (mcNext != NULL && (char *)mcInsert+mcInsert->mc_size == (char *)mcNext)) {
+ /* merge with previous and next chunk */
+ mcPrev->mc_size += mcInsert->mc_size + mcNext->mc_size;
+ mcPrev->mc_u.mc_next = mcNext->mc_u.mc_next;
+ mm->mp_freechunks.mc_usize -= 1;
+ }
+ else if ((char *)mcPrev+mcPrev->mc_size == (char *)mcInsert) {
+ /* merge with previous chunk */
+ mcPrev->mc_size += mcInsert->mc_size;
+ }
+ else if (mcNext != NULL && (char *)mcInsert+mcInsert->mc_size == (char *)mcNext) {
+ /* merge with next chunk */
+ mcInsert->mc_size += mcNext->mc_size;
+ mcInsert->mc_u.mc_next = mcNext->mc_u.mc_next;
+ mcPrev->mc_u.mc_next = mcInsert;
+ }
+ else {
+ /* no merging possible, so insert as new chunk */
+ mcInsert->mc_u.mc_next = mcNext;
+ mcPrev->mc_u.mc_next = mcInsert;
+ mm->mp_freechunks.mc_usize += 1;
+ }
+ mm_core_unlock((void *)mm);
+ return;
+}
+
+/*
+ * Retrieve a chunk from the list of free chunks. Algorithm used
+ * is: Search for minimal-sized chunk which is larger or equal
+ * than the request size. But when the retrieved chunk is still a
+ * lot larger than the requested size, split out the requested
+ * size to not waste memory.
+ */
+static mem_chunk *mm_retrieve_chunk(MM *mm, size_t size)
+{
+ mem_chunk *mc;
+ mem_chunk *mcMinLast;
+ mem_chunk *mcMin;
+ size_t sMin;
+ size_t s;
+
+ if (mm->mp_freechunks.mc_usize == 0)
+ return NULL;
+ mm_core_lock((void *)mm);
+ mc = &(mm->mp_freechunks);
+ mcMinLast = mc;
+ mcMin = NULL;
+ sMin = mm->mp_size; /* maximum possible */
+ while (mc->mc_u.mc_next != NULL) {
+ mc = mc->mc_u.mc_next;
+ if (mc->mc_size >= size && mc->mc_size < sMin) {
+ mcMin = mc;
+ sMin = mc->mc_size;
+ }
+ mcMinLast = mc;
+ }
+ if (mcMin != NULL) {
+ if (mcMin->mc_size > size+1024) {
+ /* split out in part */
+ s = mcMin->mc_size - size;
+ mcMin->mc_size = size;
+
+ /* add back remaining chunk part as new chunk */
+ mc = (mem_chunk *)((char *)mcMin + size);
+ mc->mc_size = s;
+ mc->mc_u.mc_next = mcMin->mc_u.mc_next;
+ mcMinLast->mc_u.mc_next = mc;
+ }
+ else {
+ /* split out as a whole */
+ mcMinLast->mc_u.mc_next = mcMin->mc_u.mc_next;
+ mm->mp_freechunks.mc_usize--;
+ }
+ }
+ mm_core_unlock((void *)mm);
+ return mcMin;
+}
+
+/*
+ * Allocate a chunk of memory
+ */
+void *mm_malloc(MM *mm, size_t usize)
+{
+ mem_chunk *mc;
+ size_t size;
+ void *vp;
+
+ if (mm == NULL || usize == 0)
+ return NULL;
+ size = mm_core_align2word(SIZEOF_mem_chunk+usize);
+ if ((mc = mm_retrieve_chunk(mm, size)) != NULL) {
+ mc->mc_usize = usize;
+ return mc;
+ }
+ if ((mm->mp_size - mm->mp_offset) < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ mc = (mem_chunk *)((char *)mm + mm->mp_offset);
+ mc->mc_size = size;
+ mc->mc_usize = usize;
+ vp = (void *)&(mc->mc_u.mc_base.mw_cp);
+ mm->mp_offset += size;
+ return vp;
+}
+
+/*
+ * Reallocate a chunk of memory
+ */
+void *mm_realloc(MM *mm, void *ptr, size_t usize)
+{
+ size_t size;
+ mem_chunk *mc;
+ void *vp;
+
+ if (mm == NULL || usize == 0)
+ return NULL;
+ if (ptr == NULL)
+ return mm_malloc(mm, usize); /* POSIX.1 semantics */
+ mc = (mem_chunk *)((char *)ptr - SIZEOF_mem_chunk);
+ if (usize <= mc->mc_usize) {
+ mc->mc_usize = usize;
+ return ptr;
+ }
+ size = mm_core_align2word(SIZEOF_mem_chunk+usize);
+ if (size <= mc->mc_size) {
+ mc->mc_usize = usize;
+ return ptr;
+ }
+ if ((vp = mm_malloc(mm, usize)) == NULL)
+ return NULL;
+ memcpy(vp, ptr, usize);
+ mm_free(mm, ptr);
+ return vp;
+}
+
+/*
+ * Free a chunk of memory
+ */
+void mm_free(MM *mm, void *ptr)
+{
+ mem_chunk *mc;
+
+ if (mm == NULL || ptr == NULL)
+ return;
+ mc = (mem_chunk *)((char *)ptr - SIZEOF_mem_chunk);
+ mm_insert_chunk(mm, mc);
+ return;
+}
+
+/*
+ * Allocate and initialize a chunk of memory
+ */
+void *mm_calloc(MM *mm, size_t number, size_t usize)
+{
+ void *vp;
+
+ if (mm == NULL || number*usize == 0)
+ return NULL;
+ if ((vp = mm_malloc(mm, number*usize)) == NULL)
+ return NULL;
+ memset(vp, 0, number*usize);
+ return vp;
+}
+
+/*
+ * Duplicate a string
+ */
+char *mm_strdup(MM *mm, const char *str)
+{
+ int n;
+ void *vp;
+
+ if (mm == NULL || str == NULL)
+ return NULL;
+ n = strlen(str);
+ if ((vp = mm_malloc(mm, n+1)) == NULL)
+ return NULL;
+ memcpy(vp, str, n+1);
+ return vp;
+}
+
+/*
+ * Determine user size of a memory chunk
+ */
+size_t mm_sizeof(MM *mm, void *ptr)
+{
+ mem_chunk *mc;
+
+ if (mm == NULL || ptr == NULL)
+ return -1;
+ mc = (mem_chunk *)((char *)ptr - SIZEOF_mem_chunk);
+ return mc->mc_usize;
+}
+
+/*
+**
+** Global Malloc-Replacement API
+**
+*/
+
+static MM *mm_global = NULL;
+
+int MM_create(void)
+{
+ if (mm_global != NULL)
+ return FALSE;
+ if ((mm_global = mm_create(0, NULL)) == NULL)
+ return FALSE;
+ return TRUE;
+}
+
+void MM_destroy(void)
+{
+ if (mm_global == NULL)
+ return;
+ mm_destroy(mm_global);
+ mm_global = NULL;
+ return;
+}
+
+int MM_lock(void)
+{
+ if (mm_global == NULL)
+ return NULL;
+ return mm_lock(mm_global);
+}
+
+int MM_unlock(void)
+{
+ if (mm_global == NULL)
+ return NULL;
+ return mm_unlock(mm_global);
+}
+
+
+void *MM_malloc(size_t size)
+{
+ if (mm_global == NULL)
+ return NULL;
+ return mm_malloc(mm_global, size);
+}
+
+void *MM_realloc(void *ptr, size_t size)
+{
+ if (mm_global == NULL)
+ return NULL;
+ return mm_realloc(mm_global, ptr, size);
+}
+
+void MM_free(void *ptr)
+{
+ if (mm_global == NULL)
+ return;
+ mm_free(mm_global, ptr);
+ return;
+}
+
+void *MM_calloc(size_t number, size_t size)
+{
+ if (mm_global == NULL)
+ return NULL;
+ return mm_calloc(mm_global, number, size);
+}
+
+char *MM_strdup(const char *str)
+{
+ if (mm_global == NULL)
+ return NULL;
+ return mm_strdup(mm_global, str);
+}
+
+size_t MM_sizeof(void *ptr)
+{
+ if (mm_global == NULL)
+ return -1;
+ return mm_sizeof(mm_global, ptr);
+}
+
+#endif /* MM_NA */
Index: src/include/alloc.h
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/include/alloc.h,v
retrieving revision 1.66
diff -u -r1.66 alloc.h
--- src/include/alloc.h 1999/01/03 12:04:36 1.66
+++ src/include/alloc.h 1999/01/24 12:14:06
@@ -91,8 +91,15 @@
typedef struct pool pool;
typedef struct pool ap_pool;
+#ifndef MM_NA
+#define AP_SHARED_POOL
+#endif
+
pool * ap_init_alloc(void); /* Set up everything */
API_EXPORT(pool *) ap_make_sub_pool(pool *); /* All pools are subpools of permanent_pool */
+API_EXPORT(pool *) ap_make_shared_sub_pool(pool *);
+API_EXPORT(int) ap_acquire_pool(pool *);
+API_EXPORT(int) ap_release_pool(pool *);
API_EXPORT(void) ap_destroy_pool(pool *);
/* used to guarantee to the pool debugging code that the sub pool will not be
Index: src/include/ap_mm.h
===================================================================
RCS file: ap_mm.h
diff -N ap_mm.h
--- /dev/null Sun Jan 24 13:23:07 1999
+++ ap_mm.h Sun Jan 24 13:13:31 1999
@@ -0,0 +1,356 @@
+/* ====================================================================
+ * Copyright (c) 1999 Ralf S. Engelschall. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse <email protected>>."
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by
+ * Ralf S. Engelschall <rse <email protected>>."
+ *
+ * THIS SOFTWARE IS PROVIDED BY RALF S. ENGELSCHALL ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RALF S. ENGELSCHALL OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ */
+
+/*
+**
+** ap_mm.h -- Shared Memory Library API
+**
+*/
+
+#ifndef AP_MM_H
+#define AP_MM_H 1
+
+/*
+** ____ Public Part (I) of the API ________________________
+*/
+
+#define MM_VERSION_STR "1.0"
+#define MM_VERSION_NUM 0x0100
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(FALSE)
+#define FALSE 0
+#endif
+#if !defined(TRUE)
+#define TRUE !FALSE
+#endif
+#if !defined(NULL)
+#define NULL (void *)0
+#endif
+
+/*
+** ____ Private Part of the API ___________________________
+*/
+
+#if defined(MM_PRIVATE)
+
+/*
+ * BEGIN OF APACHE SECTION FOR PLATFORM HACKINGS
+ */
+
+/* Import platform stuff and start with N/A */
+#if !defined(AP_CONFIG_H)
+#include "ap_config.h"
+#endif
+#define MM_NA
+
+/* Determine mode for known platforms */
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#undef MM_NA
+#define MM_VMPS_GETPAGESIZE
+#define MM_SHMT_MMANON
+#define MM_SEMT_FCNTL
+#endif
+#if defined(LINUX)
+#undef MM_NA
+#define MM_VMPS_GETPAGESIZE
+#define MM_SHMT_IPCSHM
+#define MM_SEMT_FCNTL
+#endif
+#if defined(SUNOS4)
+#undef MM_NA
+#define MM_VMPS_GETPAGESIZE
+#define MM_SHMT_MMZERO
+#define MM_SEMT_FLOCK
+#endif
+#if defined(SOLARIS2)
+#undef MM_NA
+#define MM_VMPS_SYSCONF
+#define MM_SHMT_IPCSHM
+#define MM_SEMT_FCNTL
+#endif
+#if defined(IRIX)
+#undef MM_NA
+#define MM_VMPS_SYSCONF
+#define MM_SHMT_IPCSHM
+#define MM_SEMT_FCNTL
+#endif
+
+/* Determine mode for unknown platforms by guessing */
+#if defined(MM_NA)
+#if defined(USE_POSIX_SCOREBOARD)
+#define MM_SHMT_MMPOSX
+#endif
+#if defined(USE_MMAP_SCOREBOARD)
+#if defined(MAP_ANON)
+#define MM_SHMT_MMANON
+#endif
+#if defined(MAP_TMPFILE)
+#define MM_SHMT_MMFILE
+#endif
+#define MM_SHMT_MMZERO
+#endif
+#if defined(USE_SHMGET_SCOREBOARD)
+#define MM_SHMT_IPCSHM
+#endif
+#if defined(USE_FCNTL_SERIALIZED_ACCEPT)
+#define MM_SEMT_FCNTL
+#endif
+#if defined(USE_FLOCK_SERIALIZED_ACCEPT)
+#define MM_SEMT_FLOCK
+#endif
+#if defined(USE_SYSVSEM_SERIALIZED_ACCEPT)
+#define MM_SEMT_IPCSEM
+#endif
+#if (defined(MM_SHMT_MMANON) ||
+ defined(MM_SHMT_MMPOSX) ||
+ defined(MM_SHMT_MMZERO) ||
+ defined(MM_SHMT_MMFILE) ||
+ defined(MM_SHMT_IPCSHM) ) &&
+ (defined(MM_SEMT_FCNTL) ||
+ defined(MM_SEMT_FLOCK) ||
+ defined(MM_SEMT_IPCSEM) )
+#undef MM_NA
+#endif
+#endif /* MM_NA */
+
+/*
+ * END OF APACHE SECTION FOR PLATFORM HACKINGS
+ */
+
+#if defined(SUNOS4)
+#include <memory.h>
+/* SunOS lacks prototypes */
+int getpagesize(void);
+int munmap(caddr_t addr, int len);
+int ftruncate(int fd, off_t length);
+int flock(int fd, int operation);
+#endif
+
+#if !defined(offsetof)
+#define offsetof(type,member) ((size_t)(&((type *)0)->member))
+#endif
+
+#define FAIL goto cus
+#define BEGIN_FAILURE cus:
+#define END_FAILURE
+
+#if defined(PATH_MAX)
+#define MM_MAXPATH PATH_MAX
+#elif defined(_POSIX_PATH_MAX)
+#define MM_MAXPATH _POSIX_PATH_MAX
+#elif defined(MAXPATHLEN)
+#define MM_MAXPATH MAXPATHLEN
+#else
+#define MM_MAXPATH 2048
+#endif
+
+#if defined(CHILD_MAX)
+#define MM_MAXCHILD CHILD_MAX
+#elif defined(_POSIX_CHILD_MAX)
+#define MM_MAXCHILD _POSIX_CHILD_MAX
+#else
+#define MM_MAXCHILD 512
+#endif
+
+#if defined(MM_SHMT_MMANON) || defined(MM_SHMT_MMPOSX) ||\
+ defined(MM_SHMT_MMZERO) || defined(MM_SHMT_MMFILE)
+#include <sys/mman.h>
+#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+#endif
+
+#if defined(MM_SHMT_IPCSHM) || defined(MM_SEMT_IPCSEM)
+#include <sys/ipc.h>
+#endif
+
+#if defined(MM_SHMT_IPCSHM)
+#include <sys/shm.h>
+#endif
+
+#if defined(MM_SEMT_IPCSEM)
+#include <sys/sem.h>
+#endif
+
+#ifdef MM_SEMT_FLOCK
+#include <sys/file.h>
+#endif
+
+#define MM_CORE_FILEMODE (S_IRUSR|S_IWUSR)
+#define MM_CORE_MINSIZE (1*1024) /* 1 KB */
+#define MM_CORE_MAXSIZE (16*1024*1024) /* 16 MB */
+#define MM_DEFAULT_PAGESIZE 8192 /* 8 KB */
+#define MM_DEFAULT_SIZE (1*1024*1024) /* 1MB */
+#define MM_DEFAULT_FILE "/tmp/mm.core.%d" /* %d is PID */
+
+/*
+ * Define a union with types which are likely to have the longest
+ * *relevant* CPU-specific memory word alignment restrictions...
+ */
+union mem_word {
+ void *mw_vp;
+ void (*mw_fp)(void);
+ char *mw_cp;
+ long mw_l;
+ double mw_d;
+};
+typedef union mem_word mem_word;
+#define SIZEOF_mem_word (sizeof(mem_word))
+
+/*
+ * Define the structure used for memory chunks
+ */
+union mem_chunk_mc_u {
+ struct mem_chunk *mc_next; /* really used when it's free */
+ mem_word mc_base; /* virtually used when it's allocated */
+};
+struct mem_chunk {
+ size_t mc_size; /* physical size */
+ size_t mc_usize; /* user known size */
+ union mem_chunk_mc_u mc_u;
+};
+typedef struct mem_chunk mem_chunk;
+#define SIZEOF_mem_chunk (sizeof(mem_chunk)-sizeof(union mem_chunk_mc_u))
+
+/*
+ * Define the structure describing a memory pool
+ */
+struct mem_pool {
+ size_t mp_size;
+ size_t mp_offset;
+ mem_chunk mp_freechunks;
+ mem_word mp_base;
+};
+typedef struct mem_pool mem_pool;
+#define SIZEOF_mem_pool (sizeof(mem_pool)-SIZEOF_mem_word)
+
+/*
+ * Define the structure holding per-process filedescriptors
+ */
+#if defined(MM_SEMT_FLOCK)
+struct mem_core_fd {
+ pid_t pid;
+ int fd;
+};
+typedef struct mem_core_fd mem_core_fd;
+#define SIZEOF_mem_core_fd (sizeof(mem_core_fd)
+#endif
+
+/*
+ * Define the structure describing a shared memory core area
+ * (the actual contents depends on the shared memory and
+ * semaphore/mutex type and is stripped down to a minimum
+ * required)
+ */
+struct mem_core {
+ size_t mc_size;
+ size_t mc_usize;
+ pid_t mc_pid;
+ int mc_fdmem;
+#if defined(MM_SHMT_MMFILE)
+ char mc_fnmem[MM_MAXPATH];
+#endif
+#if !defined(MM_SEMT_FLOCK)
+ int mc_fdsem;
+#endif
+#if defined(MM_SEMT_FLOCK)
+ mem_core_fd mc_fdsem[MM_MAXCHILD];
+#endif
+#if defined(MM_SEMT_FLOCK) || defined(MM_SEMT_FCNTL)
+ char mc_fnsem[MM_MAXPATH];
+#endif
+ mem_word mc_base;
+};
+typedef struct mem_core mem_core;
+#define SIZEOF_mem_core (sizeof(mem_core)-SIZEOF_mem_word)
+
+#endif /* MM_PRIVATE */
+
+/*
+** ____ Public Part (II) of the API _______________________
+*/
+
+#if defined(MM_PRIVATE)
+typedef mem_pool MM;
+#else
+typedef void MM;
+#endif
+
+/* Global Malloc-Replacement API */
+int MM_create(void);
+void MM_destroy(void);
+int MM_lock(void);
+int MM_unlock(void);
+void *MM_malloc(size_t size);
+void *MM_realloc(void *ptr, size_t size);
+void MM_free(void *ptr);
+void *MM_calloc(size_t number, size_t size);
+char *MM_strdup(const char *str);
+size_t MM_sizeof(void *ptr);
+
+/* Standard Malloc-Style API */
+MM *mm_create(size_t size, char *file);
+void mm_destroy(MM *mm);
+int mm_lock(MM *mm);
+int mm_unlock(MM *mm);
+void *mm_malloc(MM *mm, size_t size);
+void *mm_realloc(MM *mm, void *ptr, size_t size);
+void mm_free(MM *mm, void *ptr);
+void *mm_calloc(MM *mm, size_t number, size_t size);
+char *mm_strdup(MM *mm, const char *str);
+size_t mm_sizeof(MM *mm, void *ptr);
+#ifdef MM_DEBUG
+void mm_display_info(MM *mm);
+#endif
+
+/* Low-Level Shared Memory API */
+size_t mm_core_align2page(size_t size);
+size_t mm_core_align2word(size_t size);
+void *mm_core_create(size_t size, char *file);
+void mm_core_delete(void *core);
+size_t mm_core_size(void *core);
+int mm_core_lock(void *core);
+int mm_core_unlock(void *core);
+
+#endif /* AP_MM_H */
Index: src/include/httpd.h
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/include/httpd.h,v
retrieving revision 1.264
diff -u -r1.264 httpd.h
--- src/include/httpd.h 1999/01/10 07:48:59 1.264
+++ src/include/httpd.h 1999/01/24 12:04:50
@@ -69,6 +69,7 @@
/* Headers in which EVERYONE has an interest... */
#include "ap_config.h"
+#include "ap_mm.h"
#include "alloc.h"
#include "buff.h"
#include "ap.h"
Index: src/main/alloc.c
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/main/alloc.c,v
retrieving revision 1.105
diff -u -r1.105 alloc.c
--- src/main/alloc.c 1999/01/03 12:04:37 1.105
+++ src/main/alloc.c 1999/01/24 12:14:39
@@ -127,6 +127,10 @@
#define BLOCK_MINALLOC 0
#endif
+#if defined(AP_SHARED_POOL)
+static MM *mm = NULL;
+#endif
+
/*****************************************************************
*
* Managing free storage blocks...
@@ -155,6 +159,9 @@
char *endp;
union block_hdr *next;
char *first_avail;
+#if defined(AP_SHARED_POOL)
+ int is_shm;
+#endif
#ifdef POOL_DEBUG
union block_hdr *global_next;
struct pool *owning_pool;
@@ -198,7 +205,11 @@
/* Get a completely new block from the system pool. Note that we rely on
malloc() to provide aligned memory. */
+#if defined(AP_SHARED_POOL)
+static union block_hdr *malloc_block(int size, int is_shm)
+#else
static union block_hdr *malloc_block(int size)
+#endif
{
union block_hdr *blok;
@@ -208,12 +219,20 @@
*/
size += CLICK_SZ;
#endif
+#if defined(AP_SHARED_POOL)
+ if (is_shm)
+ blok = (union block_hdr *)mm_malloc(mm, size + sizeof(union block_hdr));
+ else
+#endif
blok = (union block_hdr *) malloc(size + sizeof(union block_hdr));
if (blok == NULL) {
fprintf(stderr, "Ouch! malloc failed in malloc_block()\n");
exit(1);
}
debug_fill(blok, size + sizeof(union block_hdr));
+#if defined(AP_SHARED_POOL)
+ blok->h.is_shm = is_shm;
+#endif
blok->h.next = NULL;
blok->h.first_avail = (char *) (blok + 1);
blok->h.endp = size + blok->h.first_avail;
@@ -271,6 +290,10 @@
if (blok == NULL)
return; /* Sanity check --- freeing empty pool? */
+#if defined(AP_SHARED_POOL)
+ if (blok->h.is_shm)
+ (void)mm_lock(mm);
+#endif
(void) ap_acquire_mutex(alloc_mutex);
old_free_list = block_freelist;
block_freelist = blok;
@@ -302,7 +325,11 @@
blok->h.next = old_free_list;
(void) ap_release_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ if (blok->h.is_shm)
+ (void)mm_unlock(mm);
#endif
+#endif
}
@@ -310,7 +337,11 @@
* if necessary. Must be called with alarms blocked.
*/
+#if defined(AP_SHARED_POOL)
+static union block_hdr *new_block(int min_size, int is_shm)
+#else
static union block_hdr *new_block(int min_size)
+#endif
{
union block_hdr **lastptr = &block_freelist;
union block_hdr *blok = block_freelist;
@@ -320,7 +351,11 @@
*/
while (blok != NULL) {
+#if defined(AP_SHARED_POOL)
+ if (blok->h.is_shm == is_shm && min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) {
+#else
if (min_size + BLOCK_MINFREE <= blok->h.endp - blok->h.first_avail) {
+#endif
*lastptr = blok->h.next;
blok->h.next = NULL;
debug_verify_filled(blok->h.first_avail, blok->h.endp,
@@ -336,7 +371,11 @@
/* Nope. */
min_size += BLOCK_MINFREE;
+#if defined(AP_SHARED_POOL)
+ blok = malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC, is_shm);
+#else
blok = malloc_block((min_size > BLOCK_MINALLOC) ? min_size : BLOCK_MINALLOC);
+#endif
return blok;
}
@@ -386,6 +425,9 @@
#ifdef POOL_DEBUG
struct pool *joined;
#endif
+#if defined(AP_SHARED_POOL)
+ int is_shm;
+#endif
};
static pool *permanent_pool;
@@ -400,16 +442,28 @@
#define POOL_HDR_CLICKS (1 + ((sizeof(struct pool) - 1) / CLICK_SZ))
#define POOL_HDR_BYTES (POOL_HDR_CLICKS * CLICK_SZ)
+#if defined(AP_SHARED_POOL)
+static struct pool *make_sub_pool_internal(struct pool *p, int is_shm)
+#else
API_EXPORT(struct pool *) ap_make_sub_pool(struct pool *p)
+#endif
{
union block_hdr *blok;
pool *new_pool;
ap_block_alarms();
+#if defined(AP_SHARED_POOL)
+ if (is_shm)
+ (void)mm_lock(mm);
+#endif
(void) ap_acquire_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ blok = new_block(POOL_HDR_BYTES, is_shm);
+#else
blok = new_block(POOL_HDR_BYTES);
+#endif
new_pool = (pool *) blok->h.first_avail;
blok->h.first_avail += POOL_HDR_BYTES;
#ifdef POOL_DEBUG
@@ -428,12 +482,36 @@
p->sub_pools = new_pool;
}
+#if defined(AP_SHARED_POOL)
+ new_pool->is_shm = is_shm;
+#endif
+
(void) ap_release_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ if (is_shm)
+ (void)mm_unlock(mm);
+#endif
ap_unblock_alarms();
return new_pool;
}
+#if defined(AP_SHARED_POOL)
+API_EXPORT(struct pool *) ap_make_sub_pool(struct pool *p)
+{
+ return make_sub_pool_internal(p, 0);
+}
+API_EXPORT(struct pool *) ap_make_shared_sub_pool(struct pool *p)
+{
+ return make_sub_pool_internal(p, 1);
+}
+#else
+API_EXPORT(struct pool *) ap_make_shared_sub_pool(struct pool *p)
+{
+ return ap_make_sub_pool(p);
+}
+#endif
+
#ifdef POOL_DEBUG
static void stack_var_init(char *s)
{
@@ -458,8 +536,10 @@
#endif
alloc_mutex = ap_create_mutex(NULL);
spawn_mutex = ap_create_mutex(NULL);
+#if defined(AP_SHARED_POOL)
+ mm = mm_create(1024*512 /* 512 KB */, NULL);
+#endif
permanent_pool = ap_make_sub_pool(NULL);
-
return permanent_pool;
}
@@ -467,10 +547,18 @@
{
ap_block_alarms();
+#if defined(AP_SHARED_POOL)
+ if (a->is_shm)
+ (void)mm_lock(mm);
+#endif
(void) ap_acquire_mutex(alloc_mutex);
while (a->sub_pools)
ap_destroy_pool(a->sub_pools);
(void) ap_release_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ if (a->is_shm)
+ (void)mm_unlock(mm);
+#endif
/* Don't hold the mutex during cleanups. */
run_cleanups(a->cleanups);
a->cleanups = NULL;
@@ -504,6 +592,10 @@
ap_block_alarms();
ap_clear_pool(a);
+#if defined(AP_SHARED_POOL)
+ if (a->is_shm)
+ (void)mm_lock(mm);
+#endif
(void) ap_acquire_mutex(alloc_mutex);
if (a->parent) {
if (a->parent->sub_pools == a)
@@ -514,6 +606,10 @@
a->sub_next->sub_prev = a->sub_prev;
}
(void) ap_release_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ if (a->is_shm)
+ (void)mm_unlock(mm);
+#endif
free_blocks(a->first);
ap_unblock_alarms();
@@ -528,6 +624,30 @@
return bytes_in_block_list(block_freelist);
}
+API_EXPORT(int) ap_acquire_pool(pool *p)
+{
+#if defined(AP_SHARED_POOL)
+ if (!p->is_shm)
+ return 1;
+ else
+ return mm_lock(mm);
+#else
+ return 1;
+#endif
+}
+
+API_EXPORT(int) ap_release_pool(pool *p)
+{
+#if defined(AP_SHARED_POOL)
+ if (!p->is_shm)
+ return 1;
+ else
+ return mm_unlock(mm);
+#else
+ return 1;
+#endif
+}
+
/*****************************************************************
* POOL_DEBUG support
*/
@@ -693,16 +813,31 @@
ap_block_alarms();
+#if defined(AP_SHARED_POOL)
+ if (a->is_shm)
+ (void)mm_lock(mm);
+#endif
(void) ap_acquire_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ blok = new_block(size, a->is_shm);
+#else
blok = new_block(size);
+#endif
a->last->h.next = blok;
a->last = blok;
#ifdef POOL_DEBUG
blok->h.owning_pool = a;
#endif
+#if defined(AP_SHARED_POOL)
+ blok->h.is_shm = a->is_shm;
+#endif
(void) ap_release_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ if (a->is_shm)
+ (void)mm_unlock(mm);
+#endif
ap_unblock_alarms();
@@ -834,9 +969,21 @@
cur_len = strp - blok->h.first_avail;
/* must try another blok */
+#if defined(AP_SHARED_POOL)
+ if (blok->h.is_shm)
+ (void)mm_lock(mm);
+#endif
(void) ap_acquire_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ nblok = new_block(2 * cur_len, blok->h.is_shm);
+#else
nblok = new_block(2 * cur_len);
+#endif
(void) ap_release_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ if (blok->h.is_shm)
+ (void)mm_unlock(mm);
+#endif
memcpy(nblok->h.first_avail, blok->h.first_avail, cur_len);
ps->vbuff.curpos = nblok->h.first_avail + cur_len;
/* save a byte for the NUL terminator */
@@ -845,10 +992,18 @@
/* did we allocate the current blok? if so free it up */
if (ps->got_a_new_block) {
debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);
+#if defined(AP_SHARED_POOL)
+ if (blok->h.is_shm)
+ (void)mm_lock(mm);
+#endif
(void) ap_acquire_mutex(alloc_mutex);
blok->h.next = block_freelist;
block_freelist = blok;
(void) ap_release_mutex(alloc_mutex);
+#if defined(AP_SHARED_POOL)
+ if (blok->h.is_shm)
+ (void)mm_unlock(mm);
+#endif
}
ps->blok = nblok;
ps->got_a_new_block = 1;
@@ -867,6 +1022,11 @@
void *ptr;
ap_block_alarms();
+#if defined(AP_SHARED_POOL)
+ if (p->is_shm)
+ ps.base = mm_malloc(mm, 512);
+ else
+#endif
ps.base = malloc(512);
if (ps.base == NULL) {
fputs("Ouch! Out of memory!\n", stderr);
-- PHP Development Mailing List http://www.php.net/ To unsubscribe send an empty message to php-dev-unsubscribe <email protected> For help: php-dev-help <email protected>
- Next message: Egon Schmid: "Re: [PHP-DEV] [PATCH] Shared Memory Pools ;-) (fwd)"
- Previous message: ryan <email protected>: "[PHP-DEV] Bug #1090: Sybase persistent connections can't handle server restart"
- Next in thread: Egon Schmid: "Re: [PHP-DEV] [PATCH] Shared Memory Pools ;-) (fwd)"
- Reply: Egon Schmid: "Re: [PHP-DEV] [PATCH] Shared Memory Pools ;-) (fwd)"
- Maybe reply: Zeev Suraski: "Re: [PHP-DEV] [PATCH] Shared Memory Pools ;-) (fwd)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

