summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArchie Cobbs <archie@FreeBSD.org>2002-03-13 01:42:33 +0000
committerArchie Cobbs <archie@FreeBSD.org>2002-03-13 01:42:33 +0000
commit44a8ff315e2a51614155fcbb86ab0577bb1f1152 (patch)
tree0df1490a2b1aa94853b37fed5acf74bb6a508a3e
parent9ed55d1061add08b8a6feef7dc3685cb30685fd1 (diff)
Notes
-rw-r--r--share/man/man9/Makefile1
-rw-r--r--share/man/man9/malloc.985
-rw-r--r--sys/kern/kern_malloc.c74
-rw-r--r--sys/sys/malloc.h4
4 files changed, 153 insertions, 11 deletions
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index 32760e353820..ce4fcdb1cfb4 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -156,6 +156,7 @@ MLINKS+=make_dev.9 dev_depends.9
MLINKS+=make_dev.9 destroy_dev.9
MLINKS+=make_dev.9 make_dev_alias.9
MLINKS+=malloc.9 FREE.9 malloc.9 MALLOC.9 malloc.9 free.9
+MLINKS+=malloc.9 realloc.9 malloc.9 reallocf.9
MLINKS+=mi_switch.9 cpu_switch.9 mi_switch.9 cpu_throw.9
MLINKS+=namei.9 NDINIT.9
MLINKS+=namei.9 NDFREE.9
diff --git a/share/man/man9/malloc.9 b/share/man/man9/malloc.9
index c748724585fa..447d8cfd2e6a 100644
--- a/share/man/man9/malloc.9
+++ b/share/man/man9/malloc.9
@@ -54,18 +54,63 @@
.Ft void
.Fn free "void *addr" "struct malloc_type *type"
.Fn FREE "void *addr" "struct malloc_type *type"
+.Ft void *
+.Fn realloc "void *addr" "unsigned long size" "struct malloc_type *type" "int flags"
+.Ft void *
+.Fn reallocf "void *addr" "unsigned long size" "struct malloc_type *type" "int flags"
.Sh DESCRIPTION
The
.Fn malloc
function allocates uninitialized memory in kernel address space for an
object whose size is specified by
.Fa size .
+.Pp
.Fn free
releases memory at address
.Fa addr
that was previously allocated by
.Fn malloc
-for re-use. The memory is not zeroed.
+for re-use.
+The memory is not zeroed.
+If
+.Fa addr
+is
+.Dv NULL ,
+then
+.Fn free
+does nothing.
+.Pp
+The
+.Fn realloc
+function changes the size of the previously allocated memory referenced by
+.Fa addr
+to
+.Fa size
+bytes.
+The contents of the memory are unchanged up to the lesser of the new and
+old sizes.
+Note that the returned value may differ from
+.Fa addr .
+If the requested memory cannot be allocated,
+.Dv NULL
+is returned and the memory referenced by
+.Fa addr
+is valid and unchanged.
+If
+.Fa addr
+is
+.Dv NULL ,
+the
+.Fn realloc
+function behaves identically to
+.Fn malloc
+for the specified size.
+.Pp
+The
+.Fn reallocf
+function call is identical to the realloc function call, except that it
+will free the passed pointer when the requested memory cannot be allocated.
+.Pp
The
.Fn MALLOC
macro variant is functionally equivalent to
@@ -92,26 +137,35 @@ operational characteristics as follows:
Causes the allocated memory to be set to all zeros.
.It Dv M_NOWAIT
Causes
-.Fn malloc
+.Fn malloc ,
+.Fn realloc ,
+or
+.Fn reallocf
to return
.Dv NULL
if the request cannot be immediately fulfilled due to resource shortage.
-Otherwise,
-.Fn malloc
-may call sleep to wait for resources to be released by other processes.
+Otherwise, the current process may be put to sleep to wait for
+resources to be released by other processes.
If this flag is set,
.Fn malloc
will return
.Dv NULL
-rather then block. Note that
+rather then block.
+Note that
.Dv M_WAITOK
is defined to be 0, meaning that blocking operation is the default.
+Also note that
+.Dv M_NOWAIT
+is required when running in an interrupt context.
.It Dv M_WAITOK
Indicates that it is Ok to wait for resources. It is unconveniently
defined as 0 so care should be taken never to compare against this value
directly or try to AND it as a flag. The default operation is to block
until the memory allocation succeeds.
-.Fn malloc
+.Fn malloc ,
+.Fn realloc ,
+and
+.Fn reallocf
can only return
.Dv NULL
if
@@ -157,13 +211,22 @@ MALLOC(buf, struct foo_buf *, sizeof *buf, M_FOOBUF, M_NOWAIT);
.Ed
.Sh RETURN VALUES
-.Fn malloc
-returns a kernel virtual address that is suitably aligned for storage of
+.Fn malloc ,
+.Fn realloc ,
+and
+.Fn reallocf
+return a kernel virtual address that is suitably aligned for storage of
any type of object, or
.Dv NULL
-if the request could not be satisfied and
+if the request could not be satisfied (implying that
.Dv M_NOWAIT
-was set.
+was set).
+.Sh IMPLEMENTATION NOTES
+The memory allocator allocates memory in chunks that have size a power
+of two for requests up to the size of a page of memory.
+For larger requests, one or more pages is allocated.
+While it should not be relied upon, this information may be useful for
+optimizing the efficiency of memory use.
.Sh SEE ALSO
.Xr vmstat 8
.Sh DIAGNOSTICS
diff --git a/sys/kern/kern_malloc.c b/sys/kern/kern_malloc.c
index 0446b1f3cad6..a8eec9c2d61c 100644
--- a/sys/kern/kern_malloc.c
+++ b/sys/kern/kern_malloc.c
@@ -57,6 +57,16 @@
#include <machine/cpu.h>
#endif
+/*
+ * When realloc() is called, if the new size is sufficiently smaller than
+ * the old size, realloc() will allocate a new, smaller block to avoid
+ * wasting memory. 'Sufficiently smaller' is defined as: newsize <=
+ * oldsize / 2^n, where REALLOC_FRACTION defines the value of 'n'.
+ */
+#ifndef REALLOC_FRACTION
+#define REALLOC_FRACTION 1 /* new block if <= half the size */
+#endif
+
MALLOC_DEFINE(M_CACHE, "cache", "Various Dynamically allocated caches");
MALLOC_DEFINE(M_DEVBUF, "devbuf", "device driver memory");
MALLOC_DEFINE(M_TEMP, "temp", "misc temporary data buffers");
@@ -294,6 +304,10 @@ free(addr, type)
#endif
register struct malloc_type *ksp = type;
+ /* free(NULL, ...) does nothing */
+ if (addr == NULL)
+ return;
+
KASSERT(kmembase <= (char *)addr && (char *)addr < kmemlimit,
("free: address %p out of range", (void *)addr));
kup = btokup(addr);
@@ -400,6 +414,66 @@ free(addr, type)
}
/*
+ * realloc: change the size of a memory block
+ */
+void *
+realloc(addr, size, type, flags)
+ void *addr;
+ unsigned long size;
+ struct malloc_type *type;
+ int flags;
+{
+ struct kmemusage *kup;
+ unsigned long alloc;
+ void *newaddr;
+
+ /* realloc(NULL, ...) is equivalent to malloc(...) */
+ if (addr == NULL)
+ return (malloc(size, type, flags));
+
+ /* Sanity check */
+ KASSERT(kmembase <= (char *)addr && (char *)addr < kmemlimit,
+ ("realloc: address %p out of range", (void *)addr));
+
+ /* Get the size of the original block */
+ kup = btokup(addr);
+ alloc = 1 << kup->ku_indx;
+ if (alloc > MAXALLOCSAVE)
+ alloc = kup->ku_pagecnt << PAGE_SHIFT;
+
+ /* Reuse the original block if appropriate */
+ if (size <= alloc
+ && (size > (alloc >> REALLOC_FRACTION) || alloc == MINALLOCSIZE))
+ return (addr);
+
+ /* Allocate a new, bigger (or smaller) block */
+ if ((newaddr = malloc(size, type, flags)) == NULL)
+ return (NULL);
+
+ /* Copy over original contents */
+ bcopy(addr, newaddr, min(size, alloc));
+ free(addr, type);
+ return (newaddr);
+}
+
+/*
+ * reallocf: same as realloc() but free memory on failure.
+ */
+void *
+reallocf(addr, size, type, flags)
+ void *addr;
+ unsigned long size;
+ struct malloc_type *type;
+ int flags;
+{
+ void *mem;
+
+ if ((mem = realloc(addr, size, type, flags)) == NULL)
+ free(addr, type);
+ return (mem);
+}
+
+/*
* Initialize the kernel memory allocator
*/
/* ARGSUSED*/
diff --git a/sys/sys/malloc.h b/sys/sys/malloc.h
index ce9932792292..5f3ec3d62ab2 100644
--- a/sys/sys/malloc.h
+++ b/sys/sys/malloc.h
@@ -173,6 +173,10 @@ void free __P((void *addr, struct malloc_type *type));
void *malloc __P((unsigned long size, struct malloc_type *type, int flags));
void malloc_init __P((void *));
void malloc_uninit __P((void *));
+void *realloc __P((void *addr, unsigned long size,
+ struct malloc_type *type, int flags));
+void *reallocf __P((void *addr, unsigned long size,
+ struct malloc_type *type, int flags));
#endif /* _KERNEL */
#endif /* !_SYS_MALLOC_H_ */