Add realloc() and reallocf(), and make free(NULL, ...) acceptable.
Reviewed by: alfred
This commit is contained in:
parent
9ed55d1061
commit
44a8ff315e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=92194
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
@ -399,6 +413,66 @@ free(addr, type)
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the kernel memory allocator
|
||||
*/
|
||||
|
@ -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_ */
|
||||
|
Loading…
Reference in New Issue
Block a user