Compare commits
52 commits
Author | SHA1 | Date | |
---|---|---|---|
|
c4b96af829 | ||
|
e1eb2c8413 | ||
|
0727224086 | ||
|
6b0eb6878b | ||
|
f8c1c0e968 | ||
|
5cc22b9326 | ||
|
7d4d667891 | ||
|
1028ce923e | ||
|
b9dc821378 | ||
|
49b7cfb4d4 | ||
|
f82ad44b62 | ||
|
b2ee64fc04 | ||
|
698dd4c9af | ||
|
da390045aa | ||
|
e5bb27aaa8 | ||
|
f90f13368b | ||
|
f4e4e257f5 | ||
|
ffd4b8b927 | ||
|
b4f8c9083e | ||
|
01ce31068d | ||
|
1a747468dc | ||
|
41bc866d58 | ||
|
eb5ef0ba13 | ||
|
409b31ca3f | ||
|
84293cb0b4 | ||
|
35e9dc7e11 | ||
|
a97a02fa4c | ||
|
a6a20ffacf | ||
|
8f2686cc81 | ||
|
c9b695687f | ||
|
7b6452aa2d | ||
|
724af76462 | ||
|
07d8e36190 | ||
|
29bf7f3e03 | ||
|
e7140b1a1a | ||
|
21f7b73b0f | ||
|
817aa395a1 | ||
|
07f343fdd8 | ||
|
c51a11fb01 | ||
|
26b3085605 | ||
|
c773e87bd3 | ||
|
e781f51fc3 | ||
|
8ddf3f8789 | ||
|
c453cb48a6 | ||
|
11a4b72485 | ||
|
0d7e97d09b | ||
|
1d494ceba8 | ||
|
aa3fcd42da | ||
|
855e068963 | ||
|
ec9812105b | ||
|
427840d649 | ||
|
3f0a4a4e9b |
53 changed files with 6931 additions and 2273 deletions
25
.cvsignore
Normal file
25
.cvsignore
Normal 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
32
.gitignore
vendored
Normal 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
0
AUTHORS
Normal file
2
COPYING
Normal file
2
COPYING
Normal file
|
@ -0,0 +1,2 @@
|
|||
Please see COPYRIGHT and OPENSOLARIS.LICENSE for the copyright
|
||||
and license details.
|
|
@ -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
0
ChangeLog
Normal file
1228
Doxyfile.in
Normal file
1228
Doxyfile.in
Normal file
File diff suppressed because it is too large
Load diff
65
Makefile.am
Normal file
65
Makefile.am
Normal 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
0
NEWS
Normal file
3
README
3
README
|
@ -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
61
README-alpha
Normal 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
19
TODO
Normal 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
3
autogen.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh
|
||||
|
||||
autoreconf -i -s
|
33
configure.ac
Normal file
33
configure.ac
Normal 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
142
envvar.c
|
@ -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
117
gdb-macros
Normal 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
|
||||
|
|
@ -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
17
hello.c
Normal 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:
|
||||
*/
|
||||
|
78
init_lib.c
78
init_lib.c
|
@ -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
|
||||
#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 */
|
||||
}
|
||||
|
|
|
@ -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
1
m4/libtool.m4
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
/usr/share/aclocal/libtool.m4
|
1
m4/ltoptions.m4
vendored
Symbolic link
1
m4/ltoptions.m4
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
/usr/share/aclocal/ltoptions.m4
|
1
m4/ltsugar.m4
vendored
Symbolic link
1
m4/ltsugar.m4
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
/usr/share/aclocal/ltsugar.m4
|
1
m4/ltversion.m4
vendored
Symbolic link
1
m4/ltversion.m4
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
/usr/share/aclocal/ltversion.m4
|
1
m4/lt~obsolete.m4
vendored
Symbolic link
1
m4/lt~obsolete.m4
vendored
Symbolic link
|
@ -0,0 +1 @@
|
|||
/usr/share/aclocal/lt~obsolete.m4
|
20
malloc.c
20
malloc.c
|
@ -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
20
misc.c
|
@ -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
10
misc.h
|
@ -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) */
|
||||
|
||||
/*
|
||||
|
|
132
sol_compat.h
132
sol_compat.h
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
||||
|
|
|
@ -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
521
test.c
Normal 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
262
umem.c
|
@ -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
4
umem.h
|
@ -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
129
umem.spec.in
Normal 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
|
|
@ -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
525
umem_alloc.3
Normal 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
|
||||
|
|
@ -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
815
umem_cache_create.3
Normal 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
275
umem_debug.3
Normal 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
|
||||
|
27
umem_fail.c
27
umem_fail.c
|
@ -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);
|
||||
}
|
||||
|
|
94
umem_fork.c
94
umem_fork.c
|
@ -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
|
||||
|
||||
|
|
|
@ -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
25
umem_test.c
Normal 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
62
umem_test2.c
Normal 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
35
umem_test3.c
Normal 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
23
umem_test4
Executable 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
|
|
@ -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
42
vmem.c
|
@ -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);
|
||||
|
|
11
vmem_base.c
11
vmem_base.c
|
@ -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)
|
||||
|
|
12
vmem_base.h
12
vmem_base.h
|
@ -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;
|
||||
|
|
40
vmem_mmap.c
40
vmem_mmap.c
|
@ -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);
|
||||
|
|
35
vmem_sbrk.c
35
vmem_sbrk.c
|
@ -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,8 +90,9 @@ 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,
|
||||
* adds min_size, aligns to a high_align boundry, and calls _brk_unlocked()
|
||||
* to set the new break. The low_aligned-aligned value is returned, and
|
||||
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue