Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/kern Make per-process shm segment descriptor magement sc...
details: https://anonhg.NetBSD.org/src/rev/5f0914e20c49
branches: trunk
changeset: 551635:5f0914e20c49
user: drochner <drochner%NetBSD.org@localhost>
date: Tue Sep 09 15:02:45 2003 +0000
description:
Make per-process shm segment descriptor magement scale better for large
shminfo.shmseg, in view of the fact that only few processes utilize a
significant fraction of it:
-turn the table into a linked list, elements allocated from a pool(9)
-On fork(), just bump a refcount instead of copying the list; it will
be decremented on exit() and exec(). Only copy if an attach or detach
takes place in between, which is rarely the case.
diffstat:
sys/kern/sysv_shm.c | 186 +++++++++++++++++++++++++++++++++++++--------------
1 files changed, 134 insertions(+), 52 deletions(-)
diffs (truncated from 315 to 300 lines):
diff -r b6c31dc59b2d -r 5f0914e20c49 sys/kern/sysv_shm.c
--- a/sys/kern/sysv_shm.c Tue Sep 09 14:44:35 2003 +0000
+++ b/sys/kern/sysv_shm.c Tue Sep 09 15:02:45 2003 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: sysv_shm.c,v 1.68 2003/02/20 22:16:07 atatat Exp $ */
+/* $NetBSD: sysv_shm.c,v 1.69 2003/09/09 15:02:45 drochner Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -68,7 +68,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sysv_shm.c,v 1.68 2003/02/20 22:16:07 atatat Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sysv_shm.c,v 1.69 2003/09/09 15:02:45 drochner Exp $");
#define SYSVSHM
@@ -82,6 +82,8 @@
#include <sys/mount.h> /* XXX for <sys/syscallargs.h> */
#include <sys/sa.h>
#include <sys/syscallargs.h>
+#include <sys/queue.h>
+#include <sys/pool.h>
#include <uvm/uvm_extern.h>
@@ -113,18 +115,29 @@
struct uvm_object *shm_object;
};
-struct shmmap_state {
+struct shmmap_entry {
+ SLIST_ENTRY(shmmap_entry) next;
vaddr_t va;
int shmid;
};
+struct pool shmmap_entry_pool;
+
+struct shmmap_state {
+ unsigned int nitems;
+ unsigned int nrefs;
+ SLIST_HEAD(, shmmap_entry) entries;
+};
+
static int shm_find_segment_by_key __P((key_t));
static void shm_deallocate_segment __P((struct shmid_ds *));
-static void shm_delete_mapping __P((struct vmspace *, struct shmmap_state *));
+static void shm_delete_mapping __P((struct vmspace *, struct shmmap_state *,
+ struct shmmap_entry *));
static int shmget_existing __P((struct proc *, struct sys_shmget_args *,
int, int, register_t *));
static int shmget_allocate_segment __P((struct proc *, struct sys_shmget_args *,
int, register_t *));
+static struct shmmap_state *shmmap_getprivate __P((struct proc *));
static int
shm_find_segment_by_key(key)
@@ -178,19 +191,22 @@
}
static void
-shm_delete_mapping(vm, shmmap_s)
+shm_delete_mapping(vm, shmmap_s, shmmap_se)
struct vmspace *vm;
struct shmmap_state *shmmap_s;
+ struct shmmap_entry *shmmap_se;
{
struct shmid_ds *shmseg;
int segnum;
size_t size;
- segnum = IPCID_TO_IX(shmmap_s->shmid);
+ segnum = IPCID_TO_IX(shmmap_se->shmid);
shmseg = &shmsegs[segnum];
size = (shmseg->shm_segsz + PGOFSET) & ~PGOFSET;
- uvm_deallocate(&vm->vm_map, shmmap_s->va, size);
- shmmap_s->shmid = -1;
+ uvm_deallocate(&vm->vm_map, shmmap_se->va, size);
+ SLIST_REMOVE(&shmmap_s->entries, shmmap_se, shmmap_entry, next);
+ shmmap_s->nitems--;
+ pool_put(&shmmap_entry_pool, shmmap_se);
shmseg->shm_dtime = time.tv_sec;
if ((--shmseg->shm_nattch <= 0) &&
(shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
@@ -199,6 +215,47 @@
}
}
+/*
+ * Get a non-shared shm map for that vmspace.
+ * 3 cases:
+ * - no shm map present: create a fresh one
+ * - a shm map with refcount=1, just used by ourselves: fine
+ * - a shared shm map: copy to a fresh one and adjust refcounts
+ */
+static struct shmmap_state *
+shmmap_getprivate(struct proc *p)
+{
+ struct shmmap_state *oshmmap_s, *shmmap_s;
+ struct shmmap_entry *oshmmap_se, *shmmap_se;
+
+ oshmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
+ if (oshmmap_s && oshmmap_s->nrefs == 1)
+ return (oshmmap_s);
+
+ shmmap_s = malloc(sizeof(struct shmmap_state), M_SHM, M_WAITOK);
+ memset(shmmap_s, 0, sizeof(struct shmmap_state));
+ shmmap_s->nrefs = 1;
+ SLIST_INIT(&shmmap_s->entries);
+ p->p_vmspace->vm_shm = (caddr_t)shmmap_s;
+
+ if (!oshmmap_s)
+ return (shmmap_s);
+
+#ifdef SHMDEBUG
+ printf("shmmap_getprivate: vm %p split (%d entries), used by %d\n",
+ p->p_vmspace, oshmmap_s->nitems, oshmmap_s->nrefs);
+#endif
+ SLIST_FOREACH(oshmmap_se, &oshmmap_s->entries, next) {
+ shmmap_se = pool_get(&shmmap_entry_pool, PR_WAITOK);
+ shmmap_se->va = oshmmap_se->va;
+ shmmap_se->shmid = oshmmap_se->shmid;
+ SLIST_INSERT_HEAD(&shmmap_s->entries, shmmap_se, next);
+ }
+ shmmap_s->nitems = oshmmap_s->nitems;
+ oshmmap_s->nrefs--;
+ return (shmmap_s);
+}
+
int
sys_shmdt(l, v, retval)
struct lwp *l;
@@ -210,20 +267,26 @@
} */ *uap = v;
struct proc *p = l->l_proc;
struct shmmap_state *shmmap_s;
- int i;
+ struct shmmap_entry *shmmap_se;
shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
if (shmmap_s == NULL)
return EINVAL;
- for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
- if (shmmap_s->shmid != -1 &&
- shmmap_s->va == (vaddr_t)SCARG(uap, shmaddr))
- break;
- if (i == shminfo.shmseg)
- return EINVAL;
- shm_delete_mapping(p->p_vmspace, shmmap_s);
- return 0;
+ SLIST_FOREACH(shmmap_se, &shmmap_s->entries, next) {
+ if (shmmap_se->va == (vaddr_t)SCARG(uap, shmaddr)) {
+ shmmap_s = shmmap_getprivate(p);
+#ifdef SHMDEBUG
+ printf("shmdt: vm %p: remove %d @%lx\n",
+ p->p_vmspace, shmmap_se->shmid, shmmap_se->va);
+#endif
+ shm_delete_mapping(p->p_vmspace, shmmap_s, shmmap_se);
+ return 0;
+ }
+ }
+
+ /* not found */
+ return EINVAL;
}
int
@@ -258,23 +321,16 @@
vaddr_t *attachp;
int findremoved;
{
- int error, i, flags;
+ int error, flags;
struct ucred *cred = p->p_ucred;
struct shmid_ds *shmseg;
- struct shmmap_state *shmmap_s = NULL;
+ struct shmmap_state *shmmap_s;
struct shm_handle *shm_handle;
vaddr_t attach_va;
vm_prot_t prot;
vsize_t size;
+ struct shmmap_entry *shmmap_se;
- shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
- if (shmmap_s == NULL) {
- size = shminfo.shmseg * sizeof(struct shmmap_state);
- shmmap_s = malloc(size, M_SHM, M_WAITOK);
- for (i = 0; i < shminfo.shmseg; i++)
- shmmap_s[i].shmid = -1;
- p->p_vmspace->vm_shm = (caddr_t)shmmap_s;
- }
shmseg = shm_find_segment_by_shmid(shmid, findremoved);
if (shmseg == NULL)
return EINVAL;
@@ -282,13 +338,11 @@
(shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
if (error)
return error;
- for (i = 0; i < shminfo.shmseg; i++) {
- if (shmmap_s->shmid == -1)
- break;
- shmmap_s++;
- }
- if (i >= shminfo.shmseg)
+
+ shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
+ if (shmmap_s && shmmap_s->nitems >= shminfo.shmseg)
return EMFILE;
+
size = (shmseg->shm_segsz + PGOFSET) & ~PGOFSET;
prot = VM_PROT_READ;
if ((shmflg & SHM_RDONLY) == 0)
@@ -315,8 +369,15 @@
if (error) {
return error;
}
- shmmap_s->va = attach_va;
- shmmap_s->shmid = shmid;
+ shmmap_se = pool_get(&shmmap_entry_pool, PR_WAITOK);
+ shmmap_se->va = attach_va;
+ shmmap_se->shmid = shmid;
+ shmmap_s = shmmap_getprivate(p);
+#ifdef SHMDEBUG
+ printf("shmat: vm %p: add %d @%lx\n", p->p_vmspace, shmid, attach_va);
+#endif
+ SLIST_INSERT_HEAD(&shmmap_s->entries, shmmap_se, next);
+ shmmap_s->nitems++;
shmseg->shm_lpid = p->p_pid;
shmseg->shm_atime = time.tv_sec;
shmseg->shm_nattch++;
@@ -554,21 +615,22 @@
struct vmspace *vm1, *vm2;
{
struct shmmap_state *shmmap_s;
- size_t size;
- int i;
+ struct shmmap_entry *shmmap_se;
- if (vm1->vm_shm == NULL) {
- vm2->vm_shm = NULL;
+ vm2->vm_shm = vm1->vm_shm;
+
+ if (vm1->vm_shm == NULL)
return;
- }
- size = shminfo.shmseg * sizeof(struct shmmap_state);
- shmmap_s = malloc(size, M_SHM, M_WAITOK);
- memcpy(shmmap_s, vm1->vm_shm, size);
- vm2->vm_shm = (caddr_t)shmmap_s;
- for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
- if (shmmap_s->shmid != -1)
- shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
+#ifdef SHMDEBUG
+ printf("shmfork %p->%p\n", vm1, vm2);
+#endif
+
+ shmmap_s = (struct shmmap_state *)vm1->vm_shm;
+
+ SLIST_FOREACH(shmmap_se, &shmmap_s->entries, next)
+ shmsegs[IPCID_TO_IX(shmmap_se->shmid)].shm_nattch++;
+ shmmap_s->nrefs++;
}
void
@@ -576,16 +638,33 @@
struct vmspace *vm;
{
struct shmmap_state *shmmap_s;
- int i;
+ struct shmmap_entry *shmmap_se;
shmmap_s = (struct shmmap_state *)vm->vm_shm;
if (shmmap_s == NULL)
return;
- for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
- if (shmmap_s->shmid != -1)
- shm_delete_mapping(vm, shmmap_s);
- free(vm->vm_shm, M_SHM);
+
vm->vm_shm = NULL;
+
+ if (--shmmap_s->nrefs > 0) {
+#ifdef SHMDEBUG
+ printf("shmexit: vm %p drop ref (%d entries), used by %d\n",
+ vm, shmmap_s->nitems, shmmap_s->nrefs);
+#endif
+ SLIST_FOREACH(shmmap_se, &shmmap_s->entries, next)
+ shmsegs[IPCID_TO_IX(shmmap_se->shmid)].shm_nattch--;
+ return;
+ }
+
+#ifdef SHMDEBUG
+ printf("shmexit: vm %p cleanup (%d entries)\n", vm, shmmap_s->nitems);
+#endif
+ while (!SLIST_EMPTY(&shmmap_s->entries)) {
+ shmmap_se = SLIST_FIRST(&shmmap_s->entries);
Home |
Main Index |
Thread Index |
Old Index