Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 12 Mar 2002 14:37:37 -0800 (PST)
From:      Archie Cobbs <archie@dellroad.org>
To:        Alfred Perlstein <bright@mu.org>
Cc:        freebsd-current@freebsd.org
Subject:   Re: Adding realloc()
Message-ID:  <200203122237.g2CMbbY67802@arch20m.dellroad.org>
In-Reply-To: <20020312215305.GL92565@elvis.mu.org> "from Alfred Perlstein at Mar 12, 2002 01:53:05 pm"

next in thread | previous in thread | raw e-mail | index | archive | help

--ELM72051456-67788-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII

Alfred Perlstein writes:
> > I've had the need for a realloc() in the kernel several times
> > before and am having it once again. Finally figured it's time to
> > do something about it.
> 
> Where is the update to malloc(9)?  What about reallocf?

Good points, thanks.. try this one instead.

-Archie

__________________________________________________________________________
Archie Cobbs     *     Packet Design     *     http://www.packetdesign.com

--ELM72051456-67788-0_
Content-Transfer-Encoding: 7bit
Content-Type: text/x-patch
Content-Disposition: attachment; filename=REALLOC.patch
Content-Description: 

Index: sys/kern/kern_malloc.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_malloc.c,v
retrieving revision 1.93
diff -u -r1.93 kern_malloc.c
--- kern_malloc.c	12 Sep 2001 08:37:44 -0000	1.93
+++ kern_malloc.c	12 Mar 2002 22:34:35 -0000
@@ -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 @@
 #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);
@@ -397,6 +411,66 @@
 #endif
 	splx(s);
 	mtx_unlock(&malloc_mtx);
+}
+
+/*
+ *	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);
 }
 
 /*
Index: sys/sys/malloc.h
===================================================================
RCS file: /home/ncvs/src/sys/sys/malloc.h,v
retrieving revision 1.54
diff -u -r1.54 malloc.h
--- malloc.h	10 Aug 2001 06:37:04 -0000	1.54
+++ malloc.h	12 Mar 2002 22:34:46 -0000
@@ -173,6 +173,10 @@
 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_ */
Index: share/man/man9/malloc.9
===================================================================
RCS file: /home/ncvs/src/share/man/man9/malloc.9,v
retrieving revision 1.21
diff -u -r1.21 malloc.9
--- malloc.9	1 Oct 2001 16:09:25 -0000	1.21
+++ malloc.9	12 Mar 2002 22:34:57 -0000
@@ -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 @@
 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 @@
 
 .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
Index: share/man/man9/Makefile
===================================================================
RCS file: /home/ncvs/src/share/man/man9/Makefile,v
retrieving revision 1.153
diff -u -r1.153 Makefile
--- Makefile	6 Mar 2002 01:53:35 -0000	1.153
+++ Makefile	12 Mar 2002 22:36:52 -0000
@@ -156,6 +156,7 @@
 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

--ELM72051456-67788-0_--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-current" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200203122237.g2CMbbY67802>