summaryrefslogtreecommitdiffstats
path: root/sys/vm
diff options
context:
space:
mode:
authordyson <dyson@FreeBSD.org>1997-08-05 00:07:31 +0000
committerdyson <dyson@FreeBSD.org>1997-08-05 00:07:31 +0000
commit54005d6ed92a5387f42043a03fca4fbcb9b07bd9 (patch)
treef85e59f85e53e2abbd411fcbf9c8ff4a9edd72b8 /sys/vm
parent8a37859859e6f7dbdd0b4771735842513932eda9 (diff)
downloadFreeBSD-src-54005d6ed92a5387f42043a03fca4fbcb9b07bd9.zip
FreeBSD-src-54005d6ed92a5387f42043a03fca4fbcb9b07bd9.tar.gz
A very simple zone allocator.
Diffstat (limited to 'sys/vm')
-rw-r--r--sys/vm/vm_zone.c227
-rw-r--r--sys/vm/vm_zone.h82
2 files changed, 309 insertions, 0 deletions
diff --git a/sys/vm/vm_zone.c b/sys/vm/vm_zone.c
new file mode 100644
index 0000000..17a8500
--- /dev/null
+++ b/sys/vm/vm_zone.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 1997 John S. Dyson
+ * 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 immediately at the beginning of the file, without modification,
+ * 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. Absolutely no warranty of function or purpose is made by the author
+ * John S. Dyson.
+ * 4. This work was done expressly for inclusion into FreeBSD. Other use
+ * is allowed if this notation is included.
+ * 5. Modifications may be freely made to this file if the above conditions
+ * are met.
+ *
+ * $Id$
+ */
+
+#include <sys/param.h>
+#include <sys/uio.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/vmmeter.h>
+#include <sys/lock.h>
+
+#include <vm/vm.h>
+#include <vm/vm_object.h>
+#include <vm/vm_prot.h>
+#include <vm/vm_page.h>
+#include <vm/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_zone.h>
+#include <vm/vm_pageout.h>
+
+/*
+ * This file comprises a very simple zone allocator. This is used
+ * in lieu of the malloc allocator, where needed or more optimal.
+ *
+ * Note that the initial implementation of this had coloring, and
+ * absolutely no improvement (actually perf degradation) occurred.
+ *
+ * _zinit, zinit, _zbootinit are the initialization routines.
+ * zalloc, zfree, are the interrupt/lock unsafe allocation/free routines.
+ * zalloci, zfreei, are the interrupt/lock safe allocation/free routines.
+ */
+
+int
+_zinit(vm_zone_t z, vm_object_t obj, char *name, int size,
+ int nentries, int flags, int zalloc) {
+ int totsize;
+
+ if ((z->zflags & ZONE_BOOT) == 0) {
+
+ z->zsize = size;
+ simple_lock_init(&z->zlock);
+ z->zfreecnt = 0;
+ z->zname = name;
+
+ }
+
+ z->zflags |= flags;
+
+ /*
+ * If we cannot wait, allocate KVA space up front, and we will fill
+ * in pages as needed.
+ */
+ if ((z->zflags & ZONE_WAIT) == 0) {
+
+ totsize = round_page(z->zsize * nentries);
+
+ z->zkva = kmem_alloc_pageable(kernel_map, totsize);
+ if (z->zkva == 0) {
+ return 0;
+ }
+
+ z->zpagemax = totsize / PAGE_SIZE;
+ if (obj == NULL) {
+ z->zobj = vm_object_allocate(OBJT_DEFAULT, z->zpagemax);
+ } else {
+ z->zobj = obj;
+ _vm_object_allocate(OBJT_DEFAULT, z->zpagemax, obj);
+ }
+ }
+
+ if ( z->zsize > PAGE_SIZE)
+ z->zfreemin = 1;
+ else
+ z->zfreemin = PAGE_SIZE / z->zsize;
+
+ z->zallocflag = VM_ALLOC_SYSTEM;
+ if (z->zflags & ZONE_INTERRUPT)
+ z->zallocflag = VM_ALLOC_INTERRUPT;
+
+ z->zpagecount = 0;
+ if (zalloc)
+ z->zalloc = zalloc;
+ else
+ z->zalloc = 1;
+
+ return 1;
+}
+
+vm_zone_t
+zinit(char *name, int size, int nentries, int flags, int zalloc) {
+ vm_zone_t z;
+ z = (vm_zone_t) malloc(sizeof (struct vm_zone), M_ZONE, M_NOWAIT);
+ if (z == NULL)
+ return NULL;
+
+ if (_zinit(z, NULL, name, size, nentries, flags, zalloc) == 0) {
+ free(z, M_ZONE);
+ return NULL;
+ }
+
+ return z;
+}
+
+void
+_zbootinit(vm_zone_t z, char *name, int size, void *item, int nitems) {
+
+ int i;
+
+ z->zname = name;
+ z->zsize = size;
+ z->zpagemax = 0;
+ z->zobj = NULL;
+ z->zflags = ZONE_BOOT;
+ z->zfreemin = 0;
+ z->zallocflag = 0;
+ z->zpagecount = 0;
+ z->zalloc = 0;
+ simple_lock_init(&z->zlock);
+
+ for (i = 0; i < nitems; i++) {
+ * (void **) item = z->zitems;
+ z->zitems = item;
+ ++z->zfreecnt;
+ (char *) item += z->zsize;
+ }
+}
+
+static inline int
+zlock(vm_zone_t z) {
+ int s;
+ s = splhigh();
+ simple_lock(&z->zlock);
+ return s;
+}
+
+static inline void
+zunlock(vm_zone_t z, int s) {
+ simple_unlock(&z->zlock);
+ splx(s);
+}
+
+void *
+zalloci(vm_zone_t z) {
+ int s;
+ void *item;
+
+ s = zlock(z);
+ item = zalloc(z);
+ zunlock(z, s);
+ return item;
+}
+
+void
+zfreei(vm_zone_t z, void *item) {
+ int s;
+
+ s = zlock(z);
+ zfree(z, item);
+ zunlock(z, s);
+ return;
+}
+
+void *
+zget(vm_zone_t z, int s) {
+ int i;
+ vm_page_t m;
+ int nitems;
+ void *item, *litem;
+
+ if ((z->zflags & ZONE_WAIT) == 0) {
+ item = (char *) z->zkva + z->zpagecount * PAGE_SIZE;
+ for( i = 0; ((i < z->zalloc) && (z->zpagecount < z->zpagemax)); i++) {
+
+ m = vm_page_alloc( z->zobj, z->zpagecount, z->zallocflag);
+ if (m == NULL) {
+ break;
+ }
+
+ pmap_kenter(z->zkva + z->zpagecount * PAGE_SIZE, VM_PAGE_TO_PHYS(m));
+ ++z->zpagecount;
+ }
+ nitems = (i * PAGE_SIZE) / z->zsize;
+ } else {
+ /*
+ * We can wait, so just do normal kernel map allocation
+ */
+ item = (void *) kmem_alloc(kernel_map, z->zalloc * PAGE_SIZE);
+ nitems = (z->zalloc * PAGE_SIZE) / z->zsize;
+ }
+
+ /*
+ * Save one for immediate allocation
+ */
+ nitems -= 1;
+ for (i = 0; i < nitems; i++) {
+ * (void **) item = z->zitems;
+ z->zitems = item;
+ (char *) item += z->zsize;
+ ++z->zfreecnt;
+ }
+
+ return item;
+}
+
diff --git a/sys/vm/vm_zone.h b/sys/vm/vm_zone.h
new file mode 100644
index 0000000..7f6630d
--- /dev/null
+++ b/sys/vm/vm_zone.h
@@ -0,0 +1,82 @@
+
+#if !defined(_SYS_ZONE_H)
+
+#define _SYS_ZONE_H
+
+#define ZONE_COLOR 1
+#define ZONE_INTERRUPT 2
+#define ZONE_WAIT 4
+#define ZONE_PREALLOCATE 8
+#define ZONE_BOOT 16
+
+#include <machine/param.h>
+#include <sys/lock.h>
+
+
+#define CACHE_LINE_SIZE 32
+
+typedef struct vm_zone {
+ struct simplelock zlock; /* lock for data structure */
+ void *zitems; /* linked list of items */
+ int zfreemin; /* minimum number of free entries */
+ int zfreecnt; /* free entries */
+ vm_offset_t zkva; /* Base kva of zone */
+ int zpagecount; /* Total # of allocated pages */
+ int zpagemax; /* Max address space */
+ int zsize; /* size of each entry */
+ int zalloc; /* hint for # of pages to alloc */
+ int zflags; /* flags for zone */
+ int zallocflag; /* flag for allocation */
+ struct vm_object *zobj; /* object to hold zone */
+ char *zname; /* name for diags */
+} *vm_zone_t;
+
+
+vm_zone_t zinit(char *name, int size, int nentries, int flags, int zalloc);
+int _zinit(vm_zone_t z, struct vm_object *obj, char *name, int size,
+ int nentries, int flags, int zalloc);
+static void * zalloc(vm_zone_t z);
+static void zfree(vm_zone_t z, void *item);
+void * zalloci(vm_zone_t z) __attribute__((regparm(1)));
+void zfreei(vm_zone_t z, void *item) __attribute__((regparm(2)));
+void _zbootinit(vm_zone_t z, char *name, int size, void *item, int nitems) ;
+void * zget(vm_zone_t z, int s) __attribute__((regparm(2)));
+
+#if SMP > 1
+
+static __inline__ void *
+zalloc(vm_zone_t z) {
+ return zalloci(z);
+}
+
+static __inline__ void
+zfree(vm_zone_t z, void *item) {
+ zfreei(z, item);
+}
+
+#else
+
+static __inline__ void *
+zalloc(vm_zone_t z) {
+ int s;
+ void *item;
+
+ if (z->zfreecnt <= z->zfreemin) {
+ return zget(z, s);
+ }
+
+ item = z->zitems;
+ z->zitems = *(void **) item;
+ --z->zfreecnt;
+ return item;
+}
+
+static __inline__ void
+zfree(vm_zone_t z, void *item) {
+ * (void **) item = z->zitems;
+ z->zitems = item;
+ ++z->zfreecnt;
+}
+#endif
+
+#endif
OpenPOWER on IntegriCloud