Compare commits

...

52 commits

Author SHA1 Message Date
Greg Burd
c4b96af829 Add test and benchmarks. 2020-06-24 10:33:13 -04:00
Greg Burd
e1eb2c8413 fixes 2020-06-22 14:21:25 -04:00
Gregory Burd
0727224086 Ignore all the unimportant things. 2012-03-17 19:23:32 -04:00
Gregory Burd
6b0eb6878b Fixes and cleanup. 2012-03-17 19:23:10 -04:00
Gregory Burd
f8c1c0e968 Initial merge from Joyent including the vmem_allocator strategy additions. 2012-03-17 11:32:48 -04:00
Wez Furlong
5cc22b9326 I was working in the wrong checkout in my last commit...
revert it, and make the constructor-ness conditional on not being
"standalone".
2010-06-27 00:05:03 +00:00
Wez Furlong
7d4d667891 Change the constructor attribute to putting this function in the
.init section.

The constructor is called too late, and clobbers state, leading
to heap corruption later.
2010-06-26 23:00:02 +00:00
Wez Furlong
1028ce923e Sync with the current sources from onnv-gate.
The solaris sources use a non-portable create-thread-suspended flag when
spawning the update thread; I've thrown together a pthreads portable
equivalent.  This has not had any real level of testing.

These changes include a lock around the underlying brk() call; the lack of lock
in earlier revisions of this repo may be the reason that
UMEM_OPTIONS=backend=sbrk was flaky.
2010-06-26 16:02:39 +00:00
Wez Furlong
b9dc821378 move umem_startup constructor to the umem .so itself, rather than
the malloc replacement.

Rename ec_atomic to umem_atomic.

Add a posix_memalign function.

-ldl isn't universal; make a configure check for it.
2010-06-26 13:10:39 +00:00
Wez Furlong
49b7cfb4d4 Apparently, the glibc malloc hooks are now deprecated due to thread safety
issues, so we simply eliminate the glibc specific code from our malloc
preload to resolve this issue.
2010-04-30 21:31:37 +00:00
Wez Furlong
f82ad44b62 * allow the sbrk backend to be requested via UMEM_OPTIONS=backend=sbrk, but note that this appears to be broken on non-solaris platforms.
* make a safer/better check for number of cpus on linux
 * use pthread_once to register the forkhandler, as it is possible to call it twice in some scenarios without this protection
2010-04-30 21:27:09 +00:00
Wez Furlong
b2ee64fc04 correct the parameter ordering for the memalign hook on glibc systems 2010-04-06 00:45:32 +00:00
Wez Furlong
698dd4c9af bump version number in trunk 2010-02-19 15:16:21 +00:00
Wez Furlong
da390045aa improve compatibility with PPC platforms. 2010-02-19 15:14:55 +00:00
Wez Furlong
e5bb27aaa8 bump the version; it's about 2 years overdue that we roll a new tarball 2009-03-06 00:58:05 +00:00
Wez Furlong
f90f13368b update copyright info 2008-06-03 03:48:16 +00:00
Wez Furlong
f4e4e257f5 fix portability issue reported by Mito 2008-06-03 03:39:58 +00:00
Wez Furlong
ffd4b8b927 packaging tweaks from Rich 2007-09-04 14:05:27 +00:00
Wez Furlong
b4f8c9083e spec fixup, patch from Rich 2007-09-03 14:38:10 +00:00
Wez Furlong
01ce31068d fixup malloc replacement on 64-bit systems; was missing a configure check. 2007-08-03 15:05:00 +00:00
Wez Furlong
1a747468dc better check for issetugid 2007-03-18 02:17:55 +00:00
Wez Furlong
41bc866d58 be more libc friendly when replacing malloc().
Use our own getenv() on glibc platforms, as the glibc implementation calls
malloc() internally.  This allows the use of env vars to enable debugging modes
in the app.
2007-03-18 01:37:02 +00:00
Wez Furlong
eb5ef0ba13 install man pages 2007-03-17 23:52:25 +00:00
Wez Furlong
409b31ca3f add gdb macros 2007-03-17 22:46:01 +00:00
Wez Furlong
84293cb0b4 fixup linkage 2007-03-17 19:14:33 +00:00
Wez Furlong
35e9dc7e11 fix another typo. 2007-03-17 18:45:43 +00:00
Wez Furlong
a97a02fa4c create a separate library, libumem_malloc, for people that want to replace
malloc with the umem routines.
2007-03-17 18:22:16 +00:00
Wez Furlong
a6a20ffacf add man pages from opensolaris 2007-03-17 18:03:10 +00:00
Wez Furlong
8f2686cc81 fix typo and build on osx 2007-03-17 17:34:33 +00:00
Wez Furlong
c9b695687f tweak for svn 2007-03-17 17:31:57 +00:00
Devon H. O'Dell
7b6452aa2d Insert bits to allow successful compilation (and apparent success in
running) on FreeBSD.
2006-10-13 18:03:34 +00:00
Wez Furlong
724af76462 merge some OSX related fixes from ecelerity 2006-10-13 15:54:13 +00:00
Richard Dawe
07d8e36190 sol_compat.h: Pull in <sys/time.h> for proto of gettimeofday (fixes warnings) 2006-09-03 12:50:46 +00:00
Richard Dawe
29bf7f3e03 Add --enable-malloc-replacement option, for using libumem as a malloc replacement 2006-09-03 12:48:23 +00:00
Richard Dawe
e7140b1a1a Bugfix: 'rpm' target uses bzip2; so should the spec file 2006-09-03 12:45:22 +00:00
Richard Dawe
21f7b73b0f Include files, to pick up declarations for printf, strcpy (fixes warnings) 2006-09-03 11:57:04 +00:00
Richard Dawe
817aa395a1 Add another test program 2006-07-25 20:15:33 +00:00
Richard Dawe
07f343fdd8 Ignore more built files 2006-07-25 18:39:24 +00:00
Richard Dawe
c51a11fb01 Relax libtool version requirement; builds OK with libtool 1.4.2 on RH8.0 2006-07-25 18:37:09 +00:00
Richard Dawe
26b3085605 Specify build deps 2006-05-13 20:51:49 +00:00
Richard Dawe
c773e87bd3 Bugfix: need to depend on dist-bzip2 target, not the tarball, to ensure that tarball is always up-to-date 2006-05-13 20:50:18 +00:00
Richard Dawe
e781f51fc3 Use doxygen to build docs; generate spec file using configure; use tar.bz2 instead of tar.gz 2006-05-13 20:37:27 +00:00
Richard Dawe
8ddf3f8789 Ignore tarballs 2006-05-13 20:36:12 +00:00
Richard Dawe
c453cb48a6 Re-add README-alpha, to provide instructions for building from CVS, but this time actually adapt it to umem 2006-05-13 19:12:20 +00:00
Richard Dawe
11a4b72485 Bugfixes: install headers in correct place; include .so in -devel, not main rpm; run ldconfig on pre/post in rpm; clean out libtool files in rpm build 2006-03-12 18:23:52 +00:00
Richard Dawe
0d7e97d09b Beginnings of rpm build (currently broken) 2006-03-12 10:19:52 +00:00
Richard Dawe
1d494ceba8 'make dist' and 'make distcheck' work 2006-03-12 09:58:38 +00:00
Wez Furlong
aa3fcd42da ignore noisy autoconf bits 2006-03-11 18:58:46 +00:00
Wez Furlong
855e068963 make the build experience nicer outside of ecelerity.
Add a simple test app.
Note: we don't compile the malloc replacement component.
2006-03-11 18:57:05 +00:00
Wez Furlong
ec9812105b don't clobber our nice copyright file with GPL 2006-03-11 18:55:22 +00:00
Wez Furlong
427840d649 looks like an accidental commit 2006-03-11 17:34:08 +00:00
Richard Dawe
3f0a4a4e9b Build a basic shared library on Linux; may not work! 2006-03-11 17:15:25 +00:00
53 changed files with 6931 additions and 2273 deletions

25
.cvsignore Normal file
View file

@ -0,0 +1,25 @@
*.lo
*.la
.deps
.libs
*.loT
Makefile
Makefile.in
aclocal.m4
autom4te.cache
config.h
config.h.in
config.log
config.status
configure
libtool
stamp-h
stamp-h.in
stamp-h1
umem_test
umem_test2
umem_test3
Doxyfile
umem.spec
*.tar.gz
*.tar.bz2

32
.gitignore vendored Normal file
View file

@ -0,0 +1,32 @@
*~
*.lo
*.la
*.o
*.libs
INSTALL
Makefile.in
aclocal.m4
autom4te.cache
compile
config.guess
config.h.in
config.sub
configure
depcomp
install-sh
ltmain.sh
missing
.deps
Doxyfile
Makefile
config.h
config.log
config.status
libtool
stamp-h1
test-driver
umem.spec
umem_test
umem_test1
umem_test2
umem_test3

0
AUTHORS Normal file
View file

2
COPYING Normal file
View file

@ -0,0 +1,2 @@
Please see COPYRIGHT and OPENSOLARIS.LICENSE for the copyright
and license details.

View file

@ -1,5 +1,5 @@
The bulk of the library is Copyright 2004 Sun Microsystems, Inc.
Portions are Copyright 2006 OmniTI, Inc.
Portions are Copyright 2006-2008 Message Systems, Inc.
The library is distributed under the terms of the CDDL.
See the file OPENSOLARIS.LICENSE for more information.

0
ChangeLog Normal file
View file

1228
Doxyfile.in Normal file

File diff suppressed because it is too large Load diff

65
Makefile.am Normal file
View file

@ -0,0 +1,65 @@
lib_LTLIBRARIES = libumem.la libumem_malloc.la
noinst_PROGRAMS = umem_test umem_test2 umem_test3
libumem_la_LDFLAGS = -lpthread
umem_test_SOURCES = umem_test.c
umem_test_LDADD = -lumem
umem_test2_SOURCES = umem_test2.c
umem_test2_LDADD = -lumem
umem_test3_SOURCES = umem_test3.c
umem_test3_LDADD = -lumem -lumem_malloc
libumem_la_SOURCES = init_lib.c \
umem_agent_support.c \
umem_fail.c \
umem_fork.c \
umem_update_thread.c \
vmem_mmap.c \
vmem_sbrk.c \
envvar.c \
getpcstack.c \
misc.c \
misc.h \
vmem_base.c \
vmem_base.h \
vmem_stand.h \
umem.c \
umem.h \
umem_base.h \
umem_impl.h \
sol_compat.h \
vmem.c \
sys/vmem.h \
sys/vmem_impl_user.h
libumem_malloc_la_SOURCES = malloc.c
libumem_malloc_la_LDFLAGS = -lpthread -R$(libdir) -lumem
AM_CFLAGS = -fno-builtin-calloc
ACLOCAL_AMFLAGS = -I m4
man3_MANS = umem_alloc.3 umem_cache_create.3 umem_debug.3
EXTRA_DIST = COPYRIGHT OPENSOLARIS.LICENSE umem.spec Doxyfile umem_test4 \
$(man3_MANS)
nobase_include_HEADERS = umem.h sys/vmem.h
TESTS = umem_test umem_test2 umem_test3 umem_test4
html-local:
mkdir -p docs
doxygen Doxyfile
clean-local:
rm -rf docs
.PHONY: rpm
rpm: dist-bzip2
rpmbuild -ta $(distdir).tar.bz2
# XXX: Non-i386: SPARC asm. x86_64?
# Convert this to GNU as format: i386_subr_sol.s
# <http://cvs.opensolaris.org/source/xref/on/usr/src/lib/libumem/>

0
NEWS Normal file
View file

3
README
View file

@ -19,5 +19,6 @@ welcome third-party patches that improve the usability for everyone.
Wez Furlong,
OmniTI, Inc.
Message Systems, Inc.
wez (at) messagesystems (dot) com

61
README-alpha Normal file
View file

@ -0,0 +1,61 @@
This is the libumem package.
This document describes the actions needed to build the pre-release
or subversion version of the package. See end of file for copying conditions.
* Introduction
This is a *pre-release* version, and not ready for production use yet. If
you are taking source from subversion, you will need to have libtool, automake,
and autoconf installed to help contribute. See the chapter `Building' for the
detailed instructions. The script autogen.sh is provided to help autoconfigure
libumem from the cvs src. After you run autogen.sh, there should be a file
'INSTALL' with (generic) installation instructions. Package-specific
installation instructions are set forth in the file README.
Please, note that the accompanying documentation may be inaccurate or
incomplete. The subversion history is the authoritative documentation of all
recent changes.
Report bugs at https://github.com/gburd/libumem/issues
* Checking Out the Sources
The following instructions apply if you wish to obtain sources from
the subversion repository:
To checkout the source tree from subversion issue the following command:
svn co https://labs.omniti.com/portableumem/trunk portable-umem
* Building
In order to build this you will first need to have right versions
of autotools and some auxiliary GNU programs. At the time of this
writing these are:
Package Version (>=)
======== ============
automake 1.4
autoconf 2.50
libtool 1.5.0
To prepare the package for building run autogen.sh. Then run
./configure with the desired options (See INSTALL and README for the
detailed instructions). Finally, run make. Notice that the first make
of the package should be made in the source directory. Subsequent
makes can use build directory different from the source one.
* Use
To use link with both umem and umem_malloc (e.g. '-lumem -lumem_malloc').
* Testing
There are two basic test files included, test.c and hello.c, with
basic instructions within those files at the end. Basic performance
testing was done using hyperfine.
* Copyright information:
Please see COPYRIGHT and OPENSOLARIS.LICENSE for the copyright
and license details.

19
TODO Normal file
View file

@ -0,0 +1,19 @@
To-do List for the Linux port of umem
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Autconf'ery for <stdint.h> in "sol_compat.h".
* Fix #define wreakage for THR_RETURN, THR_API in "sol_compat.h".
* Replace use of Ecelerity's portable atomic locking header with something
equivalent in "sol_compat.h".
* ec_debug_vprintf -> something else?
* test suite.
* static library support.
* doxygen'ate the headers/code, to produce reference docs.
* HAVE_DOT in Doxyfile.in should be detected by configure.

3
autogen.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
autoreconf -i -s

33
configure.ac Normal file
View file

@ -0,0 +1,33 @@
AC_INIT([umem], [1.0.2], [], [umem])
AM_INIT_AUTOMAKE([dist-bzip2])
AC_CONFIG_MACRO_DIRS([m4])
AC_PROG_CC
AM_PROG_AS
AC_PROG_LIBTOOL
AC_C_INLINE
AC_MSG_CHECKING([whether pthread_mutex_t is larger than 24 bytes])
AC_TRY_RUN(
[
#include <pthread.h>
int main(void){return (sizeof(pthread_mutex_t) > 24);}
],
[AC_MSG_RESULT(yes)],
[
AC_MSG_RESULT(no)
AC_DEFINE(UMEM_PTHREAD_MUTEX_TOO_BIG, [1], [need bigger cache])
AC_MSG_WARN([*** increasing umem cpu cache size to compensate.])
]
)
AC_CHECK_LIB(dl,dlopen)
AC_CHECK_HEADERS([sys/mman.h sys/sysmacros.h sys/time.h malloc.h])
AC_CHECK_FUNCS([issetugid mallinfo malloc_stats])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile Doxyfile umem.spec])
AC_OUTPUT

142
envvar.c
View file

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -19,12 +18,14 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2012 Joyent, Inc. All rights reserved.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
/* #pragma ident "@(#)envvar.c 1.5 05/06/08 SMI" */
@ -91,10 +92,34 @@ typedef struct umem_env_item {
#ifndef UMEM_STANDALONE
static arg_process_t umem_backend_process;
static arg_process_t umem_allocator_process;
#endif
#ifdef __GLIBC__
/* replace getenv() with a specialized version that doesn't
* need to allocate memory. We can't use strlen or strcmp
* here. */
#include <unistd.h>
static char *safe_getenv(const char *name)
{
int i, l;
for (l = 0; name[l]; l++)
;
for (i = 0; __environ[i]; i++) {
if (!memcmp(__environ[i], name, l) && __environ[i][l] == '=') {
return &__environ[i][l+1];
}
}
return NULL;
}
#define getenv(x) safe_getenv(x)
#endif
static arg_process_t umem_log_process;
static size_t umem_size_tempval;
static arg_process_t umem_size_process;
const char *____umem_environ_msg_options = "-- UMEM_OPTIONS --";
static umem_env_item_t umem_options_items[] = {
@ -104,6 +129,11 @@ static umem_env_item_t umem_options_items[] = {
NULL, 0, NULL, NULL,
&umem_backend_process
},
{ "allocator", "Evolving", ITEM_SPECIAL,
"=best, =first, =next, or =instant",
NULL, 0, NULL, NULL,
&umem_allocator_process
},
#endif
{ "concurrency", "Private", ITEM_UINT,
@ -124,8 +154,27 @@ static umem_env_item_t umem_options_items[] = {
NULL, 0, &umem_reap_interval
},
{ "size_add", "Private", ITEM_SPECIAL,
"add a size to the cache size table",
NULL, 0, NULL,
&umem_size_tempval, &umem_size_process
},
{ "size_clear", "Private", ITEM_SPECIAL,
"clear all but the largest size from the cache size table",
NULL, 0, NULL,
&umem_size_tempval, &umem_size_process
},
{ "size_remove", "Private", ITEM_SPECIAL,
"remove a size from the cache size table",
NULL, 0, NULL,
&umem_size_tempval, &umem_size_process
},
#ifndef _WIN32
#ifndef UMEM_STANDALONE
{ "sbrk_minalloc", "Private", ITEM_SIZE,
"The minimum allocation chunk for the sbrk(2) heap.",
NULL, 0, NULL, &vmem_sbrk_minalloc
},
{ "sbrk_pagesize", "Private", ITEM_SIZE,
"The preferred page size for the sbrk(2) heap.",
NULL, 0, NULL, &vmem_sbrk_pagesize
@ -393,6 +442,49 @@ umem_log_process(const umem_env_item_t *item, const char *item_arg)
return (ARG_SUCCESS);
}
static int
umem_size_process(const umem_env_item_t *item, const char *item_arg)
{
const char *name = item->item_name;
void (*action_func)(size_t);
size_t result;
int ret;
if (strcmp(name, "size_clear") == 0) {
if (item_arg != NULL) {
log_message("%s: %s: does not take a value. ignored\n",
CURRENT, name);
return (ARG_BAD);
}
umem_alloc_sizes_clear();
return (ARG_SUCCESS);
} else if (strcmp(name, "size_add") == 0) {
action_func = umem_alloc_sizes_add;
} else if (strcmp(name, "size_remove") == 0) {
action_func = umem_alloc_sizes_remove;
} else {
log_message("%s: %s: internally unrecognized\n",
CURRENT, name, name, name);
return (ARG_BAD);
}
if (item_arg == NULL) {
log_message("%s: %s: requires a value. ignored\n",
CURRENT, name);
return (ARG_BAD);
}
ret = item_size_process(item, item_arg);
if (ret != ARG_SUCCESS)
return (ret);
result = *item->item_size_target;
action_func(result);
return (ARG_SUCCESS);
}
#ifndef UMEM_STANDALONE
static int
umem_backend_process(const umem_env_item_t *item, const char *item_arg)
@ -416,6 +508,35 @@ fail:
CURRENT, name, name, name);
return (ARG_BAD);
}
static int
umem_allocator_process(const umem_env_item_t *item, const char *item_arg)
{
const char *name = item->item_name;
if (item_arg == NULL)
goto fail;
if (strcmp(item_arg, "best") == 0)
vmem_allocator = VM_BESTFIT;
else if (strcmp(item_arg, "next") == 0)
vmem_allocator = VM_NEXTFIT;
else if (strcmp(item_arg, "first") == 0)
vmem_allocator = VM_FIRSTFIT;
else if (strcmp(item_arg, "instant") == 0)
vmem_allocator = 0;
else
goto fail;
return (ARG_SUCCESS);
fail:
log_message("%s: %s: must be %s=best, %s=next or %s=first\n",
CURRENT, name, name, name, name);
return (ARG_BAD);
}
#endif
static int
@ -553,6 +674,7 @@ umem_setup_envvars(int invalid)
static volatile enum {
STATE_START,
STATE_GETENV,
STATE_DLOPEN,
STATE_DLSYM,
STATE_FUNC,
STATE_DONE
@ -577,6 +699,10 @@ umem_setup_envvars(int invalid)
where = "during getenv(3C) calls -- "
"getenv(3C) results ignored.";
break;
case STATE_DLOPEN:
where = "during dlopen(3C) call -- "
"_umem_*() results ignored.";
break;
case STATE_DLSYM:
where = "during dlsym(3C) call -- "
"_umem_*() results ignored.";
@ -623,6 +749,8 @@ umem_setup_envvars(int invalid)
# define dlclose(a) 0
# define dlerror() 0
#endif
state = STATE_DLOPEN;
/* get a handle to the "a.out" object */
if ((h = dlopen(0, RTLD_FIRST | RTLD_LAZY)) != NULL) {
for (cur_env = umem_envvars; cur_env->env_name != NULL;

117
gdb-macros Normal file
View file

@ -0,0 +1,117 @@
# vim:ft=gdb:ts=2:sw=2:et:
set $UMF_AUDIT = 1
set $UMF_DEADBEEF = 2
set $UMF_REDZONE = 4
set $UMF_CONTENTS = 8
set $UMF_CHECKSIGNAL = 16
set $UMF_NOMAGAZINE = 32
set $UMF_FIREWALL = 64
set $UMF_LITE = 128
set $UMF_HASH = 256
set $UMF_RANDOMIZE = 512
define umastat_cache
set $cp = $arg0
set $meminuse = ($cp->cache_slab_create - $cp->cache_slab_destroy) * $cp->cache_slabsize
if (($cp->cache_cpu[0].cc_magsize != 0) || ($cp->cache_flags & $UMF_NOMAGAZINE))
set $magsize = $cp->cache_cpu[0].cc_magsize
else
set $magsize = $cp->cache_magtype->mt_magsize
end
set $alloc = $cp->cache_slab_alloc + $cp->cache_full.ml_alloc
set $avail = $cp->cache_full.ml_total * $magsize
set $total = $cp->cache_buftotal
# walk the cpu caches
set $cpu_current = 0
while $cpu_current < umem_max_ncpus
set $cpu = umem_cpus[$cpu_current]
set $cpu_cache = (umem_cpu_cache_t*)((char*)$cp + $cpu->cpu_cache_offset)
if $cpu_cache->cc_rounds > 0
set $avail = $avail + $cpu_cache->cc_rounds
end
if $cpu_cache->cc_prounds > 0
set $avail = $avail + $cpu_cache->cc_prounds
end
set $alloc = $alloc + $cpu_cache->cc_alloc
set $cpu_current = $cpu_current + 1
end
# walk some slabs
set $slab = $cp->cache_nullslab.slab_next
while $slab != &$cp->cache_nullslab
set $avail = $avail + $slab->slab_chunks - $slab->slab_refcnt
set $slab = $slab->slab_next
end
printf "%-25s %6u %6u %6u %9u %9u %5llu\n", $cp->cache_name, $cp->cache_bufsize, $total - $avail, $total, $meminuse, $alloc, $cp->cache_alloc_fail
end
document umastat
umem allocator stats
end
define umastat
printf "cache buf buf buf memory alloc alloc\n"
printf "name size in use total in use succeed fail\n"
printf "---------------------------- ------ ------ ------ --------- --------- -----\n"
set $cp = umem_null_cache->cache_next
while $cp != &umem_null_cache
umastat_cache $cp
set $cp = $cp->cache_next
end
printf "---------------------------- ------ ------ ------ --------- --------- -----\n"
set $vmem = vmem_list
while $vmem != 0
set $meminuse = 0
set $alloc = 0
set $fail = 0
set $cp = umem_null_cache->cache_next
while $cp != &umem_null_cache
if $cp->cache_arena == $vmem
set $meminuse = $meminuse + (($cp->cache_slab_create - $cp->cache_slab_destroy) * $cp->cache_slabsize)
if (($cp->cache_cpu[0].cc_magsize != 0) || ($cp->cache_flags & $UMF_NOMAGAZINE))
set $magsize = $cp->cache_cpu[0].cc_magsize
else
set $magsize = $cp->cache_magtype->mt_magsize
end
set $alloc = $alloc + ($cp->cache_slab_alloc + $cp->cache_full.ml_alloc)
set $avail = $avail + ($cp->cache_full.ml_total * $magsize)
end
set $cp = $cp->cache_next
end
printf "Total %-25s %9u %9u %5u\n", $vmem->vm_name, $meminuse, $alloc, $fail
set $vmem = $vmem->vm_next
end
end
define umem_status
printf "Concurrency:\t%d\n", umem_max_ncpus
printf "Logs\t\t"
if umem_transaction_log != 0
printf "transaction=%d ", umem_transaction_log->lh_chunksize * umem_transaction_log->lh_nchunks
end
if umem_content_log != 0
printf "content=%d ", umem_content_log->lh_chunksize * umem_content_log->lh_nchunks
end
if umem_failure_log != 0
printf "fail=%d ", umem_failure_log->lh_chunksize * umem_failure_log->lh_nchunks
end
if umem_slab_log != 0
printf "slab=%d ", umem_slab_log->lh_chunksize * umem_slab_log->lh_nchunks
end
if umem_logging == 0
printf "(inactive)"
end
printf "\nMessage buffer:\n"
set $msg = &umem_error_buffer + umem_error_begin
printf "%s", $msg
end

View file

@ -20,11 +20,11 @@
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
* Portions Copyright 2006-2008 Message Systems, Inc.
*/
/* #pragma ident "@(#)getpcstack.c 1.5 05/06/08 SMI" */

17
hello.c Normal file
View file

@ -0,0 +1,17 @@
#include <stdio.h>
#include <stdlib.h>
int main() {
char *ptr = (char *)malloc(4096);
snprintf(ptr, 4096, "%s", "Hello, World!");
printf("%s 0x%p\n", ptr, ptr);
return 0;
}
/*
* Local variables:
* tab-width:4
* compile-command: "gcc -fpic -Wall -Werror -Ofast -march=native -mtune=native hello.c -o hello"
* End:
*/

View file

@ -19,12 +19,12 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
/* #pragma ident "@(#)init_lib.c 1.2 05/06/08 SMI" */
@ -44,33 +44,43 @@
#include <dlfcn.h>
#endif
#include <fcntl.h>
#include <string.h>
#ifdef __FreeBSD__
#include <machine/param.h>
#endif
void
vmem_heap_init(void)
{
#ifdef _WIN32
vmem_backend = VMEM_BACKEND_MMAP;
(void) vmem_sbrk_arena(NULL, NULL);
#else
#if 0
# if defined(sun)
void *handle = dlopen("libmapmalloc.so.1", RTLD_NOLOAD);
if (handle != NULL) {
#endif
log_message("sbrk backend disabled\n");
vmem_backend = VMEM_BACKEND_MMAP;
#if 0
}
#endif
# else
if (vmem_backend == 0) {
/* prefer mmap, as sbrk() seems to have problems wither working
* with other allocators or has some Solaris specific assumptions. */
vmem_backend = VMEM_BACKEND_MMAP;
}
# endif
if ((vmem_backend & VMEM_BACKEND_MMAP) != 0) {
vmem_backend = VMEM_BACKEND_MMAP;
(void) vmem_mmap_arena(NULL, NULL);
} else {
#ifndef _WIN32
vmem_backend = VMEM_BACKEND_SBRK;
(void) vmem_sbrk_arena(NULL, NULL);
#endif
}
#endif
}
/*ARGSUSED*/
@ -81,15 +91,55 @@ umem_type_init(caddr_t start, size_t len, size_t pgsize)
SYSTEM_INFO info;
GetSystemInfo(&info);
pagesize = info.dwPageSize;
#else
#elif !defined(__FreeBSD__)
pagesize = _sysconf(_SC_PAGESIZE);
#else
pagesize = PAGE_SIZE;
#endif
}
int
umem_get_max_ncpus(void)
{
#ifdef _SC_NPROCESSORS_ONLN
#ifdef linux
/*
* HACK: sysconf() will invoke malloc() on Linux as part of reading
* in /proc/stat. To avoid recursion in the malloc replacement
* version of libumem, read /proc/stat into a static buffer.
*/
static int ncpus = 0;
if (ncpus == 0) {
char proc_stat[8192];
int fd;
ncpus = 1;
fd = open("/proc/stat", O_RDONLY);
if (fd >= 0) {
const ssize_t n = read(fd, proc_stat, sizeof(proc_stat) - 1);
if (n >= 0) {
const char *cur;
const char *next;
proc_stat[n] = '\0';
cur = proc_stat;
while (*cur && (next = strstr(cur + 3, "cpu"))) {
cur = next;
}
if (*cur)
ncpus = atoi(cur + 3) + 1;
}
close(fd);
}
}
return ncpus;
#else /* !linux */
#if _SC_NPROCESSORS_ONLN
return (2 * sysconf(_SC_NPROCESSORS_ONLN));
#elif defined(_SC_NPROCESSORS_CONF)
return (2 * sysconf(_SC_NPROCESSORS_CONF));
@ -101,4 +151,6 @@ umem_get_max_ncpus(void)
/* XXX: determine CPU count on other platforms */
return (1);
#endif
#endif /* linux */
}

View file

@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/

1
m4/libtool.m4 vendored Symbolic link
View file

@ -0,0 +1 @@
/usr/share/aclocal/libtool.m4

1
m4/ltoptions.m4 vendored Symbolic link
View file

@ -0,0 +1 @@
/usr/share/aclocal/ltoptions.m4

1
m4/ltsugar.m4 vendored Symbolic link
View file

@ -0,0 +1 @@
/usr/share/aclocal/ltsugar.m4

1
m4/ltversion.m4 vendored Symbolic link
View file

@ -0,0 +1 @@
/usr/share/aclocal/ltversion.m4

1
m4/lt~obsolete.m4 vendored Symbolic link
View file

@ -0,0 +1 @@
/usr/share/aclocal/lt~obsolete.m4

View file

@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@ -33,7 +34,9 @@
#include <string.h>
#ifdef HAVE_SYS_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#include "umem_base.h"
@ -224,6 +227,16 @@ memalign(size_t align, size_t size_arg)
return ((void *)ret);
}
int
posix_memalign(void **memptr, size_t alignment, size_t size)
{
*memptr = memalign(alignment, size);
if (*memptr) {
return 0;
}
return errno;
}
void *
valloc(size_t size)
{
@ -395,6 +408,11 @@ realloc(void *buf_arg, size_t newsize)
if (buf_arg == NULL)
return (malloc(newsize));
if (newsize == 0) {
free(buf_arg);
return (NULL);
}
/*
* get the old data size without freeing the buffer
*/

20
misc.c
View file

@ -19,12 +19,12 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
/* #pragma ident "@(#)misc.c 1.6 05/06/08 SMI" */
@ -49,7 +49,6 @@
#include <umem_impl.h>
#include "misc.h"
#include "util.h"
#define UMEM_ERRFD 2 /* goes to standard error */
#define UMEM_MAX_ERROR_SIZE 4096 /* error messages are truncated to this */
@ -63,6 +62,9 @@
#define ERR_SIZE 8192 /* must be a power of 2 */
static mutex_t umem_error_lock = DEFAULTMUTEX;
#ifdef NEED_64_LOCK
pthread_mutex_t umem_ppc_64inc_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
static char umem_error_buffer[ERR_SIZE] = "";
static uint_t umem_error_begin = 0;
@ -74,13 +76,12 @@ static uint_t umem_error_end = 0;
}
static void
umem_log_enter(const char *error_str, int serious)
umem_log_enter(const char *error_str)
{
int looped;
char c;
looped = 0;
mem_printf(serious ? DCRITICAL : DINFO, "umem: %s", error_str);
(void) mutex_lock(&umem_error_lock);
@ -113,7 +114,7 @@ umem_error_enter(const char *error_str)
(void) write(UMEM_ERRFD, error_str, strlen(error_str));
#endif
umem_log_enter(error_str, 1);
umem_log_enter(error_str);
}
int
@ -199,7 +200,7 @@ log_message(const char *format, ...)
(void) write(UMEM_ERRFD, buf, strlen(buf));
#endif
umem_log_enter(buf, 0);
umem_log_enter(buf);
}
#ifndef UMEM_STANDALONE
@ -288,6 +289,7 @@ print_sym(void *pointer)
return (1);
}
#else
umem_printf("?? (0x%p)", pointer);
return 0;
#endif
}

10
misc.h
View file

@ -19,12 +19,12 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
#ifndef _MISC_H
@ -75,7 +75,7 @@ void log_message(const char *format, ...);
* returns the index of the (high/low) bit + 1
*/
int highbit(ulong_t) __attribute__ ((pure));
int lowbit(ulong_t) __attribute__ ((pure));;
int lowbit(ulong_t) __attribute__ ((pure));
/* #pragma no_side_effect(highbit, lowbit) */
/*

View file

@ -1,11 +1,30 @@
/*
* Copyright (c) 2006 OmniTI, Inc. All rights reserved
* Copyright (c) 2006-2008 Message Systems, Inc. All rights reserved
* This header file distributed under the terms of the CDDL.
* Portions Copyright 2004 Sun Microsystems, Inc. All Rights reserved.
*/
#ifndef _EC_UMEM_SOL_COMPAT_H_
#define _EC_UMEM_SOL_COMPAT_H_
#include "config.h"
#include <stdint.h>
#include <pthread.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef _WIN32
# define THR_RETURN DWORD
# define THR_API WINAPI
# define INLINE __inline
#else
# define THR_RETURN void *
# define THR_API
# define INLINE inline
#endif
#if defined(__MACH__) || defined(_WIN32)
#define NO_WEAK_SYMBOLS
#define _umem_cache_alloc(a,b) umem_cache_alloc(a,b)
@ -40,7 +59,7 @@ static INLINE hrtime_t gethrtime(void) {
static INLINE thread_t _thr_self(void) {
return thr_self();
}
#if defined(_MACH_PORT_T)
#if defined(__MACH__)
#define CPUHINT() (pthread_mach_thread_np(pthread_self()))
#endif
# define thr_sigsetmask pthread_sigmask
@ -89,7 +108,92 @@ static INLINE int thr_create(void *stack_base,
# define RTLD_FIRST 0
#endif
#include "ec_atomic.h"
#ifdef ECELERITY
# include "umem_atomic.h"
#else
# ifdef _WIN32
# define umem_atomic_inc(a) InterlockedIncrement(a)
# define umem_atomic_inc64(a) InterlockedIncrement64(a)
# elif defined(__MACH__)
# include <libkern/OSAtomic.h>
# define umem_atomic_inc(x) OSAtomicIncrement32Barrier((int32_t*)x)
# if !defined(__ppc__)
# define umem_atomic_inc64(x) OSAtomicIncrement64Barrier((int64_t*)x)
# endif
# elif (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__)
static INLINE uint_t umem_atomic_cas(uint_t *mem, uint_t with, uint_t cmp)
{
uint_t prev;
asm volatile ("lock; cmpxchgl %1, %2"
: "=a" (prev)
: "r" (with), "m" (*(mem)), "0" (cmp)
: "memory");
return prev;
}
static INLINE uint64_t umem_atomic_cas64(uint64_t *mem, uint64_t with,
uint64_t cmp)
{
uint64_t prev;
# if defined(__x86_64__)
__asm__ volatile ("lock; cmpxchgq %1, %2"
: "=a" (prev)
: "r" (with), "m" (*(mem)), "0" (cmp)
: "memory");
# else
__asm__ volatile (
"pushl %%ebx;"
"mov 4+%1,%%ecx;"
"mov %1,%%ebx;"
"lock;"
"cmpxchg8b (%3);"
"popl %%ebx"
: "=A" (prev)
: "m" (with), "A" (cmp), "r" (mem)
: "%ecx", "memory");
# endif
return prev;
}
static INLINE uint64_t umem_atomic_inc64(uint64_t *mem)
{
register uint64_t last;
do {
last = *mem;
} while (umem_atomic_cas64(mem, last+1, last) != last);
return ++last;
}
# define umem_atomic_inc64 umem_atomic_inc64
# else
# error no atomic solution for your platform
# endif
# ifndef umem_atomic_inc
static INLINE uint_t umem_atomic_inc(uint_t *mem)
{
register uint_t last;
do {
last = *mem;
} while (umem_atomic_cas(mem, last+1, last) != last);
return ++last;
}
# endif
# ifndef umem_atomic_inc64
/* yeah, it's not great. It's only used to bump failed allocation
* counts, so it is not critical right now. */
extern pthread_mutex_t umem_ppc_64inc_lock;
static INLINE uint64_t umem_atomic_inc64(uint64_t *val)
{
uint64_t rval;
pthread_mutex_lock(&umem_ppc_64inc_lock);
rval = *val + 1;
*val = rval;
pthread_mutex_unlock(&umem_ppc_64inc_lock);
return rval;
}
# define umem_atomic_inc64 umem_atomic_inc64
# define NEED_64_LOCK 1
# endif
#endif
#define P2PHASE(x, align) ((x) & ((align) - 1))
#define P2ALIGN(x, align) ((x) & -(align))
@ -101,10 +205,18 @@ static INLINE int thr_create(void *stack_base,
#define P2SAMEHIGHBIT(x, y) (((x) ^ (y)) < ((x) & (y)))
#define IS_P2ALIGNED(v, a) ((((uintptr_t)(v)) & ((uintptr_t)(a) - 1)) == 0)
#define ISP2(x) (((x) & ((x) - 1)) == 0)
/*
* return TRUE if adding len to off would cause it to cross an align
* boundary.
* eg, P2BOUNDARY(0x1234, 0xe0, 0x100) == TRUE (0x1234 + 0xe0 == 0x1314)
* eg, P2BOUNDARY(0x1234, 0x50, 0x100) == FALSE (0x1234 + 0x50 == 0x1284)
*/
#define P2BOUNDARY(off, len, align) \
(((off) ^ ((off) + (len) - 1)) > (align) - 1)
/* beware! umem only uses these atomic adds for incrementing by 1 */
#define atomic_add_64(lvalptr, delta) ec_atomic_inc64(lvalptr)
#define atomic_add_32_nv(a, b) ec_atomic_inc(a)
#define atomic_add_64(lvalptr, delta) umem_atomic_inc64(lvalptr)
#define atomic_add_32_nv(a, b) umem_atomic_inc(a)
#ifndef NANOSEC
#define NANOSEC 1000000000
@ -112,7 +224,7 @@ static INLINE int thr_create(void *stack_base,
#ifdef _WIN32
#define issetugid() 0
#else
#elif !HAVE_ISSETUGID
#define issetugid() (geteuid() == 0)
#endif
@ -130,4 +242,12 @@ static INLINE int __nthreads(void)
# define _LP64 1
#endif
#ifndef MIN
# define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAX
# define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#endif

View file

@ -19,8 +19,9 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/

View file

@ -22,9 +22,8 @@
/*
* Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
#ifndef _SYS_VMEM_IMPL_USER_H

521
test.c Normal file
View file

@ -0,0 +1,521 @@
/* malloc-test.c
* by Wolfram Gloger 1995, 1996
*
* This program is provided `as is', there is no warranty.
* https://raw.githubusercontent.com/emeryberger/Malloc-Implementations/master/allocators/CAMA/malloc-test.c
*/
#if !defined(__STDC__)
#define __STDC__ 1
#endif
#include <stdlib.h>
#include <stdio.h>
#if !defined(_WIN32)
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#endif
#ifndef MEMORY
#define MEMORY 4000000l
#endif
#ifndef BINS_MAX
#define BINS_MAX 32768
#endif
#define SBINS_MAX 1024
#define SIZE 4024
#define I_MAX 5000
#ifndef I_AVERAGE
#define I_AVERAGE 200
#endif
#define ACTIONS_MAX 50
#ifndef SBRK_AVG
#define SBRK_AVG 0
#endif
#ifndef MMAP_THRESH
#define MMAP_THRESH 0
#endif
#ifndef TEST
#define TEST 4 /* minimal testing */
#endif
#ifndef TEST_INC
#define TEST_INC 2047
#endif
#if defined(__i386__) || defined(__sparc__) || defined(mips) || defined(_WIN32)
#define PAGE_SIZE 4096
#elif defined(__alpha__)
#define PAGE_SIZE 8192
#elif defined(__SVR4)
#define PAGE_SIZE 8192
#else
#define PAGE_SIZE 4096 /* default */
#endif
#define RANDOM(s) (lran2(0) % (s))
/* All probabilities are parts in 1024. */
#ifndef PROB_MEMALIGN
#define PROB_MEMALIGN 0
#endif
#ifndef PROB_REALLOC
#define PROB_REALLOC 48
#endif
#ifndef PROB_CALLOC
#define PROB_CALLOC 0
#endif
struct bin {
unsigned char *ptr;
unsigned long size;
} m[BINS_MAX], sm[SBINS_MAX];
unsigned long size = SIZE, bins=0, sbins=0;
unsigned long total_size=0, total_size_max=0;
unsigned char *base_ptr;
unsigned long base_save;
long
#if __STDC__
lran2(long seed)
#else
lran2(seed) long seed;
#endif
#define LRAN2_MAX 714025l /* constants for portable */
#define IA 1366l /* random number generator */
#define IC 150889l /* (see Numerical Recipes p. 211) */
{
static int first = 1;
static long x, y, v[97];
int j;
if(seed || first) {
first = 0;
x = (IC - seed) % LRAN2_MAX;
if(x < 0) x = -x;
for(j=0; j<97; j++) {
x = (IA*x + IC) % LRAN2_MAX;
v[j] = x;
}
x = (IA*x + IC) % LRAN2_MAX;
y = x;
}
j = y % 97;
y = v[j];
x = (IA*x + IC) % LRAN2_MAX;
v[j] = x;
return y;
}
#undef IA
#undef IC
void
#if __STDC__
mem_init(unsigned char *ptr, unsigned long size)
#else
mem_init(ptr, size) unsigned char *ptr; unsigned long size;
#endif
{
unsigned long i, j;
if(size == 0) return;
if(size > sizeof(unsigned long)) {
/* Try the complete initial word. */
*(unsigned long *)ptr = (unsigned long)ptr ^ size;
i = TEST_INC;
} else
i = 0;
for(; i<size; i+=TEST_INC) {
j = (unsigned long)ptr ^ i;
ptr[i] = ((j ^ (j>>8)) & 0xFF);
}
j = (unsigned long)ptr ^ (size-1);
ptr[size-1] = ((j ^ (j>>8)) & 0xFF);
}
int
#if __STDC__
mem_check(unsigned char *ptr, unsigned long size)
#else
mem_check(ptr, size) unsigned char *ptr; unsigned long size;
#endif
{
unsigned long i, j;
if(size == 0) return 0;
if(size > sizeof(unsigned long)) {
if(*(unsigned long *)ptr != ((unsigned long)ptr ^ size)) {
printf ("failed size check: expected %lx, found %lx!\n",
((unsigned long) ptr ^ size), *(unsigned long *) ptr);
return 1;
}
i = TEST_INC;
} else
i = 0;
for(; i<size; i+=TEST_INC) {
j = (unsigned long)ptr ^ i;
if(ptr[i] != ((j ^ (j>>8)) & 0xFF)) return 2;
}
j = (unsigned long)ptr ^ (size-1);
if(ptr[size-1] != ((j ^ (j>>8)) & 0xFF)) {
printf ("failed last byte check: expected %lx, found %x!\n",
((unsigned long) ((j ^ (j>>8)) & 0xFF)), ptr[size-1]);
return 3;
}
return 0;
}
long
#if __STDC__
random_size(long max)
#else
random_size(max) long max;
#endif
{
long r1, r2, r, max_pages;
max_pages = max/PAGE_SIZE;
if(max_pages > 0) {
r1 = RANDOM(1024);
r2 = (r1 & 7)*4;
if(r1 < 512) {
/* small value near power of two */
r = (1L << (r1 >> 6)) + r2;
} else if(r1 < 512+20) {
/* value near a multiple of the page size */
r = (RANDOM(max_pages)+1)*PAGE_SIZE + r2 - 16;
/*printf("r = %4lx\n", r);*/
} else r = RANDOM(max) + 1;
} else r = RANDOM(max) + 1;
/*if(r <= 0) exit(-1);*/
return r;
}
void
#if __STDC__
bin_alloc(struct bin *m)
#else
bin_alloc(m) struct bin *m;
#endif
{
long r, key;
unsigned long sz;
#if TEST > 0
if(mem_check(m->ptr, m->size)) {
printf("bin_alloc: memory corrupt at %p, size=%lu!\n", m->ptr, m->size);
exit(1);
}
#endif
total_size -= m->size;
r = RANDOM(1024);
if(r < PROB_MEMALIGN) {
#if !defined(_WIN32)
if(m->size > 0) free(m->ptr);
m->size = random_size(size);
#if PROB_MEMALIGN
m->ptr = (unsigned char *)memalign(4 << RANDOM(8), m->size);
#endif
#endif
} else if(r < (PROB_MEMALIGN + PROB_REALLOC)) {
if(m->size == 0) {
#ifndef __sparc__
m->ptr = NULL;
#else
/* SunOS4 does not realloc() a NULL pointer */
m->ptr = (unsigned char *)malloc(1);
#endif
}
#if TEST > 2
key = RANDOM(256);
sz = m->size;
for(r=0; r<sz; r++) m->ptr[r] = (r ^ key) & 0xFF;
#endif
m->size = random_size(size);
/*printf("realloc %d\n", (int)m->size);*/
m->ptr = (unsigned char *)realloc(m->ptr, m->size);
#if TEST > 2
if(m->size < sz) sz = m->size;
for(r=0; r<sz; r++)
if(m->ptr[r] != ((r ^ key) & 0xFF)) {
printf("realloc bug !\n");
exit(1);
}
#endif
} else if(r < (PROB_MEMALIGN + PROB_REALLOC + PROB_CALLOC)) {
if(m->size > 0) free(m->ptr);
m->size = random_size(size);
m->ptr = (unsigned char *)calloc(m->size, 1);
#if TEST > 2
for(r=0; r<m->size; r++)
if(m->ptr[r] != '\0') {
printf("calloc bug !\n");
exit(1);
}
#endif
} else { /* normal malloc call */
if(m->size > 0) free(m->ptr);
m->size = random_size(size);
m->ptr = (unsigned char *)malloc(m->size);
}
if(!m->ptr) {
printf("out of memory!\n");
exit(1);
}
total_size += m->size;
if(total_size > total_size_max) total_size_max = total_size;
#if TEST > 0
mem_init(m->ptr, m->size);
#endif
if(m->ptr < base_ptr) {
#ifdef VERBOSE
printf("hmmm, allocating below brk...\n");
#endif
base_ptr = m->ptr;
}
}
void
#if __STDC__
bin_free(struct bin *m)
#else
bin_free(m) struct bin *m;
#endif
{
if(m->size == 0) return;
#if TEST > 0
if(mem_check(m->ptr, m->size)) {
printf("bin_free: memory corrupt!\n");
exit(1);
}
#endif
total_size -= m->size;
free(m->ptr);
m->size = 0;
}
void
bin_test()
{
unsigned int b;
int v;
// printf ("bin_test.\n");
for(b=0; b<bins; b++) {
if((v = mem_check(m[b].ptr, m[b].size))) {
printf("bin_test: memory corrupt! m[%d].ptr = %hhn, m[%d].size = %ld\n",
b, m[b].ptr, b, m[b].size);
printf ("error = %d\n", v);
exit(1);
}
}
for(b=0; b<sbins; b++) {
if(mem_check(sm[b].ptr, sm[b].size)) {
printf("bin_test: memory corrupt! sm[%d].ptr = %hhn, sm[%d].size = %ld\n",
b, sm[b].ptr, b, sm[b].size);
exit(1);
}
}
}
void
print_times()
{
#if !defined(_WIN32)
struct rusage ru;
long total_sec, total_usec;
getrusage(RUSAGE_SELF, &ru);
printf(" u=%ld.%06ldsec",
(long)ru.ru_utime.tv_sec, (long)ru.ru_utime.tv_usec);
printf(" s=%ld.%06ldsec",
(long)ru.ru_stime.tv_sec, (long)ru.ru_stime.tv_usec);
total_usec = (long)ru.ru_utime.tv_usec + (long)ru.ru_stime.tv_usec;
total_sec = (long)ru.ru_utime.tv_sec + (long)ru.ru_stime.tv_sec;
if(total_usec >= 1000000) {
total_usec -= 1000000;
total_sec++;
}
printf(" t=%ld.%06ldsec", total_sec, total_usec);
#endif
}
int
#if __STDC__
main(int argc, char *argv[])
#else
main(argc, argv) int argc; char *argv[];
#endif
{
int i, j, next_i, count, max=I_MAX, actions;
unsigned int b;
long sbrk_max, sum;
double sbrk_used_sum, total_size_sum;
if(argc > 1) max = atoi(argv[1]);
if(argc > 2) size = atoi(argv[2]);
lran2((long)max ^ size);
bins = (MEMORY/size)*4;
if(bins > BINS_MAX) bins = BINS_MAX;
#if 0 // FIX ME? Disable sbrk...
base_ptr = (unsigned char *)sbrk(0);
sum = (long)base_ptr % PAGE_SIZE;
if(sum > 0) {
if((char *)sbrk((long)PAGE_SIZE - sum) == (char *)-1) exit(1);
base_ptr += (long)PAGE_SIZE - sum;
/*printf("base_ptr = %lx\n", (long)base_ptr);*/
}
/* attempt to fill up the region below the initial brk */
void* dummy = 0;
for(i=0; i<10000; i++) {
dummy = malloc(1);
if(dummy >= (void*)base_ptr) break;
}
free(dummy);
base_save = ((unsigned long)base_ptr >> 24) << 24;
#endif
#if MMAP_THRESH > 0
if(!mallopt(-3, MMAP_THRESH)) printf("mallopt failed!\n");
if(!mallopt(-4, 200)) printf("mallopt failed!\n");
#endif
#ifdef VERBOSE
printf("# mmap_thresh=%d\n", MMAP_THRESH);
printf("# bins=%d max=%d size=%d\n", bins, max, size);
printf("# base=%lx\n", base_save);
#endif
for(b=0; b<bins; b++) {
if(RANDOM(2) == 0) bin_alloc(&m[b]);
else m[b].size = 0;
}
sbrk_max = 0;
sbrk_used_sum = total_size_sum = 0.0;
for(i=next_i=count=0; i<=max;) {
#if TEST > 1
bin_test();
#endif
#ifdef MSTATS
malloc_stats();
#endif
actions = RANDOM(ACTIONS_MAX);
for(j=0; j<actions; j++) {
b = RANDOM(bins);
bin_free(&m[b]);
#if TEST > 3
bin_test();
#endif
}
i += actions;
#ifdef AFTER_FREE
AFTER_FREE;
#endif
#if SBRK_AVG > 0
if(sbins<SBINS_MAX && RANDOM(SBRK_AVG)==0) {
/* throw in an explicit sbrk call */
sm[sbins].size = RANDOM(10000)+1;
sm[sbins].ptr = sbrk(sm[sbins].size);
if(sbins>0 && sm[sbins].ptr==(sm[sbins-1].ptr+sm[sbins-1].size)) {
sm[sbins-1].size += sm[sbins].size;
sbins--;
}
#ifdef VERBOSE
printf("sbrk #%d %p %ld\n", sbins, sm[sbins].ptr, sm[sbins].size);
#endif
#if TEST > 0
mem_init(sm[sbins].ptr, sm[sbins].size);
#endif
sbins++;
}
#endif
actions = RANDOM(ACTIONS_MAX);
for(j=0; j<actions; j++) {
b = RANDOM(bins);
bin_alloc(&m[b]);
#if TEST > 3
bin_test();
#endif
}
i += actions;
if(i >= next_i) { /* gather statistics */
count++;
#if !defined(_WIN32)
sum = (long)sbrk(0);
#else
sum = 0;
#endif
if(sum > sbrk_max) sbrk_max = sum;
sbrk_used_sum += sum;
total_size_sum += (double)total_size;
#ifdef VERBOSE
printf("%8d %7lu\n", i, total_size);
#endif
next_i += I_AVERAGE;
}
}
/* Correct sbrk values. */
sbrk_max -= (long)base_ptr;
sbrk_used_sum -= (double)count*(long)base_ptr;
#ifdef VERBOSE
printf("# initial brk: %lx\n", (long)base_ptr);
printf("# max. sbrk()'ed memory: %ld bytes\n", sbrk_max);
printf("# avg. sbrk()'ed memory: %ld bytes\n",
(long)(sbrk_used_sum/count));
printf("# current size allocated: %ld bytes\n", total_size);
printf("# maximum size allocated: %ld bytes\n", total_size_max);
printf("# average size allocated: %.1f bytes\n", total_size_sum/count);
printf("# current heap waste: %.2f%%\n",
(1.0 - (double)total_size_max/sbrk_max)*100.0);
printf("# average heap waste: %.2f%%\n",
(1.0 - (double)total_size_sum/sbrk_used_sum)*100.0);
printf("# total sbrk calls performed: %d\n", sbins);
#else
printf("size=%7ld waste=%7.3f%%", size,
/* (1.0 - (double)total_size_max/sbrk_max)*100.0, */
(1.0 - (double)total_size_sum/sbrk_used_sum)*100.0);
print_times();
printf("\n");
#endif
return 0;
}
/* testing:
* gcc -Wall -Werror -fpic -march=native -mtune=native -Ofast test.c -o test
* gcc -Wall -Werror -fpic -march=native -mtune=native -Ofast test.c -o test -lumem -lumem_malloc
*
* https://github.com/sharkdp/hyperfine
*
$ ldd test
linux-vdso.so.1 (0x00007ffc607de000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb619a4d000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb619ce9000)
$ ldd test_umem
linux-vdso.so.1 (0x00007ffd1ff59000)
libumem_malloc.so.0 => /usr/local/lib/libumem_malloc.so.0 (0x00007fe885b18000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe885926000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe885903000)
libumem.so.0 => /usr/local/lib/libumem.so.0 (0x00007fe88585b000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe885bc7000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe885855000)
$ hyperfine --warmup 3 --min-runs 10 ./test
Benchmark #1: ./test
Time (mean ± σ): 82.1 ms ± 1.1 ms [User: 81.0 ms, System: 0.9 ms]
Range (min max): 79.3 ms 84.4 ms 35 runs
$ hyperfine --warmup 3 --min-runs 10 ./test_umem
Benchmark #1: ./test_umem
Time (mean ± σ): 85.7 ms ± 1.5 ms [User: 83.2 ms, System: 2.5 ms]
Range (min max): 81.8 ms 89.2 ms 34 runs
*/
/*
* Local variables:
* tab-width:4
* compile-command: "gcc -fpic -Wall -Werror -Ofast -march=native -mtune=native test.c -o test"
* End:
*/

262
umem.c
View file

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -19,17 +18,49 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
*
* Portions Copyright 2012 Joyent, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
/* #pragma ident "@(#)umem.c 1.11 05/06/08 SMI" */
/*
/*!
* \mainpage Main Page
*
* \section README
*
* \include README
*
* \section Nuances
*
* There is a nuance in the behaviour of the umem port compared
* with umem on Solaris.
*
* On Linux umem will not return memory back to the OS until umem fails
* to allocate a chunk. On failure, umem_reap() will be called automatically,
* to return memory to the OS. If your code is going to be running
* for a long time on Linux and mixes calls to different memory allocators
* (e.g.: malloc()) and umem, your code will need to call
* umem_reap() periodically.
*
* This doesn't happen on Solaris, because malloc is replaced
* with umem calls, meaning that umem_reap() is called automatically.
*
* \section References
*
* http://docs.sun.com/app/docs/doc/816-5173/6mbb8advq?a=view
*
* http://access1.sun.com/techarticles/libumem.html
*
* \section Overview
*
* \code
* based on usr/src/uts/common/os/kmem.c r1.64 from 2001/12/18
*
* The slab allocator, as described in the following two papers:
@ -58,6 +89,7 @@
*
* * KM_SLEEP v.s. UMEM_NOFAIL
*
* * lock ordering
*
* 2. Initialization
* -----------------
@ -332,6 +364,44 @@
* If a constructor callback _does_ do a UMEM_NOFAIL allocation, and
* the nofail callback does a non-local exit, we will leak the
* partially-constructed buffer.
*
*
* 6. Lock Ordering
* ----------------
* umem has a few more locks than kmem does, mostly in the update path. The
* overall lock ordering (earlier locks must be acquired first) is:
*
* umem_init_lock
*
* vmem_list_lock
* vmem_nosleep_lock.vmpl_mutex
* vmem_t's:
* vm_lock
* sbrk_lock
*
* umem_cache_lock
* umem_update_lock
* umem_flags_lock
* umem_cache_t's:
* cache_cpu[*].cc_lock
* cache_depot_lock
* cache_lock
* umem_log_header_t's:
* lh_cpu[*].clh_lock
* lh_lock
*
* \endcode
*
* 7. Changing UMEM_MAXBUF
* -----------------------
*
* When changing UMEM_MAXBUF extra care has to be taken. It is not sufficient to
* simply increase this number. First, one must update the umem_alloc_table to
* have the appropriate number of entires based upon the new size. If this is
* not done, this will lead to libumem blowing an assertion.
*
* The second place to update, which is not required, is the umem_alloc_sizes.
* These determine the default cache sizes that we're going to support.
*/
#include "config.h"
@ -382,8 +452,12 @@ size_t pagesize;
* bytes, so that it will be 64-byte aligned. For all multiples of 64,
* the next kmem_cache_size greater than or equal to it must be a
* multiple of 64.
*
* This table must be in sorted order, from smallest to highest. The
* highest slot must be UMEM_MAXBUF, and every slot afterwards must be
* zero.
*/
static const int umem_alloc_sizes[] = {
static int umem_alloc_sizes[] = {
#ifdef _LP64
1 * 8,
1 * 16,
@ -402,17 +476,21 @@ static const int umem_alloc_sizes[] = {
P2ALIGN(8192 / 7, 64),
P2ALIGN(8192 / 6, 64),
P2ALIGN(8192 / 5, 64),
P2ALIGN(8192 / 4, 64),
P2ALIGN(8192 / 4, 64), 2304,
P2ALIGN(8192 / 3, 64),
P2ALIGN(8192 / 2, 64),
P2ALIGN(8192 / 1, 64),
P2ALIGN(8192 / 2, 64), 4544,
P2ALIGN(8192 / 1, 64), 9216,
4096 * 3,
8192 * 2,
UMEM_MAXBUF, /* = 8192 * 2 */
24576, 32768, 40960, 49152, 57344, 65536, 73728, 81920,
90112, 98304, 106496, 114688, 122880, UMEM_MAXBUF, /* 128k */
/* 24 slots for user expansion */
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
};
#define NUM_ALLOC_SIZES (sizeof (umem_alloc_sizes) / sizeof (*umem_alloc_sizes))
#define UMEM_MAXBUF 16384
static umem_magtype_t umem_magtype[] = {
{ 1, 8, 3200, 65536 },
{ 3, 16, 256, 32768 },
@ -449,21 +527,21 @@ size_t umem_minfirewall; /* hardware-enforced redzone threshold */
uint_t umem_flags = 0;
mutex_t umem_init_lock; /* locks initialization */
mutex_t umem_init_lock = DEFAULTMUTEX; /* locks initialization */
cond_t umem_init_cv = DEFAULTCV; /* initialization CV */
thread_t umem_init_thr; /* thread initializing */
int umem_init_env_ready; /* environ pre-initted */
int umem_ready = UMEM_READY_STARTUP;
static umem_nofail_callback_t *nofail_callback;
static mutex_t umem_nofail_exit_lock;
static mutex_t umem_nofail_exit_lock = DEFAULTMUTEX;
static thread_t umem_nofail_exit_thr;
static umem_cache_t *umem_slab_cache;
static umem_cache_t *umem_bufctl_cache;
static umem_cache_t *umem_bufctl_audit_cache;
mutex_t umem_flags_lock;
mutex_t umem_flags_lock = DEFAULTMUTEX;
static vmem_t *heap_arena;
static vmem_alloc_t *heap_alloc;
@ -488,8 +566,10 @@ umem_log_header_t *umem_slab_log;
extern thread_t _thr_self(void);
#ifndef CPUHINT
#define CPUHINT() (_thr_self())
# define CPUHINT() ((int)(_thr_self()))
#endif
#define CPUHINT_MAX() INT_MAX
#define CPU(mask) (umem_cpus + (CPUHINT() & (mask)))
@ -511,12 +591,12 @@ volatile thread_t umem_st_update_thr; /* only used when single-thd */
thr_self() == umem_st_update_thr)
#define IN_REAP() IN_UPDATE()
mutex_t umem_update_lock; /* cache_u{next,prev,flags} */
mutex_t umem_update_lock = DEFAULTMUTEX; /* cache_u{next,prev,flags} */
cond_t umem_update_cv = DEFAULTCV;
volatile hrtime_t umem_reap_next; /* min hrtime of next reap */
mutex_t umem_cache_lock; /* inter-cache linkage only */
mutex_t umem_cache_lock = DEFAULTMUTEX; /* inter-cache linkage only */
#ifdef UMEM_STANDALONE
umem_cache_t umem_null_cache;
@ -579,6 +659,20 @@ umem_cache_t umem_null_cache = {
ALLOC_TABLE_64, ALLOC_TABLE_64, ALLOC_TABLE_64, ALLOC_TABLE_64
static umem_cache_t *umem_alloc_table[UMEM_MAXBUF >> UMEM_ALIGN_SHIFT] = {
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024,
ALLOC_TABLE_1024
};
@ -588,6 +682,9 @@ static umem_cache_t *umem_alloc_table[UMEM_MAXBUF >> UMEM_ALIGN_SHIFT] = {
caddr_t umem_min_stack;
caddr_t umem_max_stack;
#ifndef UMEM_STANDALONE
static pthread_once_t umem_forkhandler_once = PTHREAD_ONCE_INIT;
#endif
/*
* we use the _ versions, since we don't want to be cancelled.
@ -721,6 +818,8 @@ umem_remove_updates(umem_cache_t *cp)
* Get it out of the active state
*/
while (cp->cache_uflags & UMU_ACTIVE) {
int cancel_state;
ASSERT(cp->cache_unext == NULL);
cp->cache_uflags |= UMU_NOTIFY;
@ -732,7 +831,10 @@ umem_remove_updates(umem_cache_t *cp)
ASSERT(umem_update_thr != thr_self() &&
umem_st_update_thr != thr_self());
(void) _cond_wait(&umem_update_cv, &umem_update_lock);
(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
&cancel_state);
(void) cond_wait(&umem_update_cv, &umem_update_lock);
(void) pthread_setcancelstate(cancel_state, NULL);
}
/*
* Get it out of the Work Requested state
@ -1061,7 +1163,7 @@ umem_log_enter(umem_log_header_t *lhp, void *data, size_t size)
{
void *logspace;
umem_cpu_log_header_t *clhp =
&(lhp->lh_cpu[CPU(umem_cpu_mask)->cpu_number]);
&lhp->lh_cpu[CPU(umem_cpu_mask)->cpu_number];
if (lhp == NULL || umem_logging == 0)
return (NULL);
@ -2733,6 +2835,88 @@ umem_cache_destroy(umem_cache_t *cp)
vmem_free(umem_cache_arena, cp, UMEM_CACHE_SIZE(umem_max_ncpus));
}
void
umem_alloc_sizes_clear(void)
{
int i;
umem_alloc_sizes[0] = UMEM_MAXBUF;
for (i = 1; i < NUM_ALLOC_SIZES; i++)
umem_alloc_sizes[i] = 0;
}
void
umem_alloc_sizes_add(size_t size_arg)
{
int i, j;
size_t size = size_arg;
if (size == 0) {
log_message("size_add: cannot add zero-sized cache\n",
size, UMEM_MAXBUF);
return;
}
if (size > UMEM_MAXBUF) {
log_message("size_add: %ld > %d, cannot add\n", size,
UMEM_MAXBUF);
return;
}
if (umem_alloc_sizes[NUM_ALLOC_SIZES - 1] != 0) {
log_message("size_add: no space in alloc_table for %d\n",
size);
return;
}
if (P2PHASE(size, UMEM_ALIGN) != 0) {
size = P2ROUNDUP(size, UMEM_ALIGN);
log_message("size_add: rounding %d up to %d\n", size_arg,
size);
}
for (i = 0; i < NUM_ALLOC_SIZES; i++) {
int cur = umem_alloc_sizes[i];
if (cur == size) {
log_message("size_add: %ld already in table\n",
size);
return;
}
if (cur > size)
break;
}
for (j = NUM_ALLOC_SIZES - 1; j > i; j--)
umem_alloc_sizes[j] = umem_alloc_sizes[j-1];
umem_alloc_sizes[i] = size;
}
void
umem_alloc_sizes_remove(size_t size)
{
int i;
if (size == UMEM_MAXBUF) {
log_message("size_remove: cannot remove %ld\n", size);
return;
}
for (i = 0; i < NUM_ALLOC_SIZES; i++) {
int cur = umem_alloc_sizes[i];
if (cur == size)
break;
else if (cur > size || cur == 0) {
log_message("size_remove: %ld not found in table\n",
size);
return;
}
}
for (; i + 1 < NUM_ALLOC_SIZES; i++)
umem_alloc_sizes[i] = umem_alloc_sizes[i+1];
umem_alloc_sizes[i] = 0;
}
static int
umem_cache_init(void)
{
@ -2825,6 +3009,10 @@ umem_cache_init(void)
for (i = 0; i < NUM_ALLOC_SIZES; i++) {
size_t cache_size = umem_alloc_sizes[i];
size_t align = 0;
if (cache_size == 0)
break; /* 0 terminates the list */
/*
* If they allocate a multiple of the coherency granularity,
* they get a coherency-granularity-aligned address.
@ -2852,6 +3040,9 @@ umem_cache_init(void)
for (i = 0; i < NUM_ALLOC_SIZES; i++) {
size_t cache_size = umem_alloc_sizes[i];
if (cache_size == 0)
break; /* 0 terminates the list */
cp = umem_alloc_caches[i];
while (size <= cache_size) {
@ -2859,6 +3050,7 @@ umem_cache_init(void)
size += UMEM_ALIGN;
}
}
ASSERT(size - UMEM_ALIGN == UMEM_MAXBUF);
return (1);
}
@ -2874,7 +3066,8 @@ umem_startup(caddr_t start, size_t len, size_t pagesize, caddr_t minstack,
int idx;
/* Standalone doesn't fork */
#else
umem_forkhandler_init(); /* register the fork handler */
/* register the fork handler */
(void) pthread_once(&umem_forkhandler_once, umem_forkhandler_init);
#endif
#ifdef __lint
@ -2952,9 +3145,16 @@ umem_init(void)
* someone else beat us to initializing umem. Wait
* for them to complete, then return.
*/
while (umem_ready == UMEM_READY_INITING)
(void) _cond_wait(&umem_init_cv,
while (umem_ready == UMEM_READY_INITING) {
int cancel_state;
(void) pthread_setcancelstate(
PTHREAD_CANCEL_DISABLE, &cancel_state);
(void) cond_wait(&umem_init_cv,
&umem_init_lock);
(void) pthread_setcancelstate(
cancel_state, NULL);
}
ASSERT(umem_ready == UMEM_READY ||
umem_ready == UMEM_READY_INIT_FAILED);
(void) mutex_unlock(&umem_init_lock);
@ -3156,3 +3356,13 @@ fail:
(void) mutex_unlock(&umem_init_lock);
return (0);
}
#ifndef UMEM_STANDALONE
void
__attribute__((constructor))
__umem_init (void)
{
umem_startup(NULL, 0, 0, NULL, NULL);
}
#endif

4
umem.h
View file

@ -48,13 +48,15 @@ extern void *umem_zalloc(size_t, int);
extern void umem_free(void *, size_t);
extern void umem_free_align(void *, size_t);
/*
/*!
* Flags for umem_cache_create()
*/
/*@{*/
#define UMC_NOTOUCH 0x00010000
#define UMC_NODEBUG 0x00020000
#define UMC_NOMAGAZINE 0x00040000
#define UMC_NOHASH 0x00080000
/*@}*/
struct umem_cache; /* cache structure is opaque to umem clients */

129
umem.spec.in Normal file
View file

@ -0,0 +1,129 @@
Name: @PACKAGE_NAME@
Version: @PACKAGE_VERSION@
Release: 2%{?dist}
Summary: Port of Solaris's slab allocator.
Group: System Environment/Libraries
License: CDDL
URL: https://labs.omniti.com/trac/portableumem/
Source0: %{name}-%{version}.tar.bz2
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: autoconf >= 2.50
BuildRequires: automake >= 1.4
BuildRequires: libtool >= 1.4.2
BuildRequires: doxygen
BuildRequires: gcc
BuildRequires: binutils
BuildRequires: make
BuildRequires: mktemp
%description
This a port of Solaris's slab allocator, libumem, to Linux.
"A slab allocator is a cache management structure for efficient use
of [...] memory. [...] It is targeted for use of many small pieces
of memory chunks. By managing small memory chunks in the units
called slabs, this mechanism enables lower fragmentation, fast allocation,
and reclaming memory." (Description sourced from Wikipedia.)
%prep
%setup -q
%build
%configure
%{__make}
%{__make} check
%{__make} html
%install
rm -rf $RPM_BUILD_ROOT
%makeinstall
# Remove the libtool files -- we don't want them.
find $RPM_BUILD_ROOT%{_libdir} -name '*.la' | xargs rm -fv
# Remove the symlink to the SONAME. Let ldconfig manage that.
rm -fv $RPM_BUILD_ROOT%{_libdir}/*.so.[0-9]
# Build the pkgconfig configurations.
mkdir -p $RPM_BUILD_ROOT%{_libdir}/pkgconfig
cat<<EOT >$RPM_BUILD_ROOT%{_libdir}/pkgconfig/%{name}-%{version}.pc
prefix=%{_prefix}
exec_prefix=%{_exec_prefix}
libdir=%{_libdir}
includedir=%{_includedir}
Name: %{name}
Version: %{version}
Description: Port of Solaris's slab allocator.
URL: https://labs.omniti.com/trac/portableumem/
Requires:
Libs: -L\${libdir} -lumem
Cflags:
EOT
cat<<EOT >$RPM_BUILD_ROOT%{_libdir}/pkgconfig/%{name}-malloc-%{version}.pc
prefix=%{_prefix}
exec_prefix=%{_exec_prefix}
libdir=%{_libdir}
includedir=%{_includedir}
Name: %{name}
Version: %{version}
Description: Port of Solaris's slab allocator. Libc malloc replacement.
URL: https://labs.omniti.com/trac/portableumem/
Requires:
Libs: -L\${libdir} -lumem_malloc
Cflags:
EOT
%clean
rm -rf $RPM_BUILD_ROOT
%pre
/sbin/ldconfig
%post
/sbin/ldconfig
%files
%defattr(-,root,root,-)
%doc AUTHORS COPYING COPYRIGHT INSTALL NEWS OPENSOLARIS.LICENSE README
%{_libdir}/*.so.*
%package devel
Summary: Port of Solaris's slab allocator.
Group: Development/Libraries
Requires: pkgconfig
%description devel
This contains the libraries and header files for using this port
of Solaris's slab allocator, libumem, to Linux.
%files devel
%defattr(-,root,root,-)
%doc AUTHORS COPYING COPYRIGHT INSTALL NEWS OPENSOLARIS.LICENSE README TODO
%doc docs/html
%{_includedir}/*.h
%{_includedir}/sys/*.h
%{_libdir}/*.so
%{_libdir}/*.a
%{_mandir}/man*/*
%{_libdir}/pkgconfig/*.pc

View file

@ -22,9 +22,8 @@
/*
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
/* #pragma ident "@(#)umem_agent_support.c 1.2 05/06/08 SMI" */

525
umem_alloc.3 Normal file
View file

@ -0,0 +1,525 @@
'\" te
.\" CDDL HEADER START
.\"
.\" The contents of this file are subject to the terms of the
.\" Common Development and Distribution License (the "License").
.\" You may not use this file except in compliance with the License.
.\"
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
.\" or http://www.opensolaris.org/os/licensing.
.\" See the License for the specific language governing permissions
.\" and limitations under the License.
.\"
.\" When distributing Covered Code, include this CDDL HEADER in each
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
.\" If applicable, add the following below this CDDL HEADER, with the
.\" fields enclosed by brackets "[]" replaced with your own identifying
.\" information: Portions Copyright [yyyy] [name of copyright owner]
.\"
.\" CDDL HEADER END
.\" Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved.
.TH umem_alloc 3MALLOC "26 Aug 2002" "SunOS 5.11" "Memory Allocation Library Functions"
.SH NAME
umem_alloc, umem_zalloc, umem_free, umem_nofail_callback \- fast, scalable memory allocation
.SH SYNOPSIS
.LP
.nf
cc [ \fIflag \&.\|.\|.\fR ] \fIfile\fR\&.\|.\|. \fB-lumem\fR [ \fIlibrary \&.\|.\|.\fR ]
#include <umem.h>
\fBvoid *\fR\fBumem_alloc\fR(\fBsize_t\fR \fIsize\fR, \fBint\fR \fIflags\fR);
.fi
.LP
.nf
\fBvoid *\fR\fBumem_zalloc\fR(\fBsize_t\fR \fIsize\fR, \fBint\fR \fIflags\fR);
.fi
.LP
.nf
\fBvoid\fR \fBumem_free\fR(\fBvoid *\fR\fIbuf\fR, \fBsize_t\fR \fIsize\fR);
.fi
.LP
.nf
\fBvoid\fR \fBumem_nofail_callback\fR(\fB(int (*\fR\fIcallback\fR)(void));
.fi
.LP
.nf
\fBvoid *\fR\fBmalloc\fR(\fBsize_t\fR \fIsize\fR);
.fi
.LP
.nf
\fBvoid *\fR\fBcalloc\fR(\fBsize_t\fR \fInelem\fR, \fBsize_t\fR \fIelsize\fR);
.fi
.LP
.nf
\fBvoid\fR \fBfree\fR(\fBvoid *\fR\fIptr\fR);
.fi
.LP
.nf
\fBvoid *\fR\fBmemalign\fR(\fBsize_t\fR \fIalignment\fR, \fBsize_t\fR \fIsize\fR);
.fi
.LP
.nf
\fBvoid *\fR\fBrealloc\fR(\fBvoid *\fR\fIptr\fR, \fBsize_t\fR \fIsize\fR);
.fi
.LP
.nf
\fBvoid *\fR\fBvalloc\fR(\fBsize_t\fR \fIsize\fR);
.fi
.SH DESCRIPTION
.LP
The \fBumem_alloc()\fR function returns a pointer to a block of \fIsize\fR bytes suitably aligned for any variable type. The initial contents of memory allocated using \fBumem_alloc()\fR is undefined. The \fIflags\fR argument determines
the behavior of \fBumem_alloc()\fR if it is unable to fulfill the request. The \fIflags\fR argument can take the following values:
.sp
.sp
.ne 2
.mk
.na
\fB\fBUMEM_DEFAULT\fR\fR
.ad
.RS 14n
.rt
Return \fINULL\fR on failure.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBUMEM_NOFAIL\fR\fR
.ad
.RS 14n
.rt
Call an optional \fIcallback\fR (set with \fBumem_nofail_callback()\fR) on failure. The \fIcallback\fR takes no arguments and can finish by:
.sp
.sp
.RS +4
.TP
.ie t \(bu
.el o
returning \fBUMEM_CALLBACK_RETRY\fR, in which case the allocation will be retried. If the allocation fails, the callback will be invoked again.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
returning \fBUMEM_CALLBACK_EXIT\fR(\fIstatus\fR), in which case
\fBexit\fR(2) is invoked with \fIstatus\fR
as its argument. The \fBexit()\fR function is called only once. If multiple threads return from the \fBUMEM_NOFAIL\fR callback with \fBUMEM_CALLBACK_EXIT\fR(\fIstatus\fR), one will call \fBexit()\fR while the other blocks until \fBexit()\fR terminates the program.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
invoking a context-changing function (
\fBsetcontext\fR(2)) or a non-local jump (
\fBlongjmp\fR(3C) or
\fBsiglongjmp\fR(3C), or ending the current thread of control (
\fBthr_exit\fR(3C) or
\fBpthread_exit\fR(3C). The application is responsible for any necessary cleanup. The state of \fBlibumem\fR remains consistent.
.sp
.RE
If no callback has been set or the callback has been set to \fINULL\fR, \fBumem_alloc\fR(..., \fBUMEM_NOFAIL\fR) behaves as though the callback returned \fBUMEM_CALLBACK_EXIT\fR(255).
.sp
.sp
The \fBlibumem\fR library can call callbacks from any place that a \fBUMEM_NOFAIL\fR allocation is issued. In multithreaded applications, callbacks are expected to perform their own concurrency management.
.sp
.RE
.LP
The function call \fBumem_alloc\fR(0, \fIflag\fR) always returns \fINULL\fR. The function call \fBumem_free\fR(\fINULL\fR, 0) is allowed.
.sp
.LP
The \fBumem_zalloc()\fR function has the same semantics as \fBumem_alloc()\fR, but the block of memory is initialized to zeros before it is returned.
.sp
.LP
The \fBumem_free()\fR function frees blocks previously allocated using \fBumem_alloc()\fR and \fBumem_zalloc()\fR. The buffer address and size must exactly match the original allocation. Memory must not be returned piecemeal.
.sp
.LP
The \fBumem_nofail_callback()\fR function sets the process-wide UMEM_NOFAIL callback. See the description of UMEM_NOFAIL for more information.
.sp
.LP
The \fBmalloc()\fR, \fBcalloc()\fR, \fBfree()\fR, \fBmemalign()\fR, \fBrealloc()\fR, and \fBvalloc()\fR functions are are as described in
\fBmalloc\fR(3C). The \fBlibumem\fR library provides these functions for backwards-compatibility with the standard functions.
.sp
.SH ENVIRONMENT VARIABLES
.LP
See
\fBumem_debug\fR(3MALLOC) for environment variables that effect the debugging features of the \fBlibumem\fR library.
.sp
.sp
.ne 2
.mk
.na
\fBUMEM_OPTIONS\fR
.ad
.RS 14n
.rt
Contains a list of comma-separated options. Unrecognized options are ignored. The options that are supported are:
.sp
.sp
.ne 2
.mk
.na
\fB\fBbackend\fR=\fBsbrk\fR\fR
.ad
.br
.na
\fB\fBbackend\fR=\fBmmap\fR\fR
.ad
.RS 14n
.rt
Set the underlying function used to allocate memory. This option can be set to \fBsbrk\fR (the default) for an
\fBsbrk\fR(2)-based source or \fBmmap\fR for an
\fBmmap\fR(2)-based
source. If set to a value that is not supported, \fBsbrk\fR will be used.
.sp
.RE
.RE
.SH EXAMPLES
.LP
\fBExample 1 \fRUsing the \fBumem_alloc()\fR function.
.LP
.in +2
.nf
#include <stdio.h>
#include <umem.h>
\&...
char *buf = umem_alloc(1024, UMEM_DEFAULT);
if (buf == NULL) {
fprintf(stderr, "out of memory\en");
return (1);
}
/* cannot assume anything about buf's contents */
\&...
umem_free(buf, 1024);
\&...
.fi
.in -2
.LP
\fBExample 2 \fRUsing the \fBumem_zalloc()\fR function
.LP
.in +2
.nf
#include <stdio.h>
#include <umem.h>
\&...
char *buf = umem_zalloc(1024, UMEM_DEFAULT);
if (buf == NULL) {
fprintf(stderr, "out of memory\en");
return (1);
}
/* buf contains zeros */
\&...
umem_free(buf, 1024);
\&...
.fi
.in -2
.LP
\fBExample 3 \fRUsing UMEM_NOFAIL
.LP
.in +2
.nf
#include <stdlib.h>
#include <stdio.h>
#include <umem.h>
/*
* Note that the allocation code below does not have to
* check for umem_alloc() returning NULL
*/
int
my_failure_handler(void)
{
(void) fprintf(stderr, "out of memory\en");
return (UMEM_CALLBACK_EXIT(255));
}
\&...
umem_nofail_callback(my_failure_handler);
\&...
int i;
char *buf[100];
for (i = 0; i < 100; i++)
buf[i] = umem_alloc(1024 * 1024, UMEM_NOFAIL);
\&...
for (i = 0; i < 100; i++)
umem_free(buf[i], 1024 * 1024);
\&...
.fi
.in -2
.LP
\fBExample 4 \fRUsing UMEM_NOFAIL in a multithreaded application
.LP
.in +2
.nf
#define _REENTRANT
#include <thread.h>
#include <stdio.h>
#include <umem.h>
void *
start_func(void *the_arg)
{
int *info = (int *)the_arg;
char *buf = umem_alloc(1024 * 1024, UMEM_NOFAIL);
/* does not need to check for buf == NULL */
buf[0] = 0;
...
/*
* if there were other UMEM_NOFAIL allocations,
* we would need to arrange for buf to be
* umem_free()ed upon failure.
*/
...
umem_free(buf, 1024 * 1024);
return (the_arg);
}
\&...
int
my_failure_handler(void)
{
/* terminate the current thread with status NULL */
thr_exit(NULL);
}
\&...
umem_nofail_callback(my_failure_handler);
\&...
int my_arg;
thread_t tid;
void *status;
(void) thr_create(NULL, NULL, start_func, &my_arg, 0,
NULL);
\&...
while (thr_join(0, &tid, &status) != 0)
;
if (status == NULL) {
(void) fprintf(stderr, "thread %d ran out of memory\en",
tid);
}
\&...
.fi
.in -2
.SH ATTRIBUTES
.LP
See
\fBattributes\fR(5) for descriptions of the following attributes:
.sp
.LP
.sp
.TS
tab() box;
cw(2.75i) |cw(2.75i)
lw(2.75i) |lw(2.75i)
.
ATTRIBUTE TYPEATTRIBUTE VALUE
_
Interface StabilitySee below.
_
MT-LevelMT-Safe
.TE
.LP
The \fBmalloc()\fR, \fBcalloc()\fR, \fBfree()\fR, \fBrealloc()\fR, and \fBvalloc()\fR functions are Standard. The \fBmemalign()\fR function is Stable. The \fBumem_alloc()\fR, \fBumem_zalloc()\fR, \fBumem_free()\fR, and \fBumem_nofail_callback()\fR functions are Evolving.
.sp
.SH SEE ALSO
.LP
\fBexit\fR(2),
\fBmmap\fR(2),
\fBsbrk\fR(2),
\fBbsdmalloc\fR(3MALLOC),
\fBlibumem\fR(3LIB),
\fBlongjmp\fR(3C),
\fBmalloc\fR(3C),
\fBmalloc\fR(3MALLOC),
\fBmapmalloc\fR(3MALLOC),
\fBpthread_exit\fR(3C),
\fBthr_exit\fR(3C),
\fBumem_cache_create\fR(3MALLOC),
\fBumem_debug\fR(3MALLOC),
\fBwatchmalloc\fR(3MALLOC),
\fBattributes\fR(5),
\fBstandards\fR(5)
.sp
.LP
.sp
.SH WARNINGS
.LP
Any of the following can cause undefined results:
.sp
.sp
.RS +4
.TP
.ie t \(bu
.el o
Passing a pointer returned from \fBumem_alloc()\fR or \fBumem_zalloc()\fR to \fBfree()\fR or \fBrealloc()\fR.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
Passing a pointer returned from \fBmalloc()\fR, \fBcalloc()\fR, \fBvalloc()\fR, \fBmemalign()\fR, or \fBrealloc()\fR to \fBumem_free()\fR.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
Writing past the end of a buffer allocated using \fBumem_alloc()\fR or \fBumem_zalloc()\fR
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
Performing \fBUMEM_NOFAIL\fR allocations from an
\fBatexit\fR(3C) handler.
.sp
.RE
.LP
If the \fBUMEM_NOFAIL\fR callback performs \fBUMEM_NOFAIL\fR allocations, infinite recursion can occur.
.sp
.SH NOTES
.LP
The following list compares the features of the
\fBmalloc\fR(3C),
\fBbsdmalloc\fR(3MALLOC),
\fBmalloc\fR(3MALLOC),
\fBmtmalloc\fR(3MALLOC) , and the \fBlibumem\fR
functions.
.sp
.sp
.RS +4
.TP
.ie t \(bu
.el o
The
\fBmalloc\fR(3C),
\fBbsdmalloc\fR(3MALLOC), and
\fBmalloc\fR(3MALLOC) functions have no support for concurrency. The \fBlibumem\fR and
\fBmtmalloc\fR(3MALLOC)
functions support concurrent allocations.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
The
\fBbsdmalloc\fR(3MALLOC) functions afford better performance but are space-inefficient.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
The
\fBmalloc\fR(3MALLOC) functions are space-efficient but have slower performance.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
The standard, fully SCD-compliant
\fBmalloc\fR(3C) functions are a trade-off between performance and space-efficiency.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
The
\fBmtmalloc\fR(3MALLOC) functions provide fast, concurrent \fBmalloc()\fR implementations that are not space-efficient.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
The \fBlibumem\fR functions provide a fast, concurrent allocation implementation that in most cases is more space-efficient than
\fBmtmalloc\fR(3MALLOC).
.sp
.RE

View file

@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@ -120,6 +120,10 @@ extern void umem_process_updates(void);
extern void umem_cache_applyall(void (*)(umem_cache_t *));
extern void umem_cache_update(umem_cache_t *);
extern void umem_alloc_sizes_add(size_t);
extern void umem_alloc_sizes_clear(void);
extern void umem_alloc_sizes_remove(size_t);
/*
* umem_fork.c: private interfaces
*/

815
umem_cache_create.3 Normal file
View file

@ -0,0 +1,815 @@
'\" te
.\" CDDL HEADER START
.\"
.\" The contents of this file are subject to the terms of the
.\" Common Development and Distribution License (the "License").
.\" You may not use this file except in compliance with the License.
.\"
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
.\" or http://www.opensolaris.org/os/licensing.
.\" See the License for the specific language governing permissions
.\" and limitations under the License.
.\"
.\" When distributing Covered Code, include this CDDL HEADER in each
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
.\" If applicable, add the following below this CDDL HEADER, with the
.\" fields enclosed by brackets "[]" replaced with your own identifying
.\" information: Portions Copyright [yyyy] [name of copyright owner]
.\"
.\" CDDL HEADER END
.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved.
.TH umem_cache_create 3MALLOC "4 Nov 2003" "SunOS 5.11" "Memory Allocation Library Functions"
.SH NAME
umem_cache_create, umem_cache_destroy, umem_cache_alloc, umem_cache_free \- allocation cache manipulation
.SH SYNOPSIS
.LP
.nf
cc [ \fIflag \&.\|.\|.\fR ] \fIfile\fR\&.\|.\|. \fB-lumem\fR [ \fIlibrary \&.\|.\|.\fR ]
#include <umem.h>
\fBumem_cache_t *\fR\fBumem_cache_create\fR(\fBchar *\fR\fIdebug_name\fR, \fBsize_t\fR \fIbufsize\fR,
\fBsize_t\fR \fIalign\fR, \fBumem_constructor_t *\fR\fIconstructor\fR,
\fBumem_destructor_t *\fR\fIdestructor\fR, \fBumem_reclaim_t *\fR\fIreclaim\fR,
\fBvoid *\fR\fIcallback_data\fR, \fBvmem_t *\fR\fIsource\fR, \fBint\fR \fIcflags\fR);
.fi
.LP
.nf
\fBvoid\fR \fBumem_cache_destroy\fR(\fBumem_cache_t *\fR\fIcache\fR);
.fi
.LP
.nf
\fBvoid *\fR\fBumem_cache_alloc\fR(\fBumem_cache_t *\fR\fIcache\fR, \fBint\fR \fIflags\fR);
.fi
.LP
.nf
\fBvoid\fR \fBumem_cache_free\fR(\fBumem_cache_t *\fR\fIcache\fR, \fBvoid *\fR\fIbuffer\fR);
.fi
.SH DESCRIPTION
.LP
These functions create, destroy, and use an "object cache". An object cache is a collection of buffers of a single size, with optional content caching enabled by the use of callbacks (see \fBCache Callbacks\fR). Object caches are MT-Safe. Multiple allocations and freeing of
memory from different threads can proceed simultaneously. Object caches are faster and use less space per buffer than
\fBmalloc\fR(3MALLOC) and
\fBumem_alloc\fR(3MALLOC). For more information about object caching, see "The Slab Allocator: An Object-Caching Kernel Memory Allocator" and "Magazines
and vmem: Extending the Slab Allocator to Many CPUs and Arbitrary Resources".
.sp
.LP
The \fBumem_cache_create()\fR function creates object caches. Once a cache has been created, objects can be requested from and returned to the cache using \fBumem_cache_alloc()\fR and \fBumem_cache_free()\fR, respectively. A cache with no outstanding
buffers can be destroyed with \fBumem_cache_destroy()\fR.
.sp
.SS Creating and Destroying Caches
.LP
The \fBumem_cache_create()\fR function creates a cache of objects and takes as arguments the following:
.sp
.sp
.ne 2
.mk
.na
\fB\fIdebug_name\fR\fR
.ad
.RS 15n
.rt
A human-readable name for debugging purposes.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIbufsize\fR\fR
.ad
.RS 15n
.rt
The size, in bytes, of the buffers in this cache.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIalign\fR\fR
.ad
.RS 15n
.rt
The minimum alignment required for buffers in this cache. This parameter must be a power of 2. If 0, it is replaced with the minimum required alignment for the current architecture.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIconstructor\fR\fR
.ad
.RS 15n
.rt
The callback to construct an object.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIdestructor\fR\fR
.ad
.RS 15n
.rt
The callback to destroy an object.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIreclaim\fR\fR
.ad
.RS 15n
.rt
The callback to reclaim objects.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIcallback_data\fR\fR
.ad
.RS 15n
.rt
An opaque pointer passed to the callbacks.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIsource\fR\fR
.ad
.RS 15n
.rt
This parameter must be \fINULL\fR.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIcflags\fR\fR
.ad
.RS 15n
.rt
This parameter must be either 0 or \fBUMC_NODEBUG\fR. If \fBUMC_NODEBUG\fR, all debugging features are disabled for this cache. See
\fBumem_debug\fR(3MALLOC).
.sp
.RE
.LP
Each cache can have up to three associated callbacks:
.sp
.LP
.in +2
.nf
int constructor(void *buffer, void *callback_data, int flags);
void destructor(void *buffer, void *callback_data);
void reclaim(void *callback_data);
.fi
.in -2
.LP
The \fIcallback_data\fR argument is always equal to the value passed to \fBumem_cache_create()\fR, thereby allowing a client to use the same callback functions for multiple caches, but with customized behavior.
.sp
.LP
The reclaim callback is called when the umem function is requesting more memory from the operating system. This callback can be used by clients who retain objects longer than they are strictly needed (for example, caching non-active state). A typical reclaim callback might return to the
cache ten per cent of the unneeded buffers.
.sp
.LP
The constructor and destructor callbacks enable the management of buffers with the constructed state. The constructor takes as arguments a buffer with undefined contents, some callback data, and the flags to use for any allocations. This callback should transform the buffer into the constructed
state.
.sp
.LP
The destructor callback takes as an argument a constructed object and prepares it for return to the general pool of memory. The destructor should undo any state that the constructor created. For debugging, the destructor can also check that the buffer is in the constructed state, to catch
incorrectly freed buffers. See
\fBumem_debug\fR(3MALLOC) for further information on debugging support.
.sp
.LP
The \fBumem_cache_destroy()\fR function destroys an object cache. If the cache has any outstanding allocations, the behavior is undefined.
.sp
.SS Allocating Objects
.LP
The \fBumem_cache_alloc()\fR function takes as arguments:
.sp
.sp
.ne 2
.mk
.na
\fB\fIcache\fR\fR
.ad
.RS 7n
.rt
a cache pointer
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIflags\fR\fR
.ad
.RS 7n
.rt
flags that determine the behavior if \fBumem_cache_alloc()\fR is unable to fulfill the allocation request
.sp
.RE
.LP
If successful, \fBumem_cache_alloc()\fR returns a pointer to the beginning of an object of \fIbufsize\fR length.
.sp
.LP
There are three cases to consider:
.sp
.sp
.RS +4
.TP
.ie t \(bu
.el o
A new buffer needed to be allocated. If the cache was created with a constructor, it is applied to the buffer and the resulting object is returned.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
The object cache was able to use a previously freed buffer. If the cache was created with a constructor, the object is returned unchanged from when it was freed.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
The allocation of a new buffer failed. The \fIflags\fR argument determines the behavior:
.sp
.sp
.ne 2
.mk
.na
\fB\fBUMEM_DEFAULT\fR\fR
.ad
.RS 14n
.rt
The \fBumem_cache_alloc()\fR function returns \fINULL\fR if the allocation fails.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBUMEM_NOFAIL\fR\fR
.ad
.RS 14n
.rt
The \fBumem_cache_alloc()\fR function cannot return \fINULL\fR. A callback is used to determine what action occurs. See
\fBumem_alloc\fR(3MALLOC) for more information.
.sp
.RE
.RE
.SS Freeing Objects
.LP
The \fBumem_cache_free()\fR function takes as arguments:
.sp
.sp
.ne 2
.mk
.na
\fB\fIcache\fR\fR
.ad
.RS 7n
.rt
a cache pointer
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fIbuf\fR\fR
.ad
.RS 7n
.rt
a pointer previously returned from \fBumem_cache_alloc()\fR. This argument must not be \fINULL\fR.
.sp
.RE
.LP
If the cache was created with a constructor callback, the object must be returned to the constructed state before it is freed.
.sp
.LP
Undefined behavior results if an object is freed multiple times, if an object is modified after it is freed, or if an object is freed to a cache other than the one from which it was allocated.
.sp
.SS Caches with Constructors
.LP
When a constructor callback is in use, there is essentially a contract between the cache and its clients. The cache guarantees that all objects returned from \fBumem_cache_alloc()\fR will be in the constructed state, and the client guarantees that it will return the object
to the constructed state before handing it to \fBumem_cache_free()\fR.
.sp
.SH RETURN VALUES
.LP
Upon failure, the \fBumem_cache_create()\fR function returns a null pointer.
.sp
.SH ERRORS
.LP
The \fBumem_cache_create()\fR function will fail if:
.sp
.sp
.ne 2
.mk
.na
\fB\fBEAGAIN\fR\fR
.ad
.RS 8n
.rt
There is not enough memory available to allocate the cache data structure.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBEINVAL\fR\fR
.ad
.RS 8n
.rt
The \fIdebug_name\fR argument is \fINULL\fR, the \fIalign\fR argument is not a power of two or is larger than the system pagesize, or the \fIbufsize\fR argument is 0.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBENOMEM\fR\fR
.ad
.RS 8n
.rt
The \fBlibumem\fR library could not be initialized, or the \fIbufsize\fR argument is too large and its use would cause integer overflow to occur.
.sp
.RE
.SH EXAMPLES
.LP
\fBExample 1 \fRUse a fixed-size structure with no constructor callback.
.LP
.in +2
.nf
#include <umem.h>
typedef struct my_obj {
long my_data1;
} my_obj_t;
/*
* my_objs can be freed at any time. The contents of
* my_data1 is undefined at allocation time.
*/
umem_cache_t *my_obj_cache;
\&...
my_obj_cache = umem_cache_create("my_obj", sizeof (my_obj_t),
0, NULL, NULL, NULL, NULL, NULL, 0);
\&...
my_obj_t *cur = umem_cache_alloc(my_obj_cache, UMEM_DEFAULT);
\&...
/* use cur */
\&...
umem_cache_free(my_obj_cache, cur);
\&...
.fi
.in -2
.LP
\fBExample 2 \fRUse an object with a mutex.
.LP
.in +2
.nf
#define _REENTRANT
#include <synch.h>
#include <umem.h>
typedef struct my_obj {
mutex_t my_mutex;
long my_data;
} my_obj_t;
/*
* my_objs can only be freed when my_mutex is unlocked.
*/
int
my_obj_constructor(void *buf, void *ignored, int flags)
{
my_obj_t *myobj = buf;
(void) mutex_init(&my_obj->my_mutex, USYNC_THREAD, NULL);
return (0);
}
void
my_obj_destructor(void *buf, void *ignored)
{
my_obj_t *myobj = buf;
(void) mutex_destroy(&my_obj->my_mutex);
}
umem_cache_t *my_obj_cache;
\&...
my_obj_cache = umem_cache_create("my_obj", sizeof (my_obj_t),
0, my_obj_constructor, my_obj_destructor, NULL, NULL,
NULL, 0);
\&...
my_obj_t *cur = umem_cache_alloc(my_obj_cache, UMEM_DEFAULT);
cur->my_data = 0; /* cannot assume anything about my_data */
\&...
umem_cache_free(my_obj_cache, cur);
\&...
.fi
.in -2
.LP
\fBExample 3 \fRUse a more complex object with a mutex.
.LP
.in +2
.nf
#define _REENTRANT
#include <assert.h>
#include <synch.h>
#include <umem.h>
typedef struct my_obj {
mutex_t my_mutex;
cond_t my_cv;
struct bar *my_barlist;
unsigned my_refcount;
} my_obj_t;
/*
* my_objs can only be freed when my_barlist == NULL,
* my_refcount == 0, there are no waiters on my_cv, and
* my_mutex is unlocked.
*/
int
my_obj_constructor(void *buf, void *ignored, int flags)
{
my_obj_t *myobj = buf;
(void) mutex_init(&my_obj->my_mutex, USYNC_THREAD, NULL);
(void) cond_init(&my_obj->my_cv, USYNC_THREAD, NULL);
myobj->my_barlist = NULL;
myobj->my_refcount = 0;
return (0);
}
void
my_obj_destructor(void *buf, void *ignored)
{
my_obj_t *myobj = buf;
assert(myobj->my_refcount == 0);
assert(myobj->my_barlist == NULL);
(void) cond_destroy(&my_obj->my_cv);
(void) mutex_destroy(&my_obj->my_mutex);
}
umem_cache_t *my_obj_cache;
\&...
my_obj_cache = umem_cache_create("my_obj", sizeof (my_obj_t),
0, my_obj_constructor, my_obj_destructor, NULL, NULL,
NULL, 0);
\&...
my_obj_t *cur = umem_cache_alloc(my_obj_cache, UMEM_DEFAULT);
\&...
/* use cur */
\&...
umem_cache_free(my_obj_cache, cur);
\&...
.fi
.in -2
.LP
\fBExample 4 \fRUse objects with a subordinate buffer while reusing callbacks.
.LP
.in +2
.nf
#include assert.h>
#include umem.h>
typedef struct my_obj {
char *my_buffer;
size_t my_size;
} my_obj_t;
/*
* my_size and the my_buffer pointer should never be changed
*/
int
my_obj_constructor(void *buf, void *arg, int flags)
{
size_t sz = (size_t)arg;
my_obj_t *myobj = buf;
if ((myobj->my_buffer = umem_alloc(sz, flags)) == NULL)
return (1);
my_size = sz;
return (0);
}
void
my_obj_destructor(void *buf, void *arg)
{
size_t sz = (size_t)arg;
my_obj_t *myobj = buf;
assert(sz == buf->my_size);
umem_free(myobj->my_buffer, sz);
}
\&...
umem_cache_t *my_obj_4k_cache;
umem_cache_t *my_obj_8k_cache;
\&...
my_obj_cache_4k = umem_cache_create("my_obj_4k", sizeof (my_obj_t),
0, my_obj_constructor, my_obj_destructor, NULL,
(void *)4096, NULL, 0);
my_obj_cache_8k = umem_cache_create("my_obj_8k", sizeof (my_obj_t),
0, my_obj_constructor, my_obj_destructor, NULL,
(void *)8192, NULL, 0);
\&...
my_obj_t *my_obj_4k = umem_cache_alloc(my_obj_4k_cache,
UMEM_DEFAULT);
my_obj_t *my_obj_8k = umem_cache_alloc(my_obj_8k_cache,
UMEM_DEFAULT);
/* no assumptions should be made about the contents
of the buffers */
\&...
/* make sure to return them to the correct cache */
umem_cache_free(my_obj_4k_cache, my_obj_4k);
umem_cache_free(my_obj_8k_cache, my_obj_8k);
\&...
.fi
.in -2
.LP
See the \fBEXAMPLES\fR section of
\fBumem_alloc\fR(3MALLOC) for examples involving the \fBUMEM_NOFAIL\fR flag.
.sp
.SH ATTRIBUTES
.LP
See
\fBattributes\fR(5) for descriptions of the following attributes:
.sp
.LP
.sp
.TS
tab() box;
cw(2.75i) |cw(2.75i)
lw(2.75i) |lw(2.75i)
.
ATTRIBUTE TYPEATTRIBUTE VALUE
_
Interface StabilityEvolving
_
MT-LevelMT-Safe
.TE
.SH SEE ALSO
.LP
\fBsetcontext\fR(2),
\fBatexit\fR(3C),
\fBlibumem\fR(3LIB),
\fBlongjmp\fR(3C),
\fBswapcontext\fR(3C),
\fBthr_exit\fR(3C),
\fBumem_alloc\fR(3MALLOC),
\fBumem_debug\fR(3MALLOC),
\fBattributes\fR(5)
.sp
.LP
Bonwick, Jeff, "The Slab Allocator: An Object-Caching Kernel Memory Allocator", Proceedings of the Summer 1994 Usenix Conference.
.sp
.LP
Bonwick, Jeff and Jonathan Adams, "Magazines and vmem: Extending the Slab Allocator to Many CPUs and Arbitrary Resources", Proceedings of the Summer 2001 Usenix Conference.
.sp
.SH WARNINGS
.LP
Any of the following can cause undefined results:
.sp
.sp
.RS +4
.TP
.ie t \(bu
.el o
Destroying a cache that has outstanding allocated buffers.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
Using a cache after it has been destroyed.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
Calling \fBumem_cache_free()\fR on the same buffer multiple times.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
Passing a \fINULL\fR pointer to \fBumem_cache_free()\fR.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
Writing past the end of a buffer.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
Reading from or writing to a buffer after it has been freed.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
Performing \fBUMEM_NOFAIL\fR allocations from an
\fBatexit\fR(3C) handler.
.sp
.RE
.LP
Per-cache callbacks can be called from a variety of contexts. The use of functions that modify the active context, such as
\fBsetcontext\fR(2),
\fBswapcontext\fR(3C), and
\fBthr_exit\fR(3C),
or functions that are unsafe for use in multithreaded applications, such as
\fBlongjmp\fR(3C) and
\fBsiglongjmp\fR(3C), result in undefined behavior.
.sp
.LP
A constructor callback that performs allocations must pass its \fIflags\fR argument unchanged to
\fBumem_alloc\fR(3MALLOC) and \fBumem_cache_alloc()\fR. Any allocations made with a different flags argument results in undefined behavior. The constructor must correctly handle the failure of any allocations it makes.
.sp
.SH NOTES
.LP
Object caches make the following guarantees about objects:
.sp
.sp
.RS +4
.TP
.ie t \(bu
.el o
If the cache has a constructor callback, it is applied to every object before it is returned from \fBumem_cache_alloc()\fR for the first time.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
If the cache has a constructor callback, an object passed to \fBumem_cache_free()\fR and later returned from \fBumem_cache_alloc()\fR is not modified between the two events.
.sp
.RE
.sp
.RS +4
.TP
.ie t \(bu
.el o
If the cache has a destructor, it is applied to all objects before their underlying storage is returned.
.sp
.RE
.LP
No other guarantees are made. In particular, even if there are buffers recently freed to the cache, \fBumem_cache_alloc()\fR can fail.
.sp

275
umem_debug.3 Normal file
View file

@ -0,0 +1,275 @@
'\" te
.\" CDDL HEADER START
.\"
.\" The contents of this file are subject to the terms of the
.\" Common Development and Distribution License (the "License").
.\" You may not use this file except in compliance with the License.
.\"
.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
.\" or http://www.opensolaris.org/os/licensing.
.\" See the License for the specific language governing permissions
.\" and limitations under the License.
.\"
.\" When distributing Covered Code, include this CDDL HEADER in each
.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
.\" If applicable, add the following below this CDDL HEADER, with the
.\" fields enclosed by brackets "[]" replaced with your own identifying
.\" information: Portions Copyright [yyyy] [name of copyright owner]
.\"
.\" CDDL HEADER END
.\" Copyright (c) 2002, Sun Microsystems, Inc. All Rights Reserved.
.TH umem_debug 3MALLOC "26 July 2002" "SunOS 5.11" "Memory Allocation Library Functions"
.SH NAME
umem_debug \- debugging features of the umem library
.SH SYNOPSIS
.LP
.nf
\fBcc\fR [ \fIflag\fR\&.\|.\|. ] \fIfile\fR\&.\|.\|. \fB-lumem\fR [ \fIlibrary\fR\&.\|.\|. ]
#include <\fBumem.h\fR>
.fi
.SH DESCRIPTION
.LP
The \fBlibumem\fR library provides debugging features that detect memory leaks, buffer overruns, multiple frees, use of uninitialized data, use of freed data, and many other common programming errors. The activation of the run-time debugging features is controlled by environment variables.
.sp
.LP
When the library detects an error, it writes a description of the error to an internal buffer that is readable with the \fB::umem_status\fR
\fBmdb\fR(1) \fIdcmd\fR and then calls
\fBabort\fR(3C).
.sp
.SH ENVIRONMENT VARIABLES
.sp
.ne 2
.mk
.na
\fBUMEM_DEBUG\fR
.ad
.RS 14n
.rt
This variable contains a list of comma-separated options. Unrecognized options are ignored. Possible options include:
.sp
.sp
.ne 2
.mk
.na
\fB\fBaudit\fR[=\fIframes\fR]\fR
.ad
.RS 18n
.rt
This option enables the recording of auditing information, including thread ID, high-resolution time stamp, and stack trace for the last action (allocation or free) on every allocation. If transaction logging
(see UMEM_LOGGING) is enabled, this auditing information is also logged.
.sp
.sp
The \fIframes\fR parameter sets the number of stack frames recorded in the auditing structure. The upper bound for frames is implementation-defined. If a larger value is requested, the upper bound is used instead.
.sp
.sp
If \fIframes\fR is not specified or is not an integer, the default value of 15 is used.
.sp
.sp
This option also enables the \fBguards\fR option.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBcontents\fR[=\fIcount\fR]\fR
.ad
.RS 18n
.rt
If auditing and contents logging (see UMEM_LOGGING) are enabled, the first \fIcount\fR bytes of each buffer are logged when they are freed. If a buffer is shorter than \fIcount\fR bytes, it is logged in its entirety.
.sp
.sp
If \fIcount\fR is not specified or is not an integer, the default value of 256 is used.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBdefault\fR\fR
.ad
.RS 18n
.rt
This option is equivalent to \fBaudit\fR,\fBcontents\fR,\fBguards\fR.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBguards\fR\fR
.ad
.RS 18n
.rt
This option enables filling allocated and freed buffers with special patterns to help detect the use of uninitialized data and previously freed buffers. It also enables an 8-byte redzone after each buffer that contains \fB0xfeedfacefeedfaceULL\fR.
.sp
.sp
When an object is freed, it is filled with \fB0xdeadbeef\fR. When an object is allocated, the \fB0xdeadbeef\fR pattern is verified and replaced with \fB0xbaddcafe\fR. The redzone is checked every time a buffer is allocated or freed.
.sp
.sp
For caches with either constructors or destructors, or both,
\fBumem_cache_alloc\fR(3MALLOC) and
\fBumem_cache_free\fR(3MALLOC) apply the cache's constructor and destructor, respectively, instead of caching constructed objects. The presence of
\fBassert\fR(3C)s
in the destructor verifying that the buffer is in the constructed state can be used to detect any objects returned in an improper state. See
\fBumem_cache_create\fR(3MALLOC) for
details.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBverbose\fR\fR
.ad
.RS 18n
.rt
The library writes error descriptions to standard error before aborting. These messages are not localized.
.sp
.RE
.RE
.sp
.ne 2
.mk
.na
\fBUMEM_LOGGING\fR
.ad
.RS 14n
.rt
To be enabled, this variable should be set to a comma-separated list of in-memory logs. The logs available are:
.sp
.sp
.ne 2
.mk
.na
\fB\fBtransaction\fR[=\fIsize\fR]\fR
.ad
.RS 20n
.rt
If the \fBaudit\fR debugging option is set (see \fBUMEM_DEBUG\fR), the audit structures from previous transactions are entered into this log.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBcontents\fR[=\fIsize\fR]\fR
.ad
.RS 20n
.rt
If the \fBaudit\fR debugging option is set, the contents of objects are recorded in this log as they are freed.
.sp
.sp
If the "contents" debugging option was not set, 256 bytes of each freed buffer are saved.
.sp
.RE
.sp
.ne 2
.mk
.na
\fB\fBfail\fR[=\fIsize\fR]\fR
.ad
.RS 20n
.rt
Records are entered into this log for every failed allocation.
.sp
.RE
For any of these options, if \fIsize\fR is not specified, the default value of 64k is used. The \fIsize\fR parameter must be an integer that can be qualified with K, M, G, or T to specify kilobytes, megabytes, gigabytes, or terabytes, respectively.
.sp
.sp
Logs that are not listed or that have either a size of 0 or an invalid size are disabled.
.sp
.sp
The log is disabled if during initialization the requested amount of storage cannot be allocated.
.sp
.RE
.SH ATTRIBUTES
.LP
See
\fBattributes\fR(5) for descriptions of the following attributes:
.sp
.LP
.sp
.TS
tab() box;
cw(2.75i) |cw(2.75i)
lw(2.75i) |lw(2.75i)
.
ATTRIBUTE TYPEATTRIBUTE VALUE
_
Interface StabilityUnstable
_
MT-LevelMT-Safe
.TE
.SH SEE ALSO
.LP
\fBmdb\fR(1),
\fBabort\fR(3C),
\fBsignal\fR(3C),
\fBumem_cache_create\fR(3MALLOC),
\fBattributes\fR(5)
.sp
.LP
.sp
.SH WARNINGS
.LP
When \fBlibumem\fR aborts the process using
\fBabort\fR(3C), any existing signal handler for \fBSIGABRT\fR is called. If the signal handler performs allocations, undefined
behavior can result.
.sp
.SH NOTES
.LP
Some of the debugging features work only for allocations smaller than 16 kilobytes in size. Allocations larger than 16 kilobytes could have reduced support.
.sp
.LP
Activating any of the library's debugging features could significantly increase the library's memory footprint and decrease its performance.
.sp

View file

@ -19,12 +19,12 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
/* #pragma ident "@(#)umem_fail.c 1.4 05/06/08 SMI" */
@ -38,9 +38,9 @@
#include <signal.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include "misc.h"
#include "util.h"
static volatile int umem_exiting = 0;
#define UMEM_EXIT_ABORT 1
@ -82,9 +82,21 @@ umem_do_abort(void)
}
for (;;) {
#if defined(__FreeBSD__)
sigset_t set;
struct sigaction sa;
sa.sa_handler = SIG_DFL;
(void) sigaction(SIGABRT, &sa, NULL);
(void) sigemptyset (&set);
(void) sigaddset (&set, SIGABRT);
(void) sigprocmask (SIG_UNBLOCK, &set, NULL);
(void) raise (SIGABRT);
#else
(void) signal(SIGABRT, SIG_DFL);
(void) sigrelse(SIGABRT);
(void) raise(SIGABRT);
#endif
}
#endif
}
@ -125,10 +137,6 @@ umem_panic(const char *format, ...)
if (format[strlen(format)-1] != '\n')
umem_error_enter("\n");
va_start(va, format);
ec_debug_vprintf(DCRITICAL, DMEM, format, va);
va_end(va);
print_stacktrace();
umem_do_abort();
@ -157,7 +165,6 @@ __umem_assert_failed(const char *assertion, const char *file, int line)
{
umem_panic("Assertion failed: %s, file %s, line %d\n",
assertion, file, line);
umem_do_abort();
/*NOTREACHED*/
return (0);
}

View file

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -19,18 +18,13 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*/
/* #pragma ident "@(#)umem_fork.c 1.3 05/06/08 SMI" */
#include "config.h"
/* #include "mtlib.h" */
#include "umem_base.h"
#include "vmem_base.h"
@ -38,7 +32,8 @@
#include <unistd.h>
/*
* The following functions are for pre- and post-fork1(2) handling.
* The following functions are for pre- and post-fork1(2) handling. See
* "Lock Ordering" in lib/libumem/common/umem.c for the lock ordering used.
*/
static void
@ -108,6 +103,10 @@ umem_lockup(void)
(void) umem_init();
(void) mutex_lock(&umem_init_lock);
}
vmem_lockup();
vmem_sbrk_lockup();
(void) mutex_lock(&umem_cache_lock);
(void) mutex_lock(&umem_update_lock);
(void) mutex_lock(&umem_flags_lock);
@ -124,46 +123,30 @@ umem_lockup(void)
(void) cond_broadcast(&umem_update_cv);
vmem_sbrk_lockup();
vmem_lockup();
}
static void
umem_release(void)
{
umem_cache_t *cp;
vmem_release();
vmem_sbrk_release();
umem_release_log_header(umem_slab_log);
umem_release_log_header(umem_failure_log);
umem_release_log_header(umem_content_log);
umem_release_log_header(umem_transaction_log);
for (cp = umem_null_cache.cache_next; cp != &umem_null_cache;
cp = cp->cache_next)
umem_release_cache(cp);
umem_release_cache(&umem_null_cache);
(void) mutex_unlock(&umem_flags_lock);
(void) mutex_unlock(&umem_update_lock);
(void) mutex_unlock(&umem_cache_lock);
(void) mutex_unlock(&umem_init_lock);
}
static void
umem_release_child(void)
umem_do_release(int as_child)
{
umem_cache_t *cp;
int cleanup_update = 0;
/*
* Clean up the update state
* Clean up the update state if we are the child process and
* another thread was processing updates.
*/
if (as_child) {
if (umem_update_thr != thr_self()) {
umem_update_thr = 0;
cleanup_update = 1;
}
if (umem_st_update_thr != thr_self()) {
umem_st_update_thr = 0;
cleanup_update = 1;
}
}
if (cleanup_update) {
umem_reaping = UMEM_REAP_DONE;
for (cp = umem_null_cache.cache_next; cp != &umem_null_cache;
@ -196,7 +179,36 @@ umem_release_child(void)
}
}
umem_release();
umem_release_log_header(umem_slab_log);
umem_release_log_header(umem_failure_log);
umem_release_log_header(umem_content_log);
umem_release_log_header(umem_transaction_log);
for (cp = umem_null_cache.cache_next; cp != &umem_null_cache;
cp = cp->cache_next)
umem_release_cache(cp);
umem_release_cache(&umem_null_cache);
(void) mutex_unlock(&umem_flags_lock);
(void) mutex_unlock(&umem_update_lock);
(void) mutex_unlock(&umem_cache_lock);
vmem_sbrk_release();
vmem_release();
(void) mutex_unlock(&umem_init_lock);
}
static void
umem_release(void)
{
umem_do_release(0);
}
static void
umem_release_child(void)
{
umem_do_release(1);
}
#endif

View file

@ -21,10 +21,11 @@
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
*
* Portions Copyright 2012 Joyent, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
#ifndef _UMEM_IMPL_H
@ -374,7 +375,7 @@ typedef struct umem_cpu {
uint32_t cpu_number;
} umem_cpu_t;
#define UMEM_MAXBUF 16384
#define UMEM_MAXBUF 131072
#define UMEM_ALIGN 8 /* min guaranteed alignment */
#define UMEM_ALIGN_SHIFT 3 /* log2(UMEM_ALIGN) */

25
umem_test.c Normal file
View file

@ -0,0 +1,25 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "umem.h"
#define UMEM_STANDALONE 1
#include "umem_impl.h"
int main(int argc, char *argv[])
{
char *foo;
umem_startup(NULL, 0, 0, NULL, NULL);
foo = umem_alloc(32, UMEM_DEFAULT);
strcpy(foo, "hello there");
printf("Hello %s\n", foo);
umem_free(foo, 32);
return EXIT_SUCCESS;
}

62
umem_test2.c Normal file
View file

@ -0,0 +1,62 @@
#include <stdio.h>
#include <string.h>
#include "umem.h"
static const char *TESTSTRINGS[] = {
"fred",
"fredfredfred",
"thisisabitlongerthantheotherstrings",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890",
};
#define N_TESTSTRINGS (sizeof(TESTSTRINGS) / sizeof(TESTSTRINGS[0]))
#define N_TESTS 1000
int
main (int argc, char *argv[])
{
char *testcases[N_TESTSTRINGS][N_TESTS + 1];
size_t len[N_TESTSTRINGS];
int i, j;
memset(testcases, 0, sizeof(testcases));
umem_startup(NULL, 0, 0, NULL, NULL);
for (i = 0; i < N_TESTSTRINGS; ++i)
{
len[i] = strlen(TESTSTRINGS[i]) + 1;
}
puts("Allocating...");
for (j = 0; j < N_TESTS; ++j)
{
for (i = 0; i < N_TESTSTRINGS; ++i)
{
testcases[i][j] = umem_alloc(len[i], UMEM_DEFAULT);
strcpy(testcases[i][j], TESTSTRINGS[i]);
}
}
puts("Deallocating...");
for (j = 0; j < N_TESTS; ++j)
{
for (i = N_TESTSTRINGS - 1; i >= 0; --i)
{
umem_free(testcases[i][j], len[i]);
}
if ((j % 25) == 0)
{
puts("Reaping...");
umem_reap();
}
}
puts("Done");
return 0;
}

35
umem_test3.c Normal file
View file

@ -0,0 +1,35 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
#include <malloc.h>
#endif
static void minfo(void)
{
#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO)
struct mallinfo mi;
mi = mallinfo();
printf(" fordblks = %d\n", mi.fordblks);
malloc_stats();
printf("\n");
#endif
}
int
main (void)
{
char *p;
minfo();
p = malloc(10);
free(p);
minfo();
return EXIT_SUCCESS;
}
/* vim:ts=2:sw=2:et:
*/

23
umem_test4 Executable file
View file

@ -0,0 +1,23 @@
#!/bin/sh
#
# Check that LD_PRELOAD'ing libumem works. This is how it can be used
# to replace malloc for any program.
#
FILE=Makefile.am
TMPLOC=`mktemp -d /tmp/umem_test4.XXXXXX`
trap 'rm -rf $TMPLOC' 1 2 15
LD_PRELOAD=.libs/libumem.so /usr/bin/ldd /bin/ls >$TMPLOC/log 2>&1
# Check we got the expected result
ret=0
grep -E '(symbol lookup error|undefined symbol)' $TMPLOC/log >/dev/null 2>&1
if [ "$?" = "0" ]; then
# Matched = failed to load up libumem
ret=1
fi
rm -rf $TMPLOC
exit $ret

View file

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -19,12 +18,12 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
/* #pragma ident "@(#)umem_update_thread.c 1.2 05/06/08 SMI" */
@ -35,10 +34,18 @@
#include <signal.h>
/*
* we use the _ version, since we don't want to be cancelled.
*/
extern int _cond_timedwait(cond_t *cv, mutex_t *mutex, const timespec_t *delay);
struct umem_suspend_signal_object {
/* locked by creating thread; unlocked when umem_update_thread
* can proceed */
pthread_mutex_t mtx;
/* lock associated with the condition variable */
pthread_mutex_t cmtx;
/* condition variable is signalled by umem_update_thread when
* it has obtained the mtx; it is then safe for the creating
* thread to clean up its stack (on which this object resides) */
pthread_cond_t cond;
int flag;
};
/*ARGSUSED*/
static THR_RETURN
@ -46,6 +53,12 @@ THR_API umem_update_thread(void *arg)
{
struct timeval now;
int in_update = 0;
struct umem_suspend_signal_object *obj = arg;
pthread_mutex_lock(&obj->mtx);
obj->flag = 1;
pthread_cond_signal(&obj->cond);
obj = NULL;
(void) mutex_lock(&umem_update_lock);
@ -110,12 +123,16 @@ THR_API umem_update_thread(void *arg)
* next update, or someone wakes us.
*/
if (umem_null_cache.cache_unext == &umem_null_cache) {
int cancel_state;
timespec_t abs_time;
abs_time.tv_sec = umem_update_next.tv_sec;
abs_time.tv_nsec = umem_update_next.tv_usec * 1000;
(void) _cond_timedwait(&umem_update_cv,
(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
&cancel_state);
(void) cond_timedwait(&umem_update_cv,
&umem_update_lock, &abs_time);
(void) pthread_setcancelstate(cancel_state, NULL);
}
}
/* LINTED no return statement */
@ -127,6 +144,10 @@ umem_create_update_thread(void)
#ifndef _WIN32
sigset_t sigmask, oldmask;
#endif
pthread_t newthread;
pthread_attr_t attr;
struct umem_suspend_signal_object obj;
int cancel_state;
ASSERT(MUTEX_HELD(&umem_update_lock));
ASSERT(umem_update_thr == 0);
@ -136,18 +157,65 @@ umem_create_update_thread(void)
* The update thread handles no signals
*/
(void) sigfillset(&sigmask);
(void) thr_sigsetmask(SIG_BLOCK, &sigmask, &oldmask);
(void) pthread_sigmask(SIG_BLOCK, &sigmask, &oldmask);
#endif
if (thr_create(NULL, 0, umem_update_thread, NULL,
THR_BOUND | THR_DAEMON | THR_DETACHED, &umem_update_thr) == 0) {
/*
* drop the umem_update_lock; we cannot hold locks acquired in
* pre-fork handler while calling thr_create or thr_continue().
*/
(void) mutex_unlock(&umem_update_lock);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_mutex_init(&obj.mtx, NULL);
pthread_mutex_init(&obj.cmtx, NULL);
pthread_cond_init(&obj.cond, NULL);
obj.flag = 0;
pthread_mutex_lock(&obj.mtx);
if (pthread_create(&newthread, &attr, umem_update_thread, &obj) == 0) {
#ifndef _WIN32
(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
(void) pthread_sigmask(SIG_SETMASK, &oldmask, NULL);
#endif
return (1);
(void) mutex_lock(&umem_update_lock);
/*
* due to the locking in umem_reap(), only one thread can
* ever call umem_create_update_thread() at a time. This
* must be the case for this code to work.
*/
ASSERT(umem_update_thr == 0);
umem_update_thr = newthread;
(void) mutex_unlock(&umem_update_lock);
/* tell the thread to continue */
pthread_mutex_unlock(&obj.mtx);
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
/* wait for it to be done with obj */
pthread_mutex_lock(&obj.cmtx);
do {
if (obj.flag) {
break;
}
umem_update_thr = 0;
#ifndef _WIN32
ASSERT(pthread_cond_wait(&obj.cond, &obj.cmtx) == 0);
} while (1);
pthread_setcancelstate(cancel_state, NULL);
pthread_mutex_destroy(&obj.mtx);
pthread_mutex_destroy(&obj.cmtx);
pthread_cond_destroy(&obj.cond);
(void) mutex_lock(&umem_update_lock);
return (1);
} else { /* thr_create failed */
(void) thr_sigsetmask(SIG_SETMASK, &oldmask, NULL);
#endif
(void) mutex_lock(&umem_update_lock);
pthread_mutex_destroy(&obj.mtx);
pthread_mutex_destroy(&obj.cmtx);
pthread_cond_destroy(&obj.cond);
}
return (0);
}

42
vmem.c
View file

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -19,9 +18,12 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Portions Copyright 2012 Joyent, Inc. All rights reserved.
*/
/* #pragma ident "@(#)vmem.c 1.10 05/06/08 SMI" */
@ -37,7 +39,7 @@
* Proceedings of the 2001 Usenix Conference.
* Available as /shared/sac/PSARC/2000/550/materials/vmem.pdf.
*
* For the "Big Theory Statement", see usr/src/common/os/vmem.c
* For the "Big Theory Statement", see usr/src/uts/common/os/vmem.c
*
* 1. Overview of changes
* ------------------------------
@ -212,7 +214,10 @@ static vmem_seg_t vmem_seg0[VMEM_SEG_INITIAL];
static vmem_seg_t *vmem_segfree;
static mutex_t vmem_list_lock = DEFAULTMUTEX;
static mutex_t vmem_segfree_lock = DEFAULTMUTEX;
static vmem_populate_lock_t vmem_nosleep_lock;
static vmem_populate_lock_t vmem_nosleep_lock = {
DEFAULTMUTEX,
0
};
#define IN_POPULATE() (vmem_nosleep_lock.vmpl_thr == thr_self())
static vmem_t *vmem_list;
static vmem_t *vmem_internal_arena;
@ -227,12 +232,6 @@ vmem_free_t *vmem_heap_free;
uint32_t vmem_mtbf; /* mean time between failures [default: off] */
size_t vmem_seg_size = sizeof (vmem_seg_t);
/*
* we use the _ version, since we don't want to be cancelled.
* Actually, this is automatically taken care of by including "mtlib.h".
*/
extern int _cond_wait(cond_t *cv, mutex_t *mutex);
/*
* Insert/delete from arena list (type 'a') or next-of-kin list (type 'k').
*/
@ -772,6 +771,8 @@ vmem_nextfit_alloc(vmem_t *vmp, size_t size, int vmflag)
break;
vsp = vsp->vs_anext;
if (vsp == rotor) {
int cancel_state;
/*
* We've come full circle. One possibility is that the
* there's actually enough space, but the rotor itself
@ -796,7 +797,10 @@ vmem_nextfit_alloc(vmem_t *vmp, size_t size, int vmflag)
0, 0, NULL, NULL, vmflag & VM_UMFLAGS));
}
vmp->vm_kstat.vk_wait++;
(void) _cond_wait(&vmp->vm_cv, &vmp->vm_lock);
(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
&cancel_state);
(void) cond_wait(&vmp->vm_cv, &vmp->vm_lock);
(void) pthread_setcancelstate(cancel_state, NULL);
vsp = rotor->vs_anext;
}
}
@ -864,6 +868,8 @@ vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase,
(void) mutex_lock(&vmp->vm_lock);
for (;;) {
int cancel_state;
if (vmp->vm_nsegfree < VMEM_MINFREE &&
!vmem_populate(vmp, vmflag))
break;
@ -927,7 +933,7 @@ vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase,
start = MAX(vsp->vs_start, (uintptr_t)minaddr);
end = MIN(vsp->vs_end - 1, (uintptr_t)maxaddr - 1) + 1;
taddr = P2PHASEUP(start, align, phase);
if (P2CROSS(taddr, taddr + size - 1, nocross))
if (P2BOUNDARY(taddr, size, nocross))
taddr +=
P2ROUNDUP(P2NPHASE(taddr, nocross), align);
if ((taddr - start) + size > end - start ||
@ -983,7 +989,10 @@ vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase,
if (vmflag & VM_NOSLEEP)
break;
vmp->vm_kstat.vk_wait++;
(void) _cond_wait(&vmp->vm_cv, &vmp->vm_lock);
(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
&cancel_state);
(void) cond_wait(&vmp->vm_cv, &vmp->vm_lock);
(void) pthread_setcancelstate(cancel_state, NULL);
}
if (vbest != NULL) {
ASSERT(vbest->vs_type == VMEM_FREE);
@ -991,7 +1000,7 @@ vmem_xalloc(vmem_t *vmp, size_t size, size_t align, size_t phase,
(void) vmem_seg_alloc(vmp, vbest, addr, size);
(void) mutex_unlock(&vmp->vm_lock);
ASSERT(P2PHASE(addr, align) == phase);
ASSERT(!P2CROSS(addr, addr + size - 1, nocross));
ASSERT(!P2BOUNDARY(addr, size, nocross));
ASSERT(addr >= (uintptr_t)minaddr);
ASSERT(addr + size - 1 <= (uintptr_t)maxaddr - 1);
return ((void *)addr);
@ -1077,6 +1086,7 @@ vmem_alloc(vmem_t *vmp, size_t size, int vmflag)
int hb;
int flist = 0;
uint32_t mtbf;
vmflag |= vmem_allocator;
if (size - 1 < vmp->vm_qcache_max) {
ASSERT(vmflag & VM_NOSLEEP);

View file

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -19,9 +18,12 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Portions Copyright 2012 Joyent, Inc. All rights reserved.
*/
/* #pragma ident "@(#)vmem_base.c 1.6 05/06/08 SMI" */
@ -32,6 +34,7 @@
#include "umem_base.h"
uint_t vmem_backend = 0;
uint_t vmem_allocator = VM_BESTFIT;
vmem_t *
vmem_heap_arena(vmem_alloc_t **allocp, vmem_free_t **freep)

View file

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License, (the "License").
You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -20,8 +19,10 @@
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* Portions Copyright 2012 Joyent, Inc. All rights reserved.
*/
#ifndef _VMEM_BASE_H
@ -60,12 +61,15 @@ extern void vmem_reap(void); /* vmem_populate()-safe reap */
extern size_t pagesize;
extern size_t vmem_sbrk_pagesize;
extern size_t vmem_sbrk_minalloc;
extern uint_t vmem_backend;
#define VMEM_BACKEND_SBRK 0x0000001
#define VMEM_BACKEND_MMAP 0x0000002
#define VMEM_BACKEND_STAND 0x0000003
extern uint_t vmem_allocator;
extern vmem_t *vmem_heap;
extern vmem_alloc_t *vmem_heap_alloc;
extern vmem_free_t *vmem_heap_free;

View file

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -19,12 +18,12 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
/* #pragma ident "@(#)vmem_mmap.c 1.2 05/06/08 SMI" */
@ -40,6 +39,8 @@
#include <sys/sysmacros.h>
#endif
#include <unistd.h>
#include "vmem_base.h"
#define ALLOC_PROT PROT_READ | PROT_WRITE | PROT_EXEC
@ -64,11 +65,9 @@ vmem_mmap_alloc(vmem_t *src, size_t size, int vmflags)
ret = vmem_alloc(src, size, vmflags);
#ifndef _WIN32
if (ret != NULL
&&
if (ret != NULL &&
mmap(ret, size, ALLOC_PROT, ALLOC_FLAGS | MAP_FIXED, -1, 0) ==
MAP_FAILED
) {
MAP_FAILED) {
vmem_free(src, ret, size);
vmem_reap();
@ -113,18 +112,12 @@ vmem_mmap_top_alloc(vmem_t *src, size_t size, int vmflags)
*/
#ifdef _WIN32
buf = VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (buf == NULL) buf = MAP_FAILED;
#elif defined(MAP_ALIGN)
buf = mmap((void*)CHUNKSIZE, size, FREE_PROT, FREE_FLAGS | MAP_ALIGN,
-1, 0);
#else
buf = mmap(
#ifdef MAP_ALIGN
(void *)CHUNKSIZE,
#else
0,
#endif
size, FREE_PROT, FREE_FLAGS
#ifdef MAP_ALIGN
| MAP_ALIGN
#endif
, -1, 0);
buf = mmap(0, size, FREE_PROT, FREE_FLAGS, -1, 0);
#endif
if (buf != MAP_FAILED) {
@ -167,8 +160,7 @@ vmem_mmap_arena(vmem_alloc_t **a_out, vmem_free_t **f_out)
#endif
if (mmap_heap == NULL) {
mmap_heap = vmem_init("mmap_top",
CHUNKSIZE,
mmap_heap = vmem_init("mmap_top", CHUNKSIZE,
vmem_mmap_top_alloc, vmem_free,
"mmap_heap", NULL, 0, pagesize,
vmem_mmap_alloc, vmem_mmap_free);

View file

@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@ -19,12 +18,12 @@
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Portions Copyright 2006 OmniTI, Inc.
*
* Portions Copyright 2006-2008 Message Systems, Inc. All rights reserved.
*/
/* #pragma ident "@(#)vmem_sbrk.c 1.4 05/06/08 SMI" */
@ -70,7 +69,8 @@
size_t vmem_sbrk_pagesize = 0; /* the preferred page size of the heap */
#define MIN_ALLOC (64*1024)
#define VMEM_SBRK_MINALLOC (64 * 1024)
size_t vmem_sbrk_minalloc = VMEM_SBRK_MINALLOC; /* minimum allocation */
static size_t real_pagesize;
static vmem_t *sbrk_heap;
@ -90,6 +90,7 @@ static sbrk_fail_t sbrk_fails = {
};
static mutex_t sbrk_faillock = DEFAULTMUTEX;
static mutex_t sbrk_lock = DEFAULTMUTEX;
/*
* _sbrk_grow_aligned() aligns the old break to a low_align boundry,
@ -100,7 +101,7 @@ static mutex_t sbrk_faillock = DEFAULTMUTEX;
* Unlike sbrk(2), _sbrk_grow_aligned takes an unsigned size, and does
* not allow shrinking the heap.
*/
void *
static void *
_sbrk_grow_aligned(size_t min_size, size_t low_align, size_t high_align,
size_t *actual_size)
{
@ -121,6 +122,8 @@ _sbrk_grow_aligned(size_t min_size, size_t low_align, size_t high_align,
low_align = MAX(low_align, ALIGNSZ);
high_align = MAX(high_align, ALIGNSZ);
mutex_lock(&sbrk_lock);
old_brk = (uintptr_t)BRKALIGN(sbrk(0));
ret_brk = P2ROUNDUP(old_brk, low_align);
high_brk = ret_brk + min_size;
@ -130,11 +133,13 @@ _sbrk_grow_aligned(size_t min_size, size_t low_align, size_t high_align,
* Check for overflow
*/
if (ret_brk < old_brk || high_brk < ret_brk || new_brk < high_brk) {
mutex_unlock(&sbrk_lock);
errno = ENOMEM;
return ((void *)-1);
}
brk_result = brk((void *)new_brk);
mutex_unlock(&sbrk_lock);
if (brk_result != 0)
return ((void *)-1);
@ -210,9 +215,6 @@ vmem_sbrk_tryfail(vmem_t *src, size_t size, int vmflags)
static void *
vmem_sbrk_alloc(vmem_t *src, size_t size, int vmflags)
{
extern void *_sbrk_grow_aligned(size_t min_size, size_t low_align,
size_t high_align, size_t *actual_size);
void *ret;
void *buf;
size_t buf_size;
@ -234,7 +236,7 @@ vmem_sbrk_alloc(vmem_t *src, size_t size, int vmflags)
(ret = vmem_sbrk_tryfail(src, size, vmflags)) != NULL)
return (ret);
buf_size = MAX(size, MIN_ALLOC);
buf_size = MAX(size, vmem_sbrk_minalloc);
/*
* buf_size gets overwritten with the actual allocated size
@ -311,6 +313,11 @@ vmem_sbrk_arena(vmem_alloc_t **a_out, vmem_free_t **f_out)
}
vmem_sbrk_pagesize = heap_size;
/* validate vmem_sbrk_minalloc */
if (vmem_sbrk_minalloc < VMEM_SBRK_MINALLOC)
vmem_sbrk_minalloc = VMEM_SBRK_MINALLOC;
vmem_sbrk_minalloc = P2ROUNDUP(vmem_sbrk_minalloc, heap_size);
sbrk_heap = vmem_init("sbrk_top", real_pagesize,
vmem_sbrk_alloc, vmem_free,
"sbrk_heap", NULL, 0, real_pagesize,